You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by mr...@apache.org on 2018/10/23 03:17:44 UTC
[06/16] usergrid git commit: Add ability to query by name/uuid
without using Elasticsearch
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 <md...@google.com>
Authored: Fri Apr 6 16:05:56 2018 -0700
Committer: Keyur Karnik <ke...@gmail.com>
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();
}