Repository: usergrid Updated Branches: refs/heads/master cf0b65366 -> 447b5b830
Enhance the elasticsearch filter so that sort predicates of known entity fields have a sort applied with their specific type rather than all possible types. Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/447b5b83 Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/447b5b83 Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/447b5b83 Branch: refs/heads/master Commit: 447b5b8305f6fddb8ead78755eb0bbeab5dd9ca7 Parents: cf0b653 Author: Michael Russo <russomich...@google.com> Authored: Wed Feb 22 10:43:16 2017 -0800 Committer: Michael Russo <russomich...@google.com> Committed: Wed Feb 22 10:43:16 2017 -0800 ---------------------------------------------------------------------- .../search/AbstractElasticSearchFilter.java | 20 ++++++++++++- .../usergrid/persistence/index/EntityIndex.java | 16 ++++++++++ .../index/impl/EsEntityIndexImpl.java | 8 ++++- .../persistence/index/impl/EsQueryVistor.java | 26 ++++++++++++++++ .../impl/SearchRequestBuilderStrategy.java | 31 ++++++++++---------- 5 files changed, 83 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/usergrid/blob/447b5b83/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 deba16a..4bf723e 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 @@ -21,6 +21,7 @@ package org.apache.usergrid.corepersistence.pipeline.read.search; import org.apache.usergrid.corepersistence.index.IndexLocationStrategyFactory; +import org.apache.usergrid.persistence.Schema; import org.apache.usergrid.persistence.index.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,6 +39,8 @@ import com.google.common.base.Optional; import rx.Observable; import java.util.Collection; +import java.util.HashMap; +import java.util.Map; /** @@ -80,6 +83,21 @@ public abstract class AbstractElasticSearchFilter extends AbstractPathFilter<Id, final SearchTypes searchTypes = getSearchTypes(); + // pull out the basic Usergrid entity info to get known properties and their associated types + final Map<String, Class> propertiesWithType = new HashMap<>(); + for (String type : searchTypes.getTypes()) { + try { + if ( Schema.getDefaultSchema().getEntityInfo(type) != null ){ + Schema.getDefaultSchema().getEntityInfo(type).getProperties().forEach((propName, propValue) -> + propertiesWithType.put(propName, propValue.getType()) + ); + } + }catch (Exception e){ + // do nothing here, clear the potentially partially filled map and fall back to original behavior + propertiesWithType.clear(); + logger.warn("Unable to obtain the default entity type fields with type. Sort may have degraded performance."); + } + } //return all ids that are emitted from this edge return observable.flatMap( idFilterResult -> { @@ -105,7 +123,7 @@ public abstract class AbstractElasticSearchFilter extends AbstractPathFilter<Id, try { final CandidateResults candidateResults = - applicationEntityIndex.search( searchEdge, searchTypes, query, limit, currentOffSet ); + applicationEntityIndex.search( searchEdge, searchTypes, query, limit, currentOffSet, propertiesWithType ); Collection<SelectFieldMapping> fieldMappingCollection = candidateResults.getGetFieldMappings(); http://git-wip-us.apache.org/repos/asf/usergrid/blob/447b5b83/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 8ab2d41..ee12ec8 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 @@ -26,6 +26,7 @@ import org.apache.usergrid.persistence.core.util.Health; import org.apache.usergrid.persistence.model.entity.Id; import rx.Observable; +import java.util.Map; import java.util.UUID; @@ -102,6 +103,21 @@ public interface EntityIndex extends CPManager { CandidateResults search(final SearchEdge searchEdge, final SearchTypes searchTypes, final String query, final int limit, final int offset); + /** + * 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 query The 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 + * @return + */ + CandidateResults search(final SearchEdge searchEdge, final SearchTypes searchTypes, final String query, + final int limit, final int offset, final Map<String, Class> fieldsWithType); + /** * Same as search, just iterates all documents that match the index edge exactly. http://git-wip-us.apache.org/repos/asf/usergrid/blob/447b5b83/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 6e04bed..0b7f18d 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 @@ -411,6 +411,11 @@ public class EsEntityIndexImpl implements EntityIndex,VersionedData { public CandidateResults search( final SearchEdge searchEdge, final SearchTypes searchTypes, final String query, final int limit, final int offset ) { + return search(searchEdge, searchTypes, query, limit, offset, new HashMap<>(0)); + } + + public CandidateResults search( final SearchEdge searchEdge, final SearchTypes searchTypes, final String query, + final int limit, final int offset, final Map<String, Class> fieldsWithType ) { IndexValidationUtils.validateSearchEdge(searchEdge); Preconditions.checkNotNull(searchTypes, "searchTypes cannot be null"); @@ -422,7 +427,8 @@ public class EsEntityIndexImpl implements EntityIndex,VersionedData { final ParsedQuery parsedQuery = ParsedQueryBuilder.build(query); - final SearchRequestBuilder srb = searchRequest.getBuilder( searchEdge, searchTypes, parsedQuery, limit, offset ) + final SearchRequestBuilder srb = searchRequest + .getBuilder( searchEdge, searchTypes, parsedQuery, limit, offset, fieldsWithType ) .setTimeout(TimeValue.timeValueMillis(queryTimeout)); if ( logger.isDebugEnabled() ) { http://git-wip-us.apache.org/repos/asf/usergrid/blob/447b5b83/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 414f716..7ee8961 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 @@ -526,6 +526,32 @@ public class EsQueryVistor implements QueryVisitor { "Unkown search type of " + object.getClass().getName() + " encountered" ); } + /** + * Get the field name for the primitive type + */ + public static String getFieldNameForClass( final Class clazz ) { + if ( clazz == String.class || clazz == UUID.class ) { + return IndexingUtils.FIELD_STRING_NESTED; + } + + if ( clazz == Boolean.class ) { + return IndexingUtils.FIELD_BOOLEAN_NESTED; + } + + + if ( clazz == Integer.class || clazz == Long.class ) { + return IndexingUtils.FIELD_LONG_NESTED; + } + + if ( clazz == Float.class || clazz == Double.class ) { + return IndexingUtils.FIELD_DOUBLE_NESTED; + } + + + throw new UnsupportedOperationException( + "Unkown search type of " + clazz.getClass().getName() + " encountered" ); + } + /** * Lowercase our input http://git-wip-us.apache.org/repos/asf/usergrid/blob/447b5b83/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/SearchRequestBuilderStrategy.java ---------------------------------------------------------------------- diff --git a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/SearchRequestBuilderStrategy.java b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/SearchRequestBuilderStrategy.java index a5c1af3..c201fb6 100644 --- a/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/SearchRequestBuilderStrategy.java +++ b/stack/corepersistence/queryindex/src/main/java/org/apache/usergrid/persistence/index/impl/SearchRequestBuilderStrategy.java @@ -47,6 +47,8 @@ import org.apache.usergrid.persistence.index.query.tree.QueryVisitor; import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import java.util.Map; + import static org.apache.usergrid.persistence.index.impl.IndexingUtils.createContextName; import static org.apache.usergrid.persistence.index.impl.SortBuilder.sortPropertyTermFilter; @@ -79,7 +81,8 @@ public class SearchRequestBuilderStrategy { * Get the search request builder */ public SearchRequestBuilder getBuilder( final SearchEdge searchEdge, final SearchTypes searchTypes, - final ParsedQuery query, final int limit, final int from ) { + final ParsedQuery query, final int limit, final int from, + final Map<String, Class> fieldsWithType ) { Preconditions .checkArgument( limit <= EntityIndex.MAX_LIMIT, "limit is greater than max " + EntityIndex.MAX_LIMIT ); @@ -112,7 +115,7 @@ public class SearchRequestBuilderStrategy { applyDefaultSortPredicates( srb, geoFields ); } else { - applySortPredicates( srb, query, geoFields ); + applySortPredicates( srb, query, geoFields, fieldsWithType ); } @@ -147,44 +150,40 @@ public class SearchRequestBuilderStrategy { * Invoked when there are sort predicates */ private void applySortPredicates( final SearchRequestBuilder srb, final ParsedQuery query, - final GeoSortFields geoFields ) { - + final GeoSortFields geoFields, final Map<String, Class> knownFieldsWithType ) { //we have sort predicates, sort them for ( SortPredicate sp : query.getSortPredicates() ) { - - // we do not know the type of the "order by" property and so we do not know what - // type prefix to use. So, here we add an order by clause for every possible type - // that you can order by: string, number and boolean and we ask ElasticSearch - // to ignore any fields that are not present. final SortOrder order = sp.getDirection().toEsSort(); final String propertyName = sp.getPropertyName(); - //if the user specified a geo field in their sort, then honor their sort order and use the point they // specified if ( geoFields.contains( propertyName ) ) { final GeoDistanceSortBuilder geoSort = geoFields.applyOrder( propertyName, SortOrder.ASC ); srb.addSort( geoSort ); } - - //apply regular sort logic, since this is not a geo point + // fieldsWithType gives the caller an option to provide any schema related details on properties that + // might appear in a sort predicate. loop through these and set a specific sort, rather than adding a sort + // for all possible types + else if ( knownFieldsWithType != null && knownFieldsWithType.size() > 0) { + if (knownFieldsWithType.containsKey(propertyName)){ + srb.addSort( createSort( order, EsQueryVistor.getFieldNameForClass(knownFieldsWithType.get(propertyName)), propertyName ) ); + } + } + //apply regular sort logic which check all possible data types, since this is not a known property name else { - //sort order is arbitrary if the user changes data types. Double, long, string, boolean are supported //default sort types - srb.addSort( createSort( order, IndexingUtils.FIELD_DOUBLE_NESTED, propertyName ) ); - srb.addSort( createSort( order, IndexingUtils.FIELD_LONG_NESTED, propertyName ) ); /** * We always want to sort by the unanalyzed string field to ensure correct ordering */ srb.addSort( createSort( order, IndexingUtils.FIELD_STRING_NESTED_UNANALYZED, propertyName ) ); - srb.addSort( createSort( order, IndexingUtils.FIELD_BOOLEAN_NESTED, propertyName ) ); } }