From 6b26c2021a638b69a811f71a8cc3f75079c6ee91 Mon Sep 17 00:00:00 2001 From: Martijn van Groningen Date: Wed, 8 Oct 2014 13:58:23 +0200 Subject: [PATCH] Parent/child: has_parent filter must take parent filter into account when executing the inner query/filter. Closes #8020 Closes #7943 --- .../index/query/HasParentFilterParser.java | 18 ++++------ .../index/query/HasParentQueryParser.java | 20 +++++------ .../child/SimpleChildQuerySearchTests.java | 34 +++++++++++++++++++ 3 files changed, 51 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/elasticsearch/index/query/HasParentFilterParser.java b/src/main/java/org/elasticsearch/index/query/HasParentFilterParser.java index d3df85ee2ca..673ce801be2 100644 --- a/src/main/java/org/elasticsearch/index/query/HasParentFilterParser.java +++ b/src/main/java/org/elasticsearch/index/query/HasParentFilterParser.java @@ -23,10 +23,6 @@ import org.apache.lucene.search.Query; import org.elasticsearch.common.Strings; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.index.cache.fixedbitset.FixedBitSetFilter; -import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData; -import org.elasticsearch.index.mapper.DocumentMapper; -import org.elasticsearch.index.mapper.internal.ParentFieldMapper; import org.elasticsearch.index.query.support.XContentStructure; import org.elasticsearch.index.search.child.CustomQueryWrappingFilter; @@ -63,7 +59,7 @@ public class HasParentFilterParser implements FilterParser { String filterName = null; String currentFieldName = null; XContentParser.Token token; - XContentStructure.InnerQuery innerQuery = null; + XContentStructure.InnerQuery iq = null; XContentStructure.InnerFilter innerFilter = null; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { @@ -74,7 +70,7 @@ public class HasParentFilterParser implements FilterParser { // XContentStructure. facade to parse if available, // or delay parsing if not. if ("query".equals(currentFieldName)) { - innerQuery = new XContentStructure.InnerQuery(parseContext, parentType == null ? null : new String[] {parentType}); + iq = new XContentStructure.InnerQuery(parseContext, parentType == null ? null : new String[] {parentType}); queryFound = true; } else if ("filter".equals(currentFieldName)) { innerFilter = new XContentStructure.InnerFilter(parseContext, parentType == null ? null : new String[] {parentType}); @@ -103,18 +99,18 @@ public class HasParentFilterParser implements FilterParser { throw new QueryParsingException(parseContext.index(), "[has_parent] filter requires 'parent_type' field"); } - Query query; + Query innerQuery; if (queryFound) { - query = innerQuery.asQuery(parentType); + innerQuery = iq.asQuery(parentType); } else { - query = innerFilter.asFilter(parentType); + innerQuery = innerFilter.asFilter(parentType); } - if (query == null) { + if (innerQuery == null) { return null; } - Query parentQuery = createParentQuery(query, parentType, false, parseContext); + Query parentQuery = createParentQuery(innerQuery, parentType, false, parseContext); if (parentQuery == null) { return null; } diff --git a/src/main/java/org/elasticsearch/index/query/HasParentQueryParser.java b/src/main/java/org/elasticsearch/index/query/HasParentQueryParser.java index b375cdf508e..3ebca6270af 100644 --- a/src/main/java/org/elasticsearch/index/query/HasParentQueryParser.java +++ b/src/main/java/org/elasticsearch/index/query/HasParentQueryParser.java @@ -122,14 +122,7 @@ public class HasParentQueryParser implements QueryParser { return null; } - DocumentMapper parentDocMapper = parseContext.mapperService().documentMapper(parentType); - if (parentDocMapper == null) { - throw new QueryParsingException(parseContext.index(), "[has_parent] query configured 'parent_type' [" + parentType + "] is not a valid type"); - } - innerQuery.setBoost(boost); - // wrap the query with type query - innerQuery = new XFilteredQuery(innerQuery, parseContext.cacheFilter(parentDocMapper.typeFilter(), null)); Query query = createParentQuery(innerQuery, parentType, score, parseContext); if (query == null) { return null; @@ -143,8 +136,13 @@ public class HasParentQueryParser implements QueryParser { } static Query createParentQuery(Query innerQuery, String parentType, boolean score, QueryParseContext parseContext) { + DocumentMapper parentDocMapper = parseContext.mapperService().documentMapper(parentType); + if (parentDocMapper == null) { + throw new QueryParsingException(parseContext.index(), "[has_parent] query configured 'parent_type' [" + parentType + "] is not a valid type"); + } + Set parentTypes = new HashSet<>(5); - parentTypes.add(parentType); + parentTypes.add(parentDocMapper.type()); ParentChildIndexFieldData parentChildIndexFieldData = null; for (DocumentMapper documentMapper : parseContext.mapperService().docMappers(false)) { ParentFieldMapper parentFieldMapper = documentMapper.parentFieldMapper(); @@ -182,11 +180,13 @@ public class HasParentQueryParser implements QueryParser { return null; } + // wrap the query with type query + innerQuery = new XFilteredQuery(innerQuery, parseContext.cacheFilter(parentDocMapper.typeFilter(), null)); FixedBitSetFilter childrenFilter = parseContext.fixedBitSetFilter(new NotFilter(parentFilter)); if (score) { - return new ParentQuery(parentChildIndexFieldData, innerQuery, parentType, childrenFilter); + return new ParentQuery(parentChildIndexFieldData, innerQuery, parentDocMapper.type(), childrenFilter); } else { - return new ParentConstantScoreQuery(parentChildIndexFieldData, innerQuery, parentType, childrenFilter); + return new ParentConstantScoreQuery(parentChildIndexFieldData, innerQuery, parentDocMapper.type(), childrenFilter); } } diff --git a/src/test/java/org/elasticsearch/search/child/SimpleChildQuerySearchTests.java b/src/test/java/org/elasticsearch/search/child/SimpleChildQuerySearchTests.java index a3e0ef28e1c..876635ba5f0 100644 --- a/src/test/java/org/elasticsearch/search/child/SimpleChildQuerySearchTests.java +++ b/src/test/java/org/elasticsearch/search/child/SimpleChildQuerySearchTests.java @@ -2160,6 +2160,40 @@ public class SimpleChildQuerySearchTests extends ElasticsearchIntegrationTest { assertThat(response.getHits().getAt(0).id(), equalTo("1")); } + @Test + public void testTypeIsAppliedInHasParentInnerQuery() throws Exception { + assertAcked(prepareCreate("test") + .addMapping("parent") + .addMapping("child", "_parent", "type=parent")); + ensureGreen(); + + List indexRequests = new ArrayList<>(); + indexRequests.add(client().prepareIndex("test", "parent", "1").setSource("field1", "a")); + indexRequests.add(client().prepareIndex("test", "child", "1").setParent("1").setSource("{}")); + indexRequests.add(client().prepareIndex("test", "child", "2").setParent("1").setSource("{}")); + indexRandom(true, indexRequests); + + SearchResponse searchResponse = client().prepareSearch("test") + .setQuery(constantScoreQuery(hasParentFilter("parent", notFilter(termFilter("field1", "a"))))) + .get(); + assertHitCount(searchResponse, 0l); + + searchResponse = client().prepareSearch("test") + .setQuery(hasParentQuery("parent", constantScoreQuery(notFilter(termFilter("field1", "a"))))) + .get(); + assertHitCount(searchResponse, 0l); + + searchResponse = client().prepareSearch("test") + .setQuery(constantScoreQuery(hasParentFilter("parent", termFilter("field1", "a")))) + .get(); + assertHitCount(searchResponse, 2l); + + searchResponse = client().prepareSearch("test") + .setQuery(hasParentQuery("parent", constantScoreQuery(termFilter("field1", "a")))) + .get(); + assertHitCount(searchResponse, 2l); + } + List createMinMaxDocBuilders() { List indexBuilders = new ArrayList<>(); // Parent 1 and its children