Add ability to query by name/uuid without using Elasticsearch example ql: "direct widget1,56d8fac2-39ef-11e8-b467-0ed5f89f718b,widget3"
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/57afad20 Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/57afad20 Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/57afad20 Branch: refs/heads/master Commit: 57afad20a6c152550cc7f9fb3d35d445dbb90a25 Parents: 38c7313 Author: Mike Dunker <[email protected]> Authored: Fri Apr 6 16:05:56 2018 -0700 Committer: Keyur Karnik <[email protected]> Committed: Tue Aug 28 16:41:44 2018 -0700 ---------------------------------------------------------------------- .../pipeline/PipelineContext.java | 20 +++- .../search/AbstractElasticSearchFilter.java | 2 +- .../read/search/CandidateEntityFilter.java | 86 ++++++++++++--- .../index/query/tree/CpQueryFilter.g | 110 ++++++++++++------- .../src/main/java/CpQueryFilter.tokens | 67 +++++------ .../persistence/index/CandidateResult.java | 97 +++++++++++++++- .../persistence/index/CandidateResults.java | 12 ++ .../usergrid/persistence/index/EntityIndex.java | 20 ++++ .../usergrid/persistence/index/IndexFig.java | 6 + .../TooManyDirectEntitiesException.java | 49 +++++++++ .../index/impl/EsEntityIndexImpl.java | 56 ++++++++-- .../persistence/index/impl/EsQueryVistor.java | 58 +++++++--- .../persistence/index/query/ParsedQuery.java | 5 + .../index/query/tree/DirectOperand.java | 82 ++++++++++++++ .../persistence/index/query/tree/IdLiteral.java | 46 ++++++++ .../index/query/tree/QueryVisitor.java | 18 ++- 16 files changed, 616 insertions(+), 118 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/PipelineContext.java ---------------------------------------------------------------------- diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/PipelineContext.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/PipelineContext.java index 88b5001..7aa614a 100644 --- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/PipelineContext.java +++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/PipelineContext.java @@ -28,6 +28,10 @@ import org.apache.usergrid.corepersistence.pipeline.cursor.ResponseCursor; import org.apache.usergrid.persistence.core.scope.ApplicationScope; import com.google.common.base.Optional; +import org.apache.usergrid.persistence.index.query.ParsedQuery; +import org.apache.usergrid.persistence.index.query.ParsedQueryBuilder; + +import static org.apache.usergrid.persistence.Query.MAX_LIMIT; /** @@ -43,16 +47,24 @@ public class PipelineContext { // it can happen if ES was not updated or has yet to be updated. private final boolean keepStaleEntries; private String query; + private ParsedQuery parsedQuery; public PipelineContext( final ApplicationScope applicationScope, final RequestCursor requestCursor, final int limit, final int id, boolean keepStaleEntries, String query ) { this.applicationScope = applicationScope; - this.requestCursor = requestCursor; - this.limit = limit; this.id = id; this.keepStaleEntries = keepStaleEntries; this.query = query; + this.parsedQuery = ParsedQueryBuilder.build(query); + if (parsedQuery != null && parsedQuery.isDirectQuery()) { + // for direct query, use no limit or cursor + this.limit = MAX_LIMIT + 1; + this.requestCursor = new RequestCursor(Optional.absent()); + } else { + this.limit = limit; + this.requestCursor = requestCursor; + } } @@ -98,4 +110,8 @@ public class PipelineContext { return query; } + public ParsedQuery getParsedQuery() { + return parsedQuery; + } + } http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/AbstractElasticSearchFilter.java ---------------------------------------------------------------------- diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/AbstractElasticSearchFilter.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/AbstractElasticSearchFilter.java index 7a46507..cc409b0 100644 --- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/AbstractElasticSearchFilter.java +++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/AbstractElasticSearchFilter.java @@ -129,7 +129,7 @@ public abstract class AbstractElasticSearchFilter extends AbstractPathFilter<Id, try { final CandidateResults candidateResults = - applicationEntityIndex.search( searchEdge, searchTypes, query, limit, currentOffSet, + applicationEntityIndex.search( searchEdge, searchTypes, pipelineContext.getParsedQuery(), limit, currentOffSet, propertiesWithType, analyzeOnly, returnQuery); http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java ---------------------------------------------------------------------- diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java index f9c93b0..955b419 100644 --- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java +++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/pipeline/read/search/CandidateEntityFilter.java @@ -24,11 +24,14 @@ import java.util.*; import java.util.logging.Filter; import org.apache.usergrid.corepersistence.index.IndexLocationStrategyFactory; +import org.apache.usergrid.persistence.Schema; import org.apache.usergrid.persistence.index.*; import org.apache.usergrid.persistence.index.impl.IndexProducer; +import org.apache.usergrid.persistence.model.entity.SimpleId; import org.apache.usergrid.persistence.model.field.DistanceField; import org.apache.usergrid.persistence.model.field.EntityObjectField; import org.apache.usergrid.persistence.model.field.Field; +import org.apache.usergrid.persistence.model.field.StringField; import org.apache.usergrid.persistence.model.field.value.EntityObject; import org.apache.usergrid.utils.DateUtils; import org.slf4j.Logger; @@ -100,6 +103,7 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate boolean keepStaleEntries = pipelineContext.getKeepStaleEntries(); String query = pipelineContext.getQuery(); + boolean isDirectQuery = pipelineContext.getParsedQuery().isDirectQuery(); //buffer them to get a page size we can make 1 network hop final Observable<FilterResult<Entity>> searchIdSetObservable = @@ -108,7 +112,12 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate //load them .flatMap( candidateResults -> { - //flatten toa list of ids to load + if (isDirectQuery) { + // add ids for direct query + updateDirectQueryCandidateResults(entityCollectionManager, candidateResults); + } + + //flatten to a list of ids to load final Observable<List<Candidate>> candidates = Observable.from(candidateResults) .map(filterResultCandidate -> filterResultCandidate.getValue()).toList(); @@ -119,12 +128,13 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate Observable<EntitySet> entitySets = Observable.from(candidatesList) .map(candidateEntry -> candidateEntry.getCandidateResult().getId()).toList() .flatMap(idList -> entityCollectionManager.load(idList)); - //now we have a collection, validate our canidate set is correct. + //now we have a collection, validate our candidate set is correct. return entitySets.map( entitySet -> new EntityVerifier( applicationIndex.createBatch(), entitySet, candidateResults,indexProducer) ) - .doOnNext(entityCollector -> entityCollector.merge(keepStaleEntries, query)) + .doOnNext(entityCollector -> entityCollector.merge(keepStaleEntries, query, + isDirectQuery)) .flatMap(entityCollector -> Observable.from(entityCollector.getResults())) .map(entityFilterResult -> { final Entity entity = entityFilterResult.getValue(); @@ -223,6 +233,28 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate /** + * 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); + } + } + + + /** * Our collector to collect entities. Not quite a true collector, but works within our operational * flow as this state is mutable and difficult to represent functionally */ @@ -252,16 +284,30 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate /** * Merge our candidates and our entity set into results */ - public void merge(boolean keepStaleEntries, String query) { - - filterDuplicateCandidates(query); - - for ( final FilterResult<Candidate> candidateResult : dedupedCandidateResults ) { - validate( candidateResult , keepStaleEntries, query); + public void merge(boolean keepStaleEntries, String query, boolean isDirectQuery) { + + if (!isDirectQuery) { + filterDuplicateCandidates(query); + } else { + // remove direct query duplicates + Set<UUID> foundUUIDs = new HashSet<>(); + for (FilterResult<Candidate> candidateFilterResult : candidateResults) { + UUID uuid = candidateFilterResult.getValue().getCandidateResult().getId().getUuid(); + if (!foundUUIDs.contains(uuid)) { + dedupedCandidateResults.add(candidateFilterResult); + foundUUIDs.add(uuid); + } + } } - indexProducer.put(batch.build()).toBlocking().lastOrDefault(null); // want to rethrow if batch fails + 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 + } } @@ -354,14 +400,15 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate } - private void validate( final FilterResult<Candidate> filterResult, boolean keepStaleEntries, String query ) { + private void validate( final FilterResult<Candidate> filterResult, boolean keepStaleEntries, String query, + boolean isDirectQuery) { final Candidate candidate = filterResult.getValue(); final CandidateResult candidateResult = candidate.getCandidateResult(); final boolean isGeo = candidateResult instanceof GeoCandidateResult; final SearchEdge searchEdge = candidate.getSearchEdge(); final Id candidateId = candidateResult.getId(); - final UUID candidateVersion = candidateResult.getVersion(); + UUID candidateVersion = candidateResult.getVersion(); final MvccEntity entity = entitySet.getEntity( candidateId ); @@ -369,9 +416,14 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate //doesn't exist warn and drop if ( entity == null ) { - logger.warn( - "Searched and received candidate with entityId {} and version {}, yet was not found in cassandra. Ignoring since this could be a region sync issue", - candidateId, candidateVersion ); + if (!isDirectQuery) { + logger.warn( + "Searched and received candidate with entityId {} and version {}, yet was not found in cassandra. Ignoring since this could be a region sync issue", + candidateId, candidateVersion); + } else { + logger.warn( + "Direct query for entityId {} was not found in cassandra, query=[{}]", candidateId, query); + } //TODO trigger an audit after a fail count where we explicitly try to repair from other regions @@ -382,6 +434,10 @@ public class CandidateEntityFilter extends AbstractFilter<FilterResult<Candidate final UUID databaseVersion = entity.getVersion(); + if (isDirectQuery) { + // use returned (latest) version for direct query + candidateVersion = databaseVersion; + } final Id entityId = entity.getId(); // The entity is marked as deleted http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/CpQueryFilter.g ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/CpQueryFilter.g b/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/CpQueryFilter.g index 605aed4..d75a617 100644 --- a/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/CpQueryFilter.g +++ b/stack/corepersistence/queryindex/src/main/antlr3/org/apache/usergrid/persistence/index/query/tree/CpQueryFilter.g @@ -112,7 +112,7 @@ EQ : '=' | 'eq'; GT : '>' | 'gt'; -GTE : '>=' | 'gte'; +GTE : '>=' | 'gte'; //keywords before var ids @@ -134,11 +134,14 @@ WITHIN : ('W'|'w')('I'|'i')('T'|'t')('H'|'h')('I'|'i')('N'|'n'); OF : ('O'|'o')('F'|'f'); -UUID : HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT - HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' - HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' - HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' - HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' +DIRECT : ('D'|'d')('I'|'i')('R'|'r')('E'|'e')('C'|'c')('T'|'t'); + +UUID : + HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT + HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' + HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' + HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' + HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT '-' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT @@ -156,18 +159,18 @@ FLOAT | '.' ('0'..'9')+ EXPONENT? | ('0'..'9')+ EXPONENT) ; - + STRING : '\'' ( ESC_SEQ | ~('\\'|'\'') )* '\'' ; - + WS : (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel=HIDDEN;}; - + @@ -208,12 +211,19 @@ UNICODE_ESC -property : ID<Property>; +property : + ID<Property> + | ASC<Property> + | DESC<Property> + | CONTAINS<Property> + | WITHIN<Property> + | DIRECT<Property> + ; containsproperty : ID<ContainsProperty>; withinproperty : ID<WithinProperty>; - + booleanliteral: BOOLEAN<BooleanLiteral>; @@ -225,70 +235,96 @@ uuidliteral : stringliteral : STRING<StringLiteral>; - + floatliteral : FLOAT<FloatLiteral> ; -//We delegate to each sub class literal so we can get each type -value : +idliteral : + ID<IdLiteral> ; + +directnameliteral : + ID<IdLiteral> ; + +directuuidliteral : + UUID<UUIDLiteral>; + +//We delegate to each sub class literal so we can get each type +value : booleanliteral | longliteral | uuidliteral | stringliteral | floatliteral ; - +directidliteral : + directnameliteral + | directuuidliteral + ; //Every operand returns with the name of 'op'. This is used because all subtrees require operands, -//this allows us to link the java code easily by using the same name as a converntion +//this allows us to link the java code easily by using the same name as a convention //begin search expressions - -//mathmatical equality operations + +//mathematical equality operations equalityop : property LT<LessThan>^ value |property LTE<LessThanEqual>^ value |property EQ<Equal>^ value |property GT<GreaterThan>^ value |property GTE<GreaterThanEqual>^ value - ; + ; //geo location search locationop : withinproperty WITHIN<WithinOperand>^ (floatliteral|longliteral) OF! (floatliteral|longliteral) ','! (floatliteral|longliteral); - + //string search containsop : containsproperty CONTAINS<ContainsOperand>^ stringliteral; +directidlist : + directidliteral (','! directidliteral)*; + // operation : - '('! expression ')'! - | equalityop - | locationop - | containsop + '('! orexp ')'! + | equalityop + | locationop + | containsop ; //negations of expressions notexp : //only link if we have the not - NOT<NotOperand>^ operation - |operation + NOT<NotOperand>^ operation + |operation ; //and expressions contain operands. These should always be closer to the leaves of a tree, it allows //for faster result intersection sooner in the query execution andexp : notexp (AND<AndOperand>^ notexp )*; - - + + //or expression should always be after AND expressions. This will give us a smaller result set to union when evaluating trees //also a root level expression -expression : +orexp : andexp (OR<OrOperand>^ andexp )*; +directexp : + DIRECT<DirectOperand>^ directidlist ; + + +// can use DIRECT {UUID|ID}+ at the root +expression : + directexp + | orexp + ; + + //end expressions @@ -300,14 +336,14 @@ direction : (ASC | DESC); //order clause order : (property direction?){ - String property = $property.text; + String property = $property.text; String direction = $direction.text; parsedQuery.addSort(new SortPredicate(property, direction)); - + }; //end order clauses - + //Begin select clauses select_subject @@ -317,7 +353,7 @@ select_subject }; - + select_assign : target=ID ':' source=ID { @@ -326,9 +362,9 @@ select_assign }; -select_expr - : ('*' | select_subject (',' select_subject) * | '{' select_assign (',' select_assign) * '}'); - +select_expr + : ('*' | select_subject (',' select_subject) * | '{' select_assign (',' select_assign) * '}'); + //end select clauses ql returns [ParsedQuery parsedQuery] @@ -337,7 +373,7 @@ ql returns [ParsedQuery parsedQuery] if($expression.tree instanceof Operand){ parsedQuery.setRootOperand((Operand)$expression.tree); } - + retval.parsedQuery = parsedQuery; http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/CpQueryFilter.tokens ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/CpQueryFilter.tokens b/stack/corepersistence/queryindex/src/main/java/CpQueryFilter.tokens index 53a0817..a9e7106 100644 --- a/stack/corepersistence/queryindex/src/main/java/CpQueryFilter.tokens +++ b/stack/corepersistence/queryindex/src/main/java/CpQueryFilter.tokens @@ -1,4 +1,3 @@ -T__31=31 T__32=32 T__33=33 T__34=34 @@ -8,40 +7,42 @@ T__37=37 T__38=38 T__39=39 T__40=40 +T__41=41 AND=4 ASC=5 BOOLEAN=6 CONTAINS=7 DESC=8 -EQ=9 -ESC_SEQ=10 -EXPONENT=11 -FALSE=12 -FLOAT=13 -GT=14 -GTE=15 -HEX_DIGIT=16 -ID=17 -LONG=18 -LT=19 -LTE=20 -NOT=21 -OCTAL_ESC=22 -OF=23 -OR=24 -STRING=25 -TRUE=26 -UNICODE_ESC=27 -UUID=28 -WITHIN=29 -WS=30 -'('=31 -')'=32 -'*'=33 -','=34 -':'=35 -'order by'=36 -'select'=37 -'where'=38 -'{'=39 -'}'=40 +DIRECT=9 +EQ=10 +ESC_SEQ=11 +EXPONENT=12 +FALSE=13 +FLOAT=14 +GT=15 +GTE=16 +HEX_DIGIT=17 +ID=18 +LONG=19 +LT=20 +LTE=21 +NOT=22 +OCTAL_ESC=23 +OF=24 +OR=25 +STRING=26 +TRUE=27 +UNICODE_ESC=28 +UUID=29 +WITHIN=30 +WS=31 +'('=32 +')'=33 +'*'=34 +','=35 +':'=36 +'order by'=37 +'select'=38 +'where'=39 +'{'=40 +'}'=41 http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/CandidateResult.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/CandidateResult.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/CandidateResult.java index 9b1898c..65c20f0 100644 --- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/CandidateResult.java +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/CandidateResult.java @@ -30,14 +30,59 @@ import org.apache.usergrid.persistence.model.entity.Id; * An instance of a candidate result */ public class CandidateResult implements EntityVersion { - private final Id entityId; + private Id entityId; private final UUID entityVersion; private final String docId; + private final String directEntityName; + private final UUID directEntityUUID; + private final String directEntityType; public CandidateResult( Id entityId, UUID entityVersion, String docId ) { this.entityId = entityId; this.entityVersion = entityVersion; this.docId = docId; + this.directEntityName = null; + this.directEntityUUID = null; + this.directEntityType = null; + } + + public CandidateResult( Id entityId, CandidateResult sourceResult ) { + this.entityId = entityId; + this.entityVersion = sourceResult.entityVersion; + this.docId = sourceResult.docId; + this.directEntityName = sourceResult.directEntityName; + this.directEntityUUID = sourceResult.directEntityUUID; + this.directEntityType = sourceResult.directEntityType; + } + + // direct query by name before resolution + public CandidateResult( String entityType, String directEntityName ) { + this.directEntityName = directEntityName; + this.directEntityUUID = null; + this.directEntityType = entityType; + this.entityId = null; + this.entityVersion = null; + this.docId = null; + } + + // direct query by UUID before resolution + public CandidateResult( String entityType, UUID directEntityUUID ) { + this.directEntityUUID = directEntityUUID; + this.directEntityName = null; + this.directEntityType = entityType; + this.entityId = null; + this.entityVersion = null; + this.docId = null; + } + + public boolean isDirectQueryName() { + return directEntityName != null; + } + public boolean isDirectQueryUUID() { + return directEntityUUID != null; + } + public boolean isDirectQuery() { + return isDirectQueryName() || isDirectQueryUUID(); } @Override @@ -54,25 +99,69 @@ public class CandidateResult implements EntityVersion { return docId; } + public String getDirectEntityName() { + return directEntityName; + } + + public UUID getDirectEntityUUID() { + return directEntityUUID; + } + + public String getDirectEntityType() { + return directEntityType; + } + + // use to set id for direct query after resolution + public void setId(Id entityId) { + this.entityId = entityId; + } + @Override public boolean equals( final Object o ) { if ( this == o ) { return true; } + if ( o == null ) { + return false; + } if ( !( o instanceof CandidateResult ) ) { return false; } final CandidateResult that = ( CandidateResult ) o; - if ( !entityId.equals( that.entityId ) ) { + if ( entityId == null && that.entityId != null) { + return false; + } + if ( entityId != null && !entityId.equals( that.entityId ) ) { + return false; + } + if ( entityVersion == null && that.entityVersion != null) { + return false; + } + if ( entityVersion != null && !entityVersion.equals( that.entityVersion ) ) { + return false; + } + if ( docId == null && that.docId != null) { + return false; + } + if ( docId != null && !docId.equals( that.docId ) ) { + return false; + } + if ( directEntityUUID != that.directEntityUUID ) { + return false; + } + if ( directEntityName == null && that.directEntityName != null) { + return false; + } + if ( directEntityName != null && !directEntityName.equals( that.directEntityName ) ) { return false; } - if ( !entityVersion.equals( that.entityVersion ) ) { + if ( directEntityType == null && that.directEntityType != null) { return false; } - if ( !docId.equals( that.docId ) ) { + if ( directEntityType != null && !directEntityType.equals( that.directEntityType ) ) { return false; } http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/CandidateResults.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/CandidateResults.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/CandidateResults.java index b8f87b6..3a69706 100644 --- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/CandidateResults.java +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/CandidateResults.java @@ -38,11 +38,19 @@ public class CandidateResults implements Iterable<CandidateResult> { private final List<CandidateResult> candidates; private final Collection<SelectFieldMapping> getFieldMappings; + private final boolean isDirectQuery; public CandidateResults( List<CandidateResult> candidates, final Collection<SelectFieldMapping> getFieldMappings) { + this(candidates, getFieldMappings, false); + } + + public CandidateResults(List<CandidateResult> candidates, + final Collection<SelectFieldMapping> getFieldMappings, + final boolean isDirectQuery) { this.candidates = candidates; this.getFieldMappings = getFieldMappings; offset = Optional.absent(); + this.isDirectQuery = isDirectQuery; } @@ -82,6 +90,10 @@ public class CandidateResults implements Iterable<CandidateResult> { return getFieldMappings; } + public boolean isDirectQuery() { + return this.isDirectQuery; + } + /** * Get the candidates http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java index afcfdd7..ebe6824 100644 --- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/EntityIndex.java @@ -22,6 +22,7 @@ package org.apache.usergrid.persistence.index; import org.apache.usergrid.persistence.core.CPManager; import org.apache.usergrid.persistence.core.util.Health; +import org.apache.usergrid.persistence.index.query.ParsedQuery; import org.apache.usergrid.persistence.model.entity.Id; import rx.Observable; @@ -140,6 +141,25 @@ public interface EntityIndex extends CPManager { final int limit, final int offset, final Map<String, Class> fieldsWithType, final boolean analyzeOnly, final boolean returnQuery); + /** + * Search on every document in the specified search edge. Also search by the types if specified + * + * @param searchEdge The edge to search on + * @param searchTypes The search types to search + * @param parsedQuery The parsed query to execute + * @param limit The limit of values to return + * @param offset The offset to query on + * @param fieldsWithType An optional param that allows the caller to provide schema related info which might + * relate to data in the query, such as sort predicate types + * @param analyzeOnly This optional param will instruct the query processing to only analyze the query and + * provide info but not actually execute the query. + * @param returnQuery This optional param will cause the index query to be returned instead of run. + * @return + */ + CandidateResults search(final SearchEdge searchEdge, final SearchTypes searchTypes, final ParsedQuery parsedQuery, + final int limit, final int offset, final Map<String, Class> fieldsWithType, + final boolean analyzeOnly, final boolean returnQuery); + /** * Same as search, just iterates all documents that match the index edge exactly. http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/IndexFig.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/IndexFig.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/IndexFig.java index 9b42da3..493a722 100644 --- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/IndexFig.java +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/IndexFig.java @@ -72,6 +72,8 @@ public interface IndexFig extends GuicyFig { String USERGRID_QUERYANALYZER_ENFORCE = "usergrid.queryanalyzer.enforce"; + String DIRECT_QUERY_MAX_ITEMS = "direct.query.max.items"; + @@ -238,4 +240,8 @@ public interface IndexFig extends GuicyFig { @Default("false") @Key( USERGRID_QUERYANALYZER_ENFORCE ) boolean enforceQueryBreaker(); + + @Default("1000") + @Key( DIRECT_QUERY_MAX_ITEMS ) + int directQueryMaxItems(); } http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/TooManyDirectEntitiesException.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/TooManyDirectEntitiesException.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/TooManyDirectEntitiesException.java new file mode 100644 index 0000000..b3f2052 --- /dev/null +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/exceptions/TooManyDirectEntitiesException.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.usergrid.persistence.index.exceptions; + + +/** + * Thrown when the user attempts to perform a "direct" operation with more than the max limit number of entities + */ +public class TooManyDirectEntitiesException extends QueryException { + + /** + * + */ + private static final long serialVersionUID = 1L; + final private int numberItemsRequested; + final private int maxItemsAllowed; + + + public TooManyDirectEntitiesException(int numberItemsRequested, int maxItemsAllowed) { + super( "Exceeded maximum number of direct entities requested: " + + Integer.toString(numberItemsRequested) + " requested, limit is " + Integer.toString(maxItemsAllowed)); + this.numberItemsRequested = numberItemsRequested; + this.maxItemsAllowed = maxItemsAllowed; + } + + + public int getNumberItemsRequested() { + return numberItemsRequested; + } + + + public int getMaxNumberItems() { + return maxItemsAllowed; + } +} http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java index e3121e1..6dfb2ae 100644 --- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsEntityIndexImpl.java @@ -36,11 +36,9 @@ import org.apache.usergrid.persistence.core.util.Health; import org.apache.usergrid.persistence.core.util.StringUtils; import org.apache.usergrid.persistence.index.*; import org.apache.usergrid.persistence.index.ElasticSearchQueryBuilder.SearchRequestBuilderStrategyV2; -import org.apache.usergrid.persistence.index.exceptions.IndexException; -import org.apache.usergrid.persistence.index.exceptions.QueryAnalyzerException; -import org.apache.usergrid.persistence.index.exceptions.QueryAnalyzerEnforcementException; -import org.apache.usergrid.persistence.index.exceptions.QueryReturnException; +import org.apache.usergrid.persistence.index.exceptions.*; import org.apache.usergrid.persistence.index.migration.IndexDataVersions; +import org.apache.usergrid.persistence.index.query.Identifier; import org.apache.usergrid.persistence.index.query.ParsedQuery; import org.apache.usergrid.persistence.index.query.ParsedQueryBuilder; import org.apache.usergrid.persistence.index.query.SortPredicate; @@ -437,23 +435,38 @@ public class EsEntityIndexImpl implements EntityIndex,VersionedData { public CandidateResults search( final SearchEdge searchEdge, final SearchTypes searchTypes, final String query, final int limit, final int offset, final Map<String, Class> fieldsWithType, final boolean analyzeOnly, final boolean returnQuery ) { + Preconditions.checkNotNull( query, "query cannot be null" ); + final ParsedQuery parsedQuery = ParsedQueryBuilder.build(query); + + return search(searchEdge, searchTypes, parsedQuery, limit, offset, fieldsWithType, analyzeOnly, returnQuery); + } + + public CandidateResults search( final SearchEdge searchEdge, final SearchTypes searchTypes, final ParsedQuery parsedQuery, + final int limit, final int offset, final Map<String, Class> fieldsWithType, + final boolean analyzeOnly, final boolean returnQuery ) { IndexValidationUtils.validateSearchEdge(searchEdge); Preconditions.checkNotNull(searchTypes, "searchTypes cannot be null"); - Preconditions.checkNotNull( query, "query cannot be null" ); Preconditions.checkArgument( limit > 0, "limit must be > 0" ); SearchResponse searchResponse; - final ParsedQuery parsedQuery = ParsedQueryBuilder.build(query); - if ( parsedQuery == null ){ throw new IllegalArgumentException("a null query string cannot be parsed"); } final QueryVisitor visitor = visitParsedQuery(parsedQuery); + List<Identifier> directIdentifiers = visitor.getDirectIdentifiers(); + if (directIdentifiers != null && directIdentifiers.size() > 0) { + // this is a direct query + if (directIdentifiers.size() > indexFig.directQueryMaxItems()) { + throw new TooManyDirectEntitiesException(directIdentifiers.size(), indexFig.directQueryMaxItems()); + } + return buildCandidateResultsForDirectQuery(directIdentifiers, parsedQuery, searchTypes); + } + boolean hasGeoSortPredicates = false; for (SortPredicate sortPredicate : parsedQuery.getSortPredicates() ){ @@ -644,7 +657,7 @@ public class EsEntityIndexImpl implements EntityIndex,VersionedData { /** - * Parse the results and return the canddiate results + * Parse the results and return the candidate results */ private CandidateResults parseResults( final SearchResponse searchResponse, final ParsedQuery query, final int limit, final int from, boolean hasGeoSortPredicates ) { @@ -677,6 +690,33 @@ public class EsEntityIndexImpl implements EntityIndex,VersionedData { return candidateResults; } + + /** + * 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); + } + + + private List<CandidateResult> aggregateScrollResults(List<CandidateResult> candidates, final SearchResponse searchResponse, final UUID markedVersion){ http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsQueryVistor.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsQueryVistor.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsQueryVistor.java index 4dd0d24..7f08ee3 100644 --- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsQueryVistor.java +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/EsQueryVistor.java @@ -19,9 +19,10 @@ package org.apache.usergrid.persistence.index.impl; -import java.util.Stack; -import java.util.UUID; +import java.util.*; +import org.apache.usergrid.persistence.index.query.Identifier; +import org.apache.usergrid.persistence.index.query.tree.*; import org.elasticsearch.common.geo.GeoDistance; import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.index.query.BoolFilterBuilder; @@ -44,17 +45,6 @@ import org.slf4j.LoggerFactory; import org.apache.usergrid.persistence.index.exceptions.IndexException; import org.apache.usergrid.persistence.index.exceptions.NoFullTextIndexException; import org.apache.usergrid.persistence.index.exceptions.NoIndexException; -import org.apache.usergrid.persistence.index.query.tree.AndOperand; -import org.apache.usergrid.persistence.index.query.tree.ContainsOperand; -import org.apache.usergrid.persistence.index.query.tree.Equal; -import org.apache.usergrid.persistence.index.query.tree.GreaterThan; -import org.apache.usergrid.persistence.index.query.tree.GreaterThanEqual; -import org.apache.usergrid.persistence.index.query.tree.LessThan; -import org.apache.usergrid.persistence.index.query.tree.LessThanEqual; -import org.apache.usergrid.persistence.index.query.tree.NotOperand; -import org.apache.usergrid.persistence.index.query.tree.OrOperand; -import org.apache.usergrid.persistence.index.query.tree.QueryVisitor; -import org.apache.usergrid.persistence.index.query.tree.WithinOperand; import com.google.common.base.Optional; @@ -79,6 +69,13 @@ public class EsQueryVistor implements QueryVisitor { private final GeoSortFields geoSortFields = new GeoSortFields(); + /** + * Query direct to C* bypassing ES + */ + private final List<Identifier> directIdList = new ArrayList<>(); + + + @Override public void visit( AndOperand op ) throws IndexException { @@ -323,6 +320,35 @@ public class EsQueryVistor implements QueryVisitor { @Override + public void visit( DirectOperand op ) { + List<Literal> idList = op.getDirectIds(); + + Set<Identifier> idSet = new HashSet<>(); + + for (Literal literal : idList) { + + Identifier identifier = null; + if (literal instanceof IdLiteral) { + String name = ((IdLiteral)literal).getValue(); + identifier = Identifier.fromName(name); + } else if (literal instanceof UUIDLiteral) { + UUID uuid = ((UUIDLiteral)literal).getValue(); + identifier = Identifier.fromUUID(uuid); + } + // should only allow IdLiteral or UUIDLiteral, ignore if other + + if (identifier != null) { + // ignore if already seen + if (!idSet.contains(identifier)) { + directIdList.add(identifier); + idSet.add(identifier); + } + } + } + } + + + @Override public void visit( LessThan op ) throws NoIndexException { final String name = op.getProperty().getValue().toLowerCase(); final Object value = op.getLiteral().getValue(); @@ -472,6 +498,12 @@ public class EsQueryVistor implements QueryVisitor { } + @Override + public List<Identifier> getDirectIdentifiers() { + return directIdList; + } + + /** * Generate the field name term for the field name for queries */ http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQuery.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQuery.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQuery.java index 1cb3ba2..80ba6b1 100644 --- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQuery.java +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/ParsedQuery.java @@ -34,6 +34,7 @@ import java.util.Set; import org.apache.usergrid.persistence.index.SelectFieldMapping; import org.apache.usergrid.persistence.index.exceptions.QueryParseException; +import org.apache.usergrid.persistence.index.query.tree.DirectOperand; import org.apache.usergrid.persistence.index.query.tree.Operand; @@ -206,4 +207,8 @@ public class ParsedQuery { public boolean isGeoQuery(){ return getOriginalQuery().contains("location") && getOriginalQuery().contains("within"); } + + public boolean isDirectQuery() { + return rootOperand instanceof DirectOperand; + } } http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/DirectOperand.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/DirectOperand.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/DirectOperand.java new file mode 100644 index 0000000..796dc5e --- /dev/null +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/DirectOperand.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.usergrid.persistence.index.query.tree; + + +import org.antlr.runtime.Token; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + + +public class DirectOperand extends Operand { + + public DirectOperand(Token t ) { + super( t ); + } + + /* + * (non-Javadoc) + * + * @see + * org.apache.usergrid.persistence.query.tree.Operand#visit(org.apache.usergrid.persistence + * .query.tree.QueryVisitor) + */ + @Override + public void visit( QueryVisitor visitor ) { + visitor.visit( this ); + } + + + /** + * @param name + * @param index + */ + public void setDirectId( String name, int index ) { + setChild( index, new IdLiteral( name ) ); + } + + + /** + * @param uuid + * @param index + */ + public void setDirectId(UUID uuid, int index ) { + setChild( index, new UUIDLiteral( uuid ) ); + } + + /** + * @param index + * @return + */ + public Literal getDirectId( int index ) { + return ( Literal ) this.children.get( index ); + } + + /** + * @return + */ + public List<Literal> getDirectIds() { + List<Literal> ids = new ArrayList<>(); + for (Object child : this.children) { + ids.add((Literal) child); + } + return ids; + } + +} http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/IdLiteral.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/IdLiteral.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/IdLiteral.java new file mode 100644 index 0000000..1defdd3 --- /dev/null +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/IdLiteral.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. The ASF licenses this file to You + * under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. For additional information regarding + * copyright in this work, please see the NOTICE file in the top level + * directory of this distribution. + */ + +package org.apache.usergrid.persistence.index.query.tree; + + +import org.antlr.runtime.ClassicToken; +import org.antlr.runtime.Token; + + +public class IdLiteral extends Literal<String> { + + private String value; + + + public IdLiteral(Token t ) { + super( t ); + value = t.getText(); + } + + + public IdLiteral(String value ) { + super( new ClassicToken( 0, value ) ); + this.value = value; + } + + + public String getValue() { + return this.value; + } +} http://git-wip-us.apache.org/repos/asf/usergrid/blob/57afad20/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/QueryVisitor.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/QueryVisitor.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/QueryVisitor.java index 273f23f..6c191cf 100644 --- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/QueryVisitor.java +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/query/tree/QueryVisitor.java @@ -19,19 +19,16 @@ package org.apache.usergrid.persistence.index.query.tree; -import java.util.Collection; -import java.util.Map; -import java.util.Set; +import java.util.List; import org.apache.usergrid.persistence.index.exceptions.NoFullTextIndexException; import org.apache.usergrid.persistence.index.exceptions.NoIndexException; import org.apache.usergrid.persistence.index.exceptions.IndexException; import org.apache.usergrid.persistence.index.impl.GeoSortFields; -import org.apache.usergrid.persistence.index.query.SortPredicate; +import org.apache.usergrid.persistence.index.query.Identifier; import org.elasticsearch.index.query.FilterBuilder; import org.elasticsearch.index.query.QueryBuilder; -import org.elasticsearch.search.sort.GeoDistanceSortBuilder; import com.google.common.base.Optional; @@ -103,6 +100,12 @@ public interface QueryVisitor { */ void visit( GreaterThanEqual op ) throws NoIndexException; + /** + * @param op + * @throws NoIndexException + */ + void visit( DirectOperand op ); + /** * Return any filters created during parsing @@ -126,4 +129,9 @@ public interface QueryVisitor { * @return The GeoSortFields null safe */ GeoSortFields getGeoSorts(); + + /** + * Return list of identifiers for direct query + */ + List<Identifier> getDirectIdentifiers(); }
