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.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
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.query.support.XContentStructure;
|
||||||
import org.elasticsearch.index.search.child.CustomQueryWrappingFilter;
|
import org.elasticsearch.index.search.child.CustomQueryWrappingFilter;
|
||||||
|
|
||||||
|
@ -63,7 +59,7 @@ public class HasParentFilterParser implements FilterParser {
|
||||||
String filterName = null;
|
String filterName = null;
|
||||||
String currentFieldName = null;
|
String currentFieldName = null;
|
||||||
XContentParser.Token token;
|
XContentParser.Token token;
|
||||||
XContentStructure.InnerQuery innerQuery = null;
|
XContentStructure.InnerQuery iq = null;
|
||||||
XContentStructure.InnerFilter innerFilter = null;
|
XContentStructure.InnerFilter innerFilter = null;
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
|
@ -74,7 +70,7 @@ public class HasParentFilterParser implements FilterParser {
|
||||||
// XContentStructure.<type> facade to parse if available,
|
// XContentStructure.<type> facade to parse if available,
|
||||||
// or delay parsing if not.
|
// or delay parsing if not.
|
||||||
if ("query".equals(currentFieldName)) {
|
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;
|
queryFound = true;
|
||||||
} else if ("filter".equals(currentFieldName)) {
|
} else if ("filter".equals(currentFieldName)) {
|
||||||
innerFilter = new XContentStructure.InnerFilter(parseContext, parentType == null ? null : new String[] {parentType});
|
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");
|
throw new QueryParsingException(parseContext.index(), "[has_parent] filter requires 'parent_type' field");
|
||||||
}
|
}
|
||||||
|
|
||||||
Query query;
|
Query innerQuery;
|
||||||
if (queryFound) {
|
if (queryFound) {
|
||||||
query = innerQuery.asQuery(parentType);
|
innerQuery = iq.asQuery(parentType);
|
||||||
} else {
|
} else {
|
||||||
query = innerFilter.asFilter(parentType);
|
innerQuery = innerFilter.asFilter(parentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query == null) {
|
if (innerQuery == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Query parentQuery = createParentQuery(query, parentType, false, parseContext);
|
Query parentQuery = createParentQuery(innerQuery, parentType, false, parseContext);
|
||||||
if (parentQuery == null) {
|
if (parentQuery == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,14 +122,7 @@ public class HasParentQueryParser implements QueryParser {
|
||||||
return null;
|
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);
|
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);
|
Query query = createParentQuery(innerQuery, parentType, score, parseContext);
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -143,8 +136,13 @@ public class HasParentQueryParser implements QueryParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Query createParentQuery(Query innerQuery, String parentType, boolean score, QueryParseContext parseContext) {
|
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);
|
Set<String> parentTypes = new HashSet<>(5);
|
||||||
parentTypes.add(parentType);
|
parentTypes.add(parentDocMapper.type());
|
||||||
ParentChildIndexFieldData parentChildIndexFieldData = null;
|
ParentChildIndexFieldData parentChildIndexFieldData = null;
|
||||||
for (DocumentMapper documentMapper : parseContext.mapperService().docMappers(false)) {
|
for (DocumentMapper documentMapper : parseContext.mapperService().docMappers(false)) {
|
||||||
ParentFieldMapper parentFieldMapper = documentMapper.parentFieldMapper();
|
ParentFieldMapper parentFieldMapper = documentMapper.parentFieldMapper();
|
||||||
|
@ -182,11 +180,13 @@ public class HasParentQueryParser implements QueryParser {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrap the query with type query
|
||||||
|
innerQuery = new XFilteredQuery(innerQuery, parseContext.cacheFilter(parentDocMapper.typeFilter(), null));
|
||||||
FixedBitSetFilter childrenFilter = parseContext.fixedBitSetFilter(new NotFilter(parentFilter));
|
FixedBitSetFilter childrenFilter = parseContext.fixedBitSetFilter(new NotFilter(parentFilter));
|
||||||
if (score) {
|
if (score) {
|
||||||
return new ParentQuery(parentChildIndexFieldData, innerQuery, parentType, childrenFilter);
|
return new ParentQuery(parentChildIndexFieldData, innerQuery, parentDocMapper.type(), childrenFilter);
|
||||||
} else {
|
} 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"));
|
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> createMinMaxDocBuilders() {
|
||||||
List<IndexRequestBuilder> indexBuilders = new ArrayList<>();
|
List<IndexRequestBuilder> indexBuilders = new ArrayList<>();
|
||||||
// Parent 1 and its children
|
// Parent 1 and its children
|
||||||
|
|
Loading…
Reference in New Issue