Parent/child: has_parent filter must take parent filter into account when executing the inner query/filter.
Closes #8020 Closes #7943
This commit is contained in:
parent
9ce7ca21e4
commit
6b26c2021a
|
@ -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.<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});
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<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
|
||||
|
|
Loading…
Reference in New Issue