Skip to content

Commit

Permalink
Parent/child: has_parent filter must take parent filter into account …
Browse files Browse the repository at this point in the history
…when executing the inner query/filter.

Closes #8020
Closes #7943
  • Loading branch information
martijnvg committed Oct 8, 2014
1 parent 9ce7ca2 commit 6b26c20
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 21 deletions.
Expand Up @@ -23,10 +23,6 @@
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;

Expand Down Expand Up @@ -63,7 +59,7 @@ public Filter parse(QueryParseContext parseContext) throws IOException, QueryPar
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) {
Expand All @@ -74,7 +70,7 @@ public Filter parse(QueryParseContext parseContext) throws IOException, QueryPar
// XContentStructure.<type> 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});
Expand Down Expand Up @@ -103,18 +99,18 @@ public Filter parse(QueryParseContext parseContext) throws IOException, QueryPar
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;
}
Expand Down
Expand Up @@ -122,14 +122,7 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars
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;
Expand All @@ -143,8 +136,13 @@ public Query parse(QueryParseContext parseContext) throws IOException, QueryPars
}

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<String> 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();
Expand Down Expand Up @@ -182,11 +180,13 @@ static Query createParentQuery(Query innerQuery, String parentType, boolean scor
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);
}
}

Expand Down
Expand Up @@ -2160,6 +2160,40 @@ public void testParentFieldInMultiMatchField() throws Exception {
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<IndexRequestBuilder> 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<IndexRequestBuilder> createMinMaxDocBuilders() {
List<IndexRequestBuilder> indexBuilders = new ArrayList<>();
// Parent 1 and its children
Expand Down

0 comments on commit 6b26c20

Please sign in to comment.