From 3cd54fc4ee70a395e26dc5220e8245a55e2723aa Mon Sep 17 00:00:00 2001 From: Martijn van Groningen Date: Thu, 13 Sep 2012 15:47:24 +0200 Subject: [PATCH] Improve `has_child` filter / query performance (#2251) Added a new has_child filter implementation, that works _uid based instead of bitset based. This implementation is about ~2 till ~6 times (depending on the query) faster than the already existing bitset based implementation. --- .../index/query/HasChildFilterBuilder.java | 17 +- .../index/query/HasChildFilterParser.java | 7 +- .../index/query/HasChildQueryBuilder.java | 17 +- .../index/query/HasChildQueryParser.java | 7 +- .../index/query/HasParentFilterBuilder.java | 2 +- .../index/query/HasParentFilterParser.java | 1 - .../index/search/child/HasChildFilter.java | 183 +++++++++++++----- .../index/search/child/HasParentFilter.java | 30 +-- .../search/child/ChildSearchBenchmark.java | 77 +++++--- .../BitsetExecutionChildQuerySearchTests.java | 32 +++ .../child/SimpleChildQuerySearchTests.java | 63 +++--- 11 files changed, 319 insertions(+), 117 deletions(-) create mode 100644 src/test/java/org/elasticsearch/test/integration/search/child/BitsetExecutionChildQuerySearchTests.java diff --git a/src/main/java/org/elasticsearch/index/query/HasChildFilterBuilder.java b/src/main/java/org/elasticsearch/index/query/HasChildFilterBuilder.java index 3b65784307a..c2efa525502 100644 --- a/src/main/java/org/elasticsearch/index/query/HasChildFilterBuilder.java +++ b/src/main/java/org/elasticsearch/index/query/HasChildFilterBuilder.java @@ -36,6 +36,8 @@ public class HasChildFilterBuilder extends BaseFilterBuilder { private String filterName; + private String executionType; + public HasChildFilterBuilder(String type, QueryBuilder queryBuilder) { this.childType = type; this.queryBuilder = queryBuilder; @@ -54,18 +56,31 @@ public class HasChildFilterBuilder extends BaseFilterBuilder { return this; } + /** + * Expert: Sets the low level child to parent filtering implementation. Can be: 'bitset' or 'uid' + * + * This option is experimental and will be removed. + */ + public HasChildFilterBuilder executionType(String executionType) { + this.executionType = executionType; + return this; + } + @Override protected void doXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(HasChildFilterParser.NAME); builder.field("query"); queryBuilder.toXContent(builder, params); - builder.field("type", childType); + builder.field("child_type", childType); if (scope != null) { builder.field("_scope", scope); } if (filterName != null) { builder.field("_name", filterName); } + if (executionType != null) { + builder.field("execution_type", executionType); + } builder.endObject(); } } diff --git a/src/main/java/org/elasticsearch/index/query/HasChildFilterParser.java b/src/main/java/org/elasticsearch/index/query/HasChildFilterParser.java index 2a356942015..c4b897e81d0 100644 --- a/src/main/java/org/elasticsearch/index/query/HasChildFilterParser.java +++ b/src/main/java/org/elasticsearch/index/query/HasChildFilterParser.java @@ -56,6 +56,7 @@ public class HasChildFilterParser implements FilterParser { String childType = null; String scope = null; + String executionType = "uid"; String filterName = null; String currentFieldName = null; XContentParser.Token token; @@ -77,12 +78,14 @@ public class HasChildFilterParser implements FilterParser { throw new QueryParsingException(parseContext.index(), "[has_child] filter does not support [" + currentFieldName + "]"); } } else if (token.isValue()) { - if ("type".equals(currentFieldName)) { + if ("type".equals(currentFieldName) || "child_type".equals(currentFieldName) || "childType".equals(currentFieldName)) { childType = parser.text(); } else if ("_scope".equals(currentFieldName)) { scope = parser.text(); } else if ("_name".equals(currentFieldName)) { filterName = parser.text(); + } else if ("execution_type".equals(currentFieldName) || "executionType".equals(currentFieldName)) {// This option is experimental and will most likely be removed. + executionType = parser.text(); } else { throw new QueryParsingException(parseContext.index(), "[has_child] filter does not support [" + currentFieldName + "]"); } @@ -112,7 +115,7 @@ public class HasChildFilterParser implements FilterParser { SearchContext searchContext = SearchContext.current(); - HasChildFilter childFilter = new HasChildFilter(query, scope, childType, parentType, searchContext); + HasChildFilter childFilter = HasChildFilter.create(query, scope, parentType, childType, searchContext, executionType); searchContext.addScopePhase(childFilter); if (filterName != null) { diff --git a/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java b/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java index bcddc1c080e..13c94abe554 100644 --- a/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java +++ b/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java @@ -36,6 +36,8 @@ public class HasChildQueryBuilder extends BaseQueryBuilder implements BoostableQ private float boost = 1.0f; + private String executionType; + public HasChildQueryBuilder(String type, QueryBuilder queryBuilder) { this.childType = type; this.queryBuilder = queryBuilder; @@ -59,18 +61,31 @@ public class HasChildQueryBuilder extends BaseQueryBuilder implements BoostableQ return this; } + /** + * Expert: Sets the low level child to parent filtering implementation. Can be: 'bitset' or 'uid' + * + * This option is experimental and will be removed. + */ + public HasChildQueryBuilder executionType(String executionType) { + this.executionType = executionType; + return this; + } + @Override protected void doXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(HasChildQueryParser.NAME); builder.field("query"); queryBuilder.toXContent(builder, params); - builder.field("type", childType); + builder.field("child_type", childType); if (scope != null) { builder.field("_scope", scope); } if (boost != 1.0f) { builder.field("boost", boost); } + if (executionType != null) { + builder.field("execution_type", executionType); + } builder.endObject(); } } diff --git a/src/main/java/org/elasticsearch/index/query/HasChildQueryParser.java b/src/main/java/org/elasticsearch/index/query/HasChildQueryParser.java index 73dbe6ed2ee..391df38adbb 100644 --- a/src/main/java/org/elasticsearch/index/query/HasChildQueryParser.java +++ b/src/main/java/org/elasticsearch/index/query/HasChildQueryParser.java @@ -57,6 +57,7 @@ public class HasChildQueryParser implements QueryParser { String childType = null; String scope = null; + String executionType = "uid"; String currentFieldName = null; XContentParser.Token token; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { @@ -77,12 +78,14 @@ public class HasChildQueryParser implements QueryParser { throw new QueryParsingException(parseContext.index(), "[has_child] query does not support [" + currentFieldName + "]"); } } else if (token.isValue()) { - if ("type".equals(currentFieldName)) { + if ("type".equals(currentFieldName) || "child_type".equals(currentFieldName) || "childType".equals(currentFieldName)) { childType = parser.text(); } else if ("_scope".equals(currentFieldName)) { scope = parser.text(); } else if ("boost".equals(currentFieldName)) { boost = parser.floatValue(); + } else if ("execution_type".equals(currentFieldName) || "executionType".equals(currentFieldName)) {// This option is experimental and will most likely be removed. + executionType = parser.text(); } else { throw new QueryParsingException(parseContext.index(), "[has_child] query does not support [" + currentFieldName + "]"); } @@ -112,7 +115,7 @@ public class HasChildQueryParser implements QueryParser { query = new FilteredQuery(query, parseContext.cacheFilter(childDocMapper.typeFilter(), null)); SearchContext searchContext = SearchContext.current(); - HasChildFilter childFilter = new HasChildFilter(query, scope, childType, parentType, searchContext); + HasChildFilter childFilter = HasChildFilter.create(query, scope, parentType, childType, searchContext, executionType); // we don't need DeletionAwareConstantScore, since we filter deleted parent docs in the filter ConstantScoreQuery childQuery = new ConstantScoreQuery(childFilter); childQuery.setBoost(boost); diff --git a/src/main/java/org/elasticsearch/index/query/HasParentFilterBuilder.java b/src/main/java/org/elasticsearch/index/query/HasParentFilterBuilder.java index eebb452312a..36655760bf7 100644 --- a/src/main/java/org/elasticsearch/index/query/HasParentFilterBuilder.java +++ b/src/main/java/org/elasticsearch/index/query/HasParentFilterBuilder.java @@ -54,7 +54,7 @@ public class HasParentFilterBuilder extends BaseFilterBuilder { } /** - * Expert: Sets the low level parent to child filtering implementation. Can be: 'indirect' or 'uid' + * Expert: Sets the low level parent to child filtering implementation. Can be: 'bitset' or 'uid' * * This option is experimental and will be removed. */ diff --git a/src/main/java/org/elasticsearch/index/query/HasParentFilterParser.java b/src/main/java/org/elasticsearch/index/query/HasParentFilterParser.java index 3b4d1614b1c..30e73aa3eb7 100644 --- a/src/main/java/org/elasticsearch/index/query/HasParentFilterParser.java +++ b/src/main/java/org/elasticsearch/index/query/HasParentFilterParser.java @@ -85,7 +85,6 @@ public class HasParentFilterParser implements FilterParser { scope = parser.text(); } else if ("_name".equals(currentFieldName)) { filterName = parser.text(); - // TODO: change to execution_type } else if ("execution_type".equals(currentFieldName) || "executionType".equals(currentFieldName)) { // This option is experimental and will most likely be removed. executionType = parser.text(); } else { diff --git a/src/main/java/org/elasticsearch/index/search/child/HasChildFilter.java b/src/main/java/org/elasticsearch/index/search/child/HasChildFilter.java index 5a6c8c8a64b..ff74f455693 100644 --- a/src/main/java/org/elasticsearch/index/search/child/HasChildFilter.java +++ b/src/main/java/org/elasticsearch/index/search/child/HasChildFilter.java @@ -19,12 +19,19 @@ package org.elasticsearch.index.search.child; +import gnu.trove.set.hash.THashSet; import org.apache.lucene.index.IndexReader; import org.apache.lucene.search.Collector; import org.apache.lucene.search.DocIdSet; import org.apache.lucene.search.Filter; import org.apache.lucene.search.Query; import org.apache.lucene.util.FixedBitSet; +import org.elasticsearch.ElasticSearchIllegalStateException; +import org.elasticsearch.common.CacheRecycler; +import org.elasticsearch.common.bytes.HashedBytesArray; +import org.elasticsearch.common.lucene.docset.GetDocSet; +import org.elasticsearch.common.lucene.search.NoopCollector; +import org.elasticsearch.index.cache.id.IdReaderTypeCache; import org.elasticsearch.search.internal.ScopePhase; import org.elasticsearch.search.internal.SearchContext; @@ -34,68 +41,150 @@ import java.util.Map; /** * */ -public class HasChildFilter extends Filter implements ScopePhase.CollectorPhase { +public abstract class HasChildFilter extends Filter implements ScopePhase.CollectorPhase { - private Query query; + final Query childQuery; + final String scope; + final String parentType; + final String childType; + final SearchContext searchContext; - private String scope; - - private String parentType; - - private String childType; - - private final SearchContext searchContext; - - private Map parentDocs; - - public HasChildFilter(Query query, String scope, String childType, String parentType, SearchContext searchContext) { - this.query = query; - this.scope = scope; + protected HasChildFilter(Query childQuery, String scope, String parentType, String childType, SearchContext searchContext) { + this.searchContext = searchContext; this.parentType = parentType; this.childType = childType; - this.searchContext = searchContext; + this.scope = scope; + this.childQuery = childQuery; } - @Override public Query query() { - return query; + return childQuery; } - @Override - public boolean requiresProcessing() { - return parentDocs == null; - } - - @Override - public Collector collector() { - return new ChildCollector(parentType, searchContext); - } - - @Override - public void processCollector(Collector collector) { - this.parentDocs = ((ChildCollector) collector).parentDocs(); - } - - @Override public String scope() { - return this.scope; - } - - @Override - public void clear() { - parentDocs = null; - } - - @Override - public DocIdSet getDocIdSet(IndexReader reader) throws IOException { - // ok to return null - return parentDocs.get(reader.getCoreCacheKey()); + return scope; } @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("child_filter[").append(childType).append("/").append(parentType).append("](").append(query).append(')'); + sb.append("child_filter[").append(childType).append("/").append(parentType).append("](").append(childQuery).append(')'); return sb.toString(); } + + public static HasChildFilter create(Query childQuery, String scope, String parentType, String childType, SearchContext searchContext, String executionType) { + // This mechanism is experimental and will most likely be removed. + if ("bitset".equals(executionType)) { + return new Bitset(childQuery, scope, parentType, childType, searchContext); + } else if ("uid".endsWith(executionType)) { + return new Uid(childQuery, scope, parentType, childType, searchContext); + } + throw new ElasticSearchIllegalStateException("Illegal has_child execution type: " + executionType); + } + + static class Bitset extends HasChildFilter { + + private Map parentDocs; + + public Bitset(Query childQuery, String scope, String parentType, String childType, SearchContext searchContext) { + super(childQuery, scope, parentType, childType, searchContext); + } + + public boolean requiresProcessing() { + return parentDocs == null; + } + + public Collector collector() { + return new ChildCollector(parentType, searchContext); + } + + public void processCollector(Collector collector) { + this.parentDocs = ((ChildCollector) collector).parentDocs(); + } + + public void clear() { + parentDocs = null; + } + + public DocIdSet getDocIdSet(IndexReader reader) throws IOException { + // ok to return null + return parentDocs.get(reader.getCoreCacheKey()); + } + + } + + static class Uid extends HasChildFilter { + + THashSet collectedUids; + + Uid(Query childQuery, String scope, String parentType, String childType, SearchContext searchContext) { + super(childQuery, scope, parentType, childType, searchContext); + } + + public boolean requiresProcessing() { + return collectedUids == null; + } + + public Collector collector() { + collectedUids = CacheRecycler.popHashSet(); + return new UidCollector(parentType, searchContext, collectedUids); + } + + public void processCollector(Collector collector) { + collectedUids = ((UidCollector) collector).collectedUids; + } + + public DocIdSet getDocIdSet(IndexReader reader) throws IOException { + IdReaderTypeCache idReaderTypeCache = searchContext.idCache().reader(reader).type(parentType); + return new ParentDocSet(reader, collectedUids, idReaderTypeCache); + } + + public void clear() { + CacheRecycler.pushHashSet(collectedUids); + collectedUids = null; + } + + static class ParentDocSet extends GetDocSet { + + final IndexReader reader; + final THashSet parents; + final IdReaderTypeCache typeCache; + + ParentDocSet(IndexReader reader, THashSet parents, IdReaderTypeCache typeCache) { + super(reader.maxDoc()); + this.reader = reader; + this.parents = parents; + this.typeCache = typeCache; + } + + public boolean get(int doc) { + return !reader.isDeleted(doc) && parents.contains(typeCache.idByDoc(doc)); + } + } + + static class UidCollector extends NoopCollector { + + final String parentType; + final SearchContext context; + final THashSet collectedUids; + + private IdReaderTypeCache typeCache; + + UidCollector(String parentType, SearchContext context, THashSet collectedUids) { + this.parentType = parentType; + this.context = context; + this.collectedUids = collectedUids; + } + + @Override + public void collect(int doc) throws IOException { + collectedUids.add(typeCache.parentIdByDoc(doc)); + } + + @Override + public void setNextReader(IndexReader reader, int docBase) throws IOException { + typeCache = context.idCache().reader(reader).type(parentType); + } + } + } } diff --git a/src/main/java/org/elasticsearch/index/search/child/HasParentFilter.java b/src/main/java/org/elasticsearch/index/search/child/HasParentFilter.java index 7ea61fb67b0..9ef3d0ef553 100644 --- a/src/main/java/org/elasticsearch/index/search/child/HasParentFilter.java +++ b/src/main/java/org/elasticsearch/index/search/child/HasParentFilter.java @@ -29,7 +29,6 @@ import org.elasticsearch.common.bytes.HashedBytesArray; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.lucene.docset.GetDocSet; import org.elasticsearch.common.lucene.search.NoopCollector; -import org.elasticsearch.common.trove.ExtTHashMap; import org.elasticsearch.index.cache.id.IdReaderTypeCache; import org.elasticsearch.search.internal.ScopePhase; import org.elasticsearch.search.internal.SearchContext; @@ -44,13 +43,13 @@ import static com.google.common.collect.Maps.newHashMap; */ public abstract class HasParentFilter extends Filter implements ScopePhase.CollectorPhase { - final Query query; + final Query parentQuery; final String scope; final String parentType; final SearchContext context; - HasParentFilter(Query query, String scope, String parentType, SearchContext context) { - this.query = query; + HasParentFilter(Query parentQuery, String scope, String parentType, SearchContext context) { + this.parentQuery = parentQuery; this.scope = scope; this.parentType = parentType; this.context = context; @@ -61,24 +60,31 @@ public abstract class HasParentFilter extends Filter implements ScopePhase.Colle } public Query query() { - return query; + return parentQuery; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("parent_filter[").append(parentType).append("](").append(query()).append(')'); + return sb.toString(); } public static HasParentFilter create(String executionType, Query query, String scope, String parentType, SearchContext context) { // This mechanism is experimental and will most likely be removed. - if ("indirect".equals(executionType)) { - return new InDirect(query, scope, parentType, context); + if ("bitset".equals(executionType)) { + return new Bitset(query, scope, parentType, context); } else if ("uid".equals(executionType)) { - return new UidParentFilter(query, scope, parentType, context); + return new Uid(query, scope, parentType, context); } throw new ElasticSearchIllegalStateException("Illegal has_parent execution type: " + executionType); } - static class UidParentFilter extends HasParentFilter { + static class Uid extends HasParentFilter { THashSet parents; - UidParentFilter(Query query, String scope, String parentType, SearchContext context) { + Uid(Query query, String scope, String parentType, SearchContext context) { super(query, scope, parentType, context); } @@ -149,11 +155,11 @@ public abstract class HasParentFilter extends Filter implements ScopePhase.Colle } - static class InDirect extends HasParentFilter { + static class Bitset extends HasParentFilter { Map parentDocs; - InDirect(Query query, String scope, String parentType, SearchContext context) { + Bitset(Query query, String scope, String parentType, SearchContext context) { super(query, scope, parentType, context); } diff --git a/src/test/java/org/elasticsearch/benchmark/search/child/ChildSearchBenchmark.java b/src/test/java/org/elasticsearch/benchmark/search/child/ChildSearchBenchmark.java index 094e7ece33e..84e1a25f357 100644 --- a/src/test/java/org/elasticsearch/benchmark/search/child/ChildSearchBenchmark.java +++ b/src/test/java/org/elasticsearch/benchmark/search/child/ChildSearchBenchmark.java @@ -136,32 +136,61 @@ public class ChildSearchBenchmark { } System.out.println("--> Just Child Query Avg: " + (totalQueryTime / QUERY_COUNT) + "ms"); - System.out.println("--> Running has_child query"); - // run parent child constant query - for (int j = 0; j < QUERY_WARMUP; j++) { - SearchResponse searchResponse = client.prepareSearch().setQuery(hasChildQuery("child", termQuery("tag", "tag1"))).execute().actionGet(); - if (searchResponse.failedShards() > 0) { - System.err.println("Search Failures " + Arrays.toString(searchResponse.shardFailures())); + String[] executionTypes = new String[]{"uid", "bitset"};// either uid (faster, in general a bit more memory) or bitset (slower, but in general a bit less memory) + for (String executionType : executionTypes) { + System.out.println("--> Running has_child query with execution type " + executionType); + // run parent child constant query + for (int j = 0; j < QUERY_WARMUP; j++) { + SearchResponse searchResponse = client.prepareSearch() + .setQuery( + hasChildQuery("child", termQuery("tag", "tag1")).executionType(executionType) + ) + .execute().actionGet(); + if (searchResponse.failedShards() > 0) { + System.err.println("Search Failures " + Arrays.toString(searchResponse.shardFailures())); + } + if (searchResponse.hits().totalHits() != COUNT) { + System.err.println("--> mismatch on hits [" + j + "], got [" + searchResponse.hits().totalHits() + "], expected [" + COUNT + "]"); + } } - if (searchResponse.hits().totalHits() != COUNT) { - System.err.println("--> mismatch on hits [" + j + "], got [" + searchResponse.hits().totalHits() + "], expected [" + COUNT + "]"); + + totalQueryTime = 0; + for (int j = 0; j < QUERY_COUNT; j++) { + SearchResponse searchResponse = client.prepareSearch() + .setQuery( + hasChildQuery("child", termQuery("tag", "tag1")).executionType(executionType) + ) + .execute().actionGet(); + if (searchResponse.failedShards() > 0) { + System.err.println("Search Failures " + Arrays.toString(searchResponse.shardFailures())); + } + if (searchResponse.hits().totalHits() != COUNT) { + System.err.println("--> mismatch on hits [" + j + "], got [" + searchResponse.hits().totalHits() + "], expected [" + COUNT + "]"); + } + totalQueryTime += searchResponse.tookInMillis(); } + System.out.println("--> has_child[" + executionType + "] Query Avg: " + (totalQueryTime / QUERY_COUNT) + "ms"); + + System.out.println("--> Running has_child[" + executionType + "] filter with match_all child query"); + totalQueryTime = 0; + for (int j = 1; j <= QUERY_COUNT; j++) { + SearchResponse searchResponse = client.prepareSearch() + .setQuery( + hasChildQuery("child", matchAllQuery()).executionType(executionType) + ) + .execute().actionGet(); + if (searchResponse.failedShards() > 0) { + System.err.println("Search Failures " + Arrays.toString(searchResponse.shardFailures())); + } + long expected = (COUNT / BATCH) * BATCH; + if (searchResponse.hits().totalHits() != expected) { + System.err.println("--> mismatch on hits [" + j + "], got [" + searchResponse.hits().totalHits() + "], expected [" + expected + "]"); + } + totalQueryTime += searchResponse.tookInMillis(); + } + System.out.println("--> has_child[" + executionType + "] with match_all child query, Query Avg: " + (totalQueryTime / QUERY_COUNT) + "ms"); } - totalQueryTime = 0; - for (int j = 0; j < QUERY_COUNT; j++) { - SearchResponse searchResponse = client.prepareSearch().setQuery(hasChildQuery("child", termQuery("tag", "tag1"))).execute().actionGet(); - if (searchResponse.failedShards() > 0) { - System.err.println("Search Failures " + Arrays.toString(searchResponse.shardFailures())); - } - if (searchResponse.hits().totalHits() != COUNT) { - System.err.println("--> mismatch on hits [" + j + "], got [" + searchResponse.hits().totalHits() + "], expected [" + COUNT + "]"); - } - totalQueryTime += searchResponse.tookInMillis(); - } - System.out.println("--> has_child Query Avg: " + (totalQueryTime / QUERY_COUNT) + "ms"); - - String[] executionTypes = new String[]{"uid", "indirect"}; // either uid (faster, in general a bit more memory) or indirect (slower, but in general a bit less memory) for (String executionType : executionTypes) { System.out.println("--> Running has_parent filter with " + executionType + " execution type"); // run parent child constant query @@ -196,7 +225,7 @@ public class ChildSearchBenchmark { } System.out.println("--> has_parent[" + executionType + "] Query Avg: " + (totalQueryTime / QUERY_COUNT) + "ms"); - System.out.println("--> Running has_parent[" + executionType + "] filter with match_all query as parent query"); + System.out.println("--> Running has_parent[" + executionType + "] filter with match_all parent query "); totalQueryTime = 0; for (int j = 1; j <= QUERY_COUNT; j++) { SearchResponse searchResponse = client.prepareSearch() @@ -212,7 +241,7 @@ public class ChildSearchBenchmark { } totalQueryTime += searchResponse.tookInMillis(); } - System.out.println("--> has_parent[" + executionType + "] with match_all query as parent query Query Avg: " + (totalQueryTime / QUERY_COUNT) + "ms"); + System.out.println("--> has_parent[" + executionType + "] with match_all parent query, Query Avg: " + (totalQueryTime / QUERY_COUNT) + "ms"); } System.out.println("--> Running top_children query"); // run parent child score query diff --git a/src/test/java/org/elasticsearch/test/integration/search/child/BitsetExecutionChildQuerySearchTests.java b/src/test/java/org/elasticsearch/test/integration/search/child/BitsetExecutionChildQuerySearchTests.java new file mode 100644 index 00000000000..782da1dbf70 --- /dev/null +++ b/src/test/java/org/elasticsearch/test/integration/search/child/BitsetExecutionChildQuerySearchTests.java @@ -0,0 +1,32 @@ +/* + * Licensed to ElasticSearch and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. ElasticSearch 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.elasticsearch.test.integration.search.child; + +/** + * Runs super class tests, but with bitset execution type. + */ +public class BitsetExecutionChildQuerySearchTests extends SimpleChildQuerySearchTests { + + @Override + protected String getExecutionMethod() { + return "bitset"; + } + +} diff --git a/src/test/java/org/elasticsearch/test/integration/search/child/SimpleChildQuerySearchTests.java b/src/test/java/org/elasticsearch/test/integration/search/child/SimpleChildQuerySearchTests.java index 9f5384bc682..2a8728718d1 100644 --- a/src/test/java/org/elasticsearch/test/integration/search/child/SimpleChildQuerySearchTests.java +++ b/src/test/java/org/elasticsearch/test/integration/search/child/SimpleChildQuerySearchTests.java @@ -19,7 +19,6 @@ package org.elasticsearch.test.integration.search.child; -import com.beust.jcommander.internal.Maps; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.search.ShardSearchFailure; @@ -67,6 +66,10 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { return client("node1"); } + protected String getExecutionMethod() { + return "uid"; + } + @Test public void multiLevelChild() throws Exception { client.admin().indices().prepareDelete().execute().actionGet(); @@ -87,7 +90,15 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { client.admin().indices().prepareRefresh().execute().actionGet(); SearchResponse searchResponse = client.prepareSearch("test") - .setQuery(filteredQuery(matchAllQuery(), hasChildFilter("child", filteredQuery(termQuery("c_field", "c_value1"), hasChildFilter("grandchild", termQuery("gc_field", "gc_value1")))))) + .setQuery( + filteredQuery( + matchAllQuery(), + hasChildFilter( + "child", + filteredQuery(termQuery("c_field", "c_value1"), hasChildFilter("grandchild", termQuery("gc_field", "gc_value1")).executionType(getExecutionMethod())) + ).executionType(getExecutionMethod()) + ) + ) .execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); @@ -192,7 +203,7 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { // HAS CHILD QUERY - searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "yellow"))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "yellow")).executionType(getExecutionMethod())).execute().actionGet(); if (searchResponse.failedShards() > 0) { logger.warn("Failed shards:"); for (ShardSearchFailure shardSearchFailure : searchResponse.shardFailures()) { @@ -203,13 +214,13 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p1")); - searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "blue"))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "blue")).executionType(getExecutionMethod())).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p2")); - searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "red"))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "red")).executionType(getExecutionMethod())).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(2l)); @@ -218,13 +229,13 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { // HAS CHILD FILTER - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "yellow")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "yellow")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p1")); - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "blue")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "blue")).executionType(getExecutionMethod()))).execute().actionGet(); if (searchResponse.failedShards() > 0) { logger.warn("Failed shards:"); for (ShardSearchFailure shardSearchFailure : searchResponse.shardFailures()) { @@ -235,7 +246,7 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p2")); - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "red")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "red")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(2l)); @@ -243,14 +254,14 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { assertThat(searchResponse.hits().getAt(1).id(), anyOf(equalTo("p2"), equalTo("p1"))); // HAS PARENT FILTER - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasParentFilter("parent", termQuery("p_field", "p_value2")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasParentFilter("parent", termQuery("p_field", "p_value2")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(2l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("c3")); assertThat(searchResponse.hits().getAt(1).id(), equalTo("c4")); - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasParentFilter("parent", termQuery("p_field", "p_value1")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasParentFilter("parent", termQuery("p_field", "p_value1")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(2l)); @@ -299,7 +310,7 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { assertThat(parentToChildren.isEmpty(), equalTo(false)); for (Map.Entry> parentToChildrenEntry : parentToChildren.entrySet()) { SearchResponse searchResponse = client.prepareSearch("test") - .setQuery(constantScoreQuery(hasParentFilter("parent", termQuery("p_field", parentToChildrenEntry.getKey())))) + .setQuery(constantScoreQuery(hasParentFilter("parent", termQuery("p_field", parentToChildrenEntry.getKey())).executionType(getExecutionMethod()))) .setSize(numChildDocsPerParent) .execute().actionGet(); @@ -368,19 +379,19 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { // HAS CHILD QUERY - searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "yellow"))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "yellow")).executionType(getExecutionMethod())).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p1")); - searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "blue"))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "blue")).executionType(getExecutionMethod())).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p2")); - searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "red"))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "red")).executionType(getExecutionMethod())).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(2l)); @@ -389,19 +400,19 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { // HAS CHILD FILTER - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "yellow")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "yellow")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p1")); - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "blue")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "blue")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p2")); - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "red")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "red")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(2l)); @@ -463,19 +474,19 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { // HAS CHILD QUERY - searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "yellow"))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "yellow")).executionType(getExecutionMethod())).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p1")); - searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "blue"))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "blue")).executionType(getExecutionMethod())).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p2")); - searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "red"))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "red")).executionType(getExecutionMethod())).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(2l)); @@ -484,19 +495,19 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { // HAS CHILD FILTER - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "yellow")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "yellow")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p1")); - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "blue")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "blue")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); assertThat(searchResponse.hits().getAt(0).id(), equalTo("p2")); - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "red")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "red")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(2l)); @@ -577,7 +588,7 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { assertThat(searchResponse.hits().getAt(0).id(), equalTo("p1")); assertThat(searchResponse.hits().getAt(0).sourceAsString(), containsString("\"p_value1\"")); - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "yellow")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "yellow")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); @@ -596,7 +607,7 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { assertThat(searchResponse.hits().getAt(0).id(), equalTo("p1")); assertThat(searchResponse.hits().getAt(0).sourceAsString(), containsString("\"p_value1_updated\"")); - searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "yellow")))).execute().actionGet(); + searchResponse = client.prepareSearch("test").setQuery(constantScoreQuery(hasChildFilter("child", termQuery("c_field", "yellow")).executionType(getExecutionMethod()))).execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); assertThat(searchResponse.failedShards(), equalTo(0)); assertThat(searchResponse.hits().totalHits(), equalTo(1l)); @@ -625,7 +636,7 @@ public class SimpleChildQuerySearchTests extends AbstractNodesTests { client.admin().indices().prepareRefresh().execute().actionGet(); SearchResponse searchResponse = client.prepareSearch("test").setSearchType(SearchType.DFS_QUERY_THEN_FETCH) - .setQuery(boolQuery().mustNot(hasChildQuery("child", boolQuery().should(queryString("c_field:*"))))) + .setQuery(boolQuery().mustNot(hasChildQuery("child", boolQuery().should(queryString("c_field:*"))).executionType(getExecutionMethod()))) .execute().actionGet(); assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0)); }