@Override public EntityIndexBatch deindex(final SearchEdge searchEdge, final CandidateResult entity) { return deindex( searchEdge, entity.getId(), entity.getVersion() ); } @Override
/** * Update direct query candidates to add IDs. */ private void updateDirectQueryCandidateResults( EntityCollectionManager entityCollectionManager, List<FilterResult<Candidate>> candidatesList) { for (FilterResult<Candidate> filterCandidate : candidatesList) { Candidate candidate = filterCandidate.getValue(); CandidateResult candidateResult = candidate.getCandidateResult(); String entityType = candidateResult.getDirectEntityType(); Id entityId = null; if (candidateResult.isDirectQueryName()) { entityId = entityCollectionManager.getIdField( entityType, new StringField( Schema.PROPERTY_NAME, candidateResult.getDirectEntityName() ) ) .toBlocking() .lastOrDefault( null ); } else if (candidateResult.isDirectQueryUUID()) { entityId = new SimpleId(candidateResult.getDirectEntityUUID(), entityType); } filterCandidate.getValue().getCandidateResult().setId(entityId); } }
/** * Parse the document id into a candidate result */ public static CandidateResult parseIndexDocId( final String documentId, final double distance ) { final Matcher matcher = DOCUMENT_PATTERN.matcher(documentId); Preconditions.checkArgument(matcher.matches(), "Pattern for document id did not match expected format"); Preconditions.checkArgument(matcher.groupCount() == 9, "9 groups expected in the pattern"); //Other fields can be parsed using groups. The groups start at value 1, group 0 is the entire match final String entityUUID = matcher.group(3); final String entityType = matcher.group(4); final String versionUUID = matcher.group(5); Id entityId = new SimpleId(UUID.fromString(entityUUID), entityType); return distance >= 0 ? new GeoCandidateResult(entityId, UUID.fromString(versionUUID), documentId, distance) : new CandidateResult(entityId, UUID.fromString(versionUUID), documentId); }
public boolean isDirectQuery() { return isDirectQueryName() || isDirectQueryUUID(); }
/** * Merge our candidates and our entity set into results */ public void merge(boolean keepStaleEntries, String query, boolean isDirectQuery) { if (!isDirectQuery) { filterDuplicateCandidates(query); } else { // remove direct query duplicates or missing entities (names that don't exist will have null ids) Set<UUID> foundUUIDs = new HashSet<>(); for (FilterResult<Candidate> candidateFilterResult : candidateResults) { Id id = candidateFilterResult.getValue().getCandidateResult().getId(); if (id != null) { UUID uuid = id.getUuid(); if (!foundUUIDs.contains(uuid)) { dedupedCandidateResults.add(candidateFilterResult); foundUUIDs.add(uuid); } } } } for (final FilterResult<Candidate> candidateResult : dedupedCandidateResults) { validate(candidateResult, keepStaleEntries, query, isDirectQuery); } // no index requests made for direct query, so no need to modify index if (!isDirectQuery) { indexProducer.put(batch.build()).toBlocking().lastOrDefault(null); // want to rethrow if batch fails } }
assertEquals(1, results.size()); assertEquals(newVersion, results.get(0).getVersion());
@Override public Observable<FilterResult<Id>> call( final Observable<FilterResult<Candidate>> filterResultObservable ) { /** * A bit kludgy from old 1.0 -> 2.0 apis. Refactor this as we clean up our lower levels and create new results * objects */ final ApplicationScope applicationScope = pipelineContext.getApplicationScope(); final EntityCollectionManager entityCollectionManager = entityCollectionManagerFactory.createCollectionManager( applicationScope ); final EntityIndex applicationIndex = entityIndexFactory.createEntityIndex(indexLocationStrategyFactory.getIndexLocationStrategy(applicationScope)); final Observable<FilterResult<Id>> searchIdSetObservable = filterResultObservable.buffer( pipelineContext.getLimit() ).flatMap( candidateResults -> { //flatten toa list of ids to load final Observable<List<Id>> candidateIds = Observable.from( candidateResults ).map( candidate -> candidate.getValue().getCandidateResult().getId() ).toList(); //load the ids final Observable<VersionSet> versionSetObservable = candidateIds.flatMap( ids -> entityCollectionManager.getLatestVersion( ids ) ); //now we have a collection, validate our canidate set is correct. return versionSetObservable.map( entitySet -> new EntityCollector( applicationIndex.createBatch(), entitySet, candidateResults, indexProducer ) ).doOnNext( entityCollector -> entityCollector.merge() ).flatMap( entityCollector -> Observable.from( entityCollector.collectResults() ) ); } ); return searchIdSetObservable; }
if(candidateResult.getVersion().timestamp() <= markedVersion.timestamp()){ candidateResult.getVersion(), markedVersion, candidateResult.getId() ); logger.trace("Candidate version {} is > provided entity version {} for entityId {}. Not" + "adding to candidate results", candidateResult.getVersion(), markedVersion, candidateResult.getId() );
Collection<SelectFieldMapping> mappings = candidatesList.get(0).getFields(); Observable<EntitySet> entitySets = Observable.from(candidatesList) .map(candidateEntry -> candidateEntry.getCandidateResult().getId()).toList() .flatMap(idList -> entityCollectionManager.load(idList));
/** * Build CandidateResults from direct query */ private CandidateResults buildCandidateResultsForDirectQuery(final List<Identifier> directIdentifiers, final ParsedQuery query, final SearchTypes searchTypes) { Preconditions.checkArgument(searchTypes.getTypes().length > 0, "Search type required"); String entityType = searchTypes.getTypes()[0]; List<CandidateResult> candidates = new ArrayList<>(directIdentifiers.size()); for (Identifier id : directIdentifiers) { CandidateResult candidateResult = null; if (id.isUUID()) { candidateResult = new CandidateResult(entityType, id.getUUID()); } else if (id.isName()) { candidateResult = new CandidateResult(entityType, id.getName()); } candidates.add(candidateResult); } return new CandidateResults(candidates, query.getSelectFieldMappings(), true); }
final Candidate candidate = filterResult.getValue(); final CandidateResult candidateResult = candidate.getCandidateResult(); final Id candidateId = candidateResult.getId(); final UUID candidateVersion = candidateResult.getVersion(); final Candidate candidate = filterResult.getValue(); final CandidateResult candidateResult = candidate.getCandidateResult(); final Id candidateId = candidateResult.getId(); final UUID candidateVersion = candidateResult.getVersion();
/** * Validate each candidate results vs the data loaded from cass */ private void validate( final FilterResult<Candidate> filterCandidate ) { final CandidateResult candidateResult = filterCandidate.getValue().getCandidateResult(); final SearchEdge searchEdge = filterCandidate.getValue().getSearchEdge(); final MvccLogEntry logEntry = versionSet.getMaxVersion( candidateResult.getId() ); final UUID candidateVersion = candidateResult.getVersion(); final UUID entityVersion = logEntry.getVersion(); final Id entityId = logEntry.getEntityId(); //entity is newer than ES version if ( UUIDComparator.staticCompare( entityVersion, candidateVersion ) > 0 ) { logger.warn( "Deindexing stale entity on edge {} for entityId {} and version {}", searchEdge, entityId, entityVersion ); batch.deindex( searchEdge, entityId, entityVersion ); return; } //ES is newer than cass, it means we haven't repaired the record in Cass, we don't want to //remove the ES record, since the read in cass should cause a read repair, just ignore if ( UUIDComparator.staticCompare( candidateVersion, entityVersion ) > 0 ) { logger.warn( "Found a newer version in ES over cassandra for edge {} for entityId {} and version {}. Repair should be run", searchEdge, entityId, entityVersion ); } //they're the same add it final FilterResult<Id> result = new FilterResult<>( entityId, filterCandidate.getPath() ); results.add( result ); } }
if ( !results.isEmpty() && results.get( 0 ).getId().equals( entityObservable.getId() ) ) { found = true;
final boolean isGeo = candidateResult instanceof GeoCandidateResult; final SearchEdge searchEdge = candidate.getSearchEdge(); final Id candidateId = candidateResult.getId(); UUID candidateVersion = candidateResult.getVersion();
assertEquals( entity1.getId(), candidate1.getId() ); assertEquals(entity1.getVersion(), candidate1.getVersion());
assertEquals( entity1.getId(), candidate1.getId() ); assertEquals(entity1.getVersion(), candidate1.getVersion()); assertEquals( entity2.getId(), candidate2.getId() ); assertEquals( entity2.getVersion(), candidate2.getVersion() ); assertEquals(entity1.getId(),candidateResults.get(0).getId()); assertEquals(entity1.getId(),candidateResults.get(0).getId());
@Test public void deleteVerification() throws Throwable { Id ownerId = new SimpleId( "owner" ); IndexEdge indexSCope = new IndexEdgeImpl( ownerId, "user", SearchEdge.NodeType.SOURCE, 10 ); final String middleName = "middleName" + UUIDUtils.newTimeUUID(); Map entityMap = new HashMap() {{ put( "username", "edanuff" ); put( "email", "ed@anuff.com" ); put( "middlename", middleName ); }}; Entity user = EntityIndexMapUtils.fromMap( entityMap ); EntityUtils.setId( user, new SimpleId( "edanuff" ) ); EntityUtils.setVersion( user, UUIDGenerator.newTimeUUID() ); EntityIndexBatch batch = entityIndex.createBatch(); batch.index( indexSCope, user ); indexProducer.put(batch.build()).subscribe();; entityIndex.refreshAsync().toBlocking().first(); final String query = "where username = 'edanuff'"; CandidateResults r = entityIndex.search( indexSCope, SearchTypes.fromTypes( "edanuff" ), query, 10, 0, false); assertEquals( user.getId(), r.get( 0 ).getId()); batch.deindex( indexSCope, user.getId(), user.getVersion() ); indexProducer.put(batch.build()).subscribe();; entityIndex.refreshAsync().toBlocking().first(); // EntityRef r = entityIndex.search( indexSCope, SearchTypes.fromTypes( "edanuff" ), query, 10, 0, false ); assertFalse( r.iterator().hasNext() ); }