inner_hits: Properly support named queries for both nested and parent child inner hits.
Before inner_hits existed named queries has support to also verify if inner queries of nested query matched with returned documents. This logic was broken and became obsolete from the moment inner hits get released. #10694 fixed named queries for nested docs in the top_hits agg, but it didn't fix the named query support for nested inner hits. This commit fixes that and on top of this also adds support for parent/child inner hits.
This commit is contained in:
parent
8a44d938d4
commit
5f6623c03b
|
@ -151,7 +151,8 @@ public class HasChildQueryParser implements QueryParser {
|
|||
}
|
||||
|
||||
if (innerHits != null) {
|
||||
InnerHitsContext.ParentChildInnerHits parentChildInnerHits = new InnerHitsContext.ParentChildInnerHits(innerHits.v2(), innerQuery, null, parseContext.mapperService(), childDocMapper);
|
||||
ParsedQuery parsedQuery = new ParsedQuery(innerQuery, parseContext.copyNamedQueries());
|
||||
InnerHitsContext.ParentChildInnerHits parentChildInnerHits = new InnerHitsContext.ParentChildInnerHits(innerHits.v2(), parsedQuery, null, parseContext.mapperService(), childDocMapper);
|
||||
String name = innerHits.v1() != null ? innerHits.v1() : childType;
|
||||
parseContext.addInnerHits(name, parentChildInnerHits);
|
||||
}
|
||||
|
|
|
@ -154,7 +154,8 @@ public class HasParentQueryParser implements QueryParser {
|
|||
}
|
||||
|
||||
if (innerHits != null) {
|
||||
InnerHitsContext.ParentChildInnerHits parentChildInnerHits = new InnerHitsContext.ParentChildInnerHits(innerHits.v2(), innerQuery, null, parseContext.mapperService(), parentDocMapper);
|
||||
ParsedQuery parsedQuery = new ParsedQuery(innerQuery, parseContext.copyNamedQueries());
|
||||
InnerHitsContext.ParentChildInnerHits parentChildInnerHits = new InnerHitsContext.ParentChildInnerHits(innerHits.v2(), parsedQuery, null, parseContext.mapperService(), parentDocMapper);
|
||||
String name = innerHits.v1() != null ? innerHits.v1() : parentType;
|
||||
parseContext.addInnerHits(name, parentChildInnerHits);
|
||||
}
|
||||
|
|
|
@ -217,7 +217,7 @@ public class IndexQueryParserService extends AbstractIndexComponent {
|
|||
if (filter == null) {
|
||||
return null;
|
||||
}
|
||||
return new ParsedQuery(filter, context.copyNamedFilters());
|
||||
return new ParsedQuery(filter, context.copyNamedQueries());
|
||||
} finally {
|
||||
context.reset(null);
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ public class IndexQueryParserService extends AbstractIndexComponent {
|
|||
if (query == null) {
|
||||
query = Queries.newMatchNoDocsQuery();
|
||||
}
|
||||
return new ParsedQuery(query, parseContext.copyNamedFilters());
|
||||
return new ParsedQuery(query, parseContext.copyNamedQueries());
|
||||
} finally {
|
||||
parseContext.reset(null);
|
||||
}
|
||||
|
|
|
@ -151,7 +151,8 @@ public class NestedQueryParser implements QueryParser {
|
|||
}
|
||||
|
||||
if (innerHits != null) {
|
||||
InnerHitsContext.NestedInnerHits nestedInnerHits = new InnerHitsContext.NestedInnerHits(innerHits.v2(), innerQuery, null, getParentObjectMapper(), nestedObjectMapper);
|
||||
ParsedQuery parsedQuery = new ParsedQuery(innerQuery, parseContext.copyNamedQueries());
|
||||
InnerHitsContext.NestedInnerHits nestedInnerHits = new InnerHitsContext.NestedInnerHits(innerHits.v2(), parsedQuery, null, getParentObjectMapper(), nestedObjectMapper);
|
||||
String name = innerHits.v1() != null ? innerHits.v1() : path;
|
||||
parseContext.addInnerHits(name, nestedInnerHits);
|
||||
}
|
||||
|
|
|
@ -185,11 +185,11 @@ public class QueryParseContext {
|
|||
namedQueries.put(name, query);
|
||||
}
|
||||
|
||||
public ImmutableMap<String, Query> copyNamedFilters() {
|
||||
public ImmutableMap<String, Query> copyNamedQueries() {
|
||||
return ImmutableMap.copyOf(namedQueries);
|
||||
}
|
||||
|
||||
public void combineNamedFilters(QueryParseContext context) {
|
||||
public void combineNamedQueries(QueryParseContext context) {
|
||||
namedQueries.putAll(context.namedQueries);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public class WrapperQueryParser implements QueryParser {
|
|||
context.reset(qSourceParser);
|
||||
Query result = context.parseInnerQuery();
|
||||
parser.nextToken();
|
||||
parseContext.combineNamedFilters(context);
|
||||
parseContext.combineNamedQueries(context);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,34 +19,17 @@
|
|||
|
||||
package org.elasticsearch.search.fetch.innerhits;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import org.apache.lucene.index.LeafReader;
|
||||
import org.apache.lucene.index.LeafReaderContext;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.search.BooleanClause.Occur;
|
||||
import org.apache.lucene.search.BooleanQuery;
|
||||
import org.apache.lucene.search.ConstantScoreScorer;
|
||||
import org.apache.lucene.search.ConstantScoreWeight;
|
||||
import org.apache.lucene.search.DocIdSet;
|
||||
import org.apache.lucene.search.DocIdSetIterator;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.Scorer;
|
||||
import org.apache.lucene.search.TermQuery;
|
||||
import org.apache.lucene.search.TopDocs;
|
||||
import org.apache.lucene.search.TopDocsCollector;
|
||||
import org.apache.lucene.search.TopFieldCollector;
|
||||
import org.apache.lucene.search.TopScoreDocCollector;
|
||||
import org.apache.lucene.search.Weight;
|
||||
import org.apache.lucene.search.*;
|
||||
import org.apache.lucene.search.join.BitDocIdSetFilter;
|
||||
import org.apache.lucene.util.BitSet;
|
||||
import org.apache.lucene.util.Bits;
|
||||
import org.elasticsearch.ExceptionsHelper;
|
||||
import org.elasticsearch.common.lucene.Lucene;
|
||||
import org.elasticsearch.common.lucene.search.Queries;
|
||||
import org.elasticsearch.index.fieldvisitor.SingleFieldsVisitor;
|
||||
import org.elasticsearch.index.mapper.DocumentMapper;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.mapper.Uid;
|
||||
|
@ -83,10 +66,10 @@ public final class InnerHitsContext {
|
|||
|
||||
public static abstract class BaseInnerHits extends FilteredSearchContext {
|
||||
|
||||
protected final Query query;
|
||||
protected final ParsedQuery query;
|
||||
private final InnerHitsContext childInnerHits;
|
||||
|
||||
protected BaseInnerHits(SearchContext context, Query query, Map<String, BaseInnerHits> childInnerHits) {
|
||||
protected BaseInnerHits(SearchContext context, ParsedQuery query, Map<String, BaseInnerHits> childInnerHits) {
|
||||
super(context);
|
||||
this.query = query;
|
||||
if (childInnerHits != null && !childInnerHits.isEmpty()) {
|
||||
|
@ -98,12 +81,12 @@ public final class InnerHitsContext {
|
|||
|
||||
@Override
|
||||
public Query query() {
|
||||
return query;
|
||||
return query.query();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParsedQuery parsedQuery() {
|
||||
return new ParsedQuery(query, ImmutableMap.<String, Query>of());
|
||||
return query;
|
||||
}
|
||||
|
||||
public abstract TopDocs topDocs(SearchContext context, FetchSubPhase.HitContext hitContext) throws IOException;
|
||||
|
@ -120,7 +103,7 @@ public final class InnerHitsContext {
|
|||
private final ObjectMapper parentObjectMapper;
|
||||
private final ObjectMapper childObjectMapper;
|
||||
|
||||
public NestedInnerHits(SearchContext context, Query query, Map<String, BaseInnerHits> childInnerHits, ObjectMapper parentObjectMapper, ObjectMapper childObjectMapper) {
|
||||
public NestedInnerHits(SearchContext context, ParsedQuery query, Map<String, BaseInnerHits> childInnerHits, ObjectMapper parentObjectMapper, ObjectMapper childObjectMapper) {
|
||||
super(context, query, childInnerHits);
|
||||
this.parentObjectMapper = parentObjectMapper;
|
||||
this.childObjectMapper = childObjectMapper;
|
||||
|
@ -136,7 +119,7 @@ public final class InnerHitsContext {
|
|||
}
|
||||
BitDocIdSetFilter parentFilter = context.bitsetFilterCache().getBitDocIdSetFilter(rawParentFilter);
|
||||
Filter childFilter = childObjectMapper.nestedTypeFilter();
|
||||
Query q = Queries.filtered(query, new NestedChildrenQuery(parentFilter, childFilter, hitContext));
|
||||
Query q = Queries.filtered(query.query(), new NestedChildrenQuery(parentFilter, childFilter, hitContext));
|
||||
|
||||
if (size() == 0) {
|
||||
return new TopDocs(context.searcher().count(q), Lucene.EMPTY_SCORE_DOCS, 0);
|
||||
|
@ -280,7 +263,7 @@ public final class InnerHitsContext {
|
|||
private final MapperService mapperService;
|
||||
private final DocumentMapper documentMapper;
|
||||
|
||||
public ParentChildInnerHits(SearchContext context, Query query, Map<String, BaseInnerHits> childInnerHits, MapperService mapperService, DocumentMapper documentMapper) {
|
||||
public ParentChildInnerHits(SearchContext context, ParsedQuery query, Map<String, BaseInnerHits> childInnerHits, MapperService mapperService, DocumentMapper documentMapper) {
|
||||
super(context, query, childInnerHits);
|
||||
this.mapperService = mapperService;
|
||||
this.documentMapper = documentMapper;
|
||||
|
@ -307,7 +290,7 @@ public final class InnerHitsContext {
|
|||
}
|
||||
|
||||
BooleanQuery q = new BooleanQuery();
|
||||
q.add(query, Occur.MUST);
|
||||
q.add(query.query(), Occur.MUST);
|
||||
// Only include docs that have the current hit as parent
|
||||
q.add(new TermQuery(new Term(field, term)), Occur.MUST);
|
||||
// Only include docs that have this inner hits type
|
||||
|
|
|
@ -19,12 +19,11 @@
|
|||
|
||||
package org.elasticsearch.search.fetch.innerhits;
|
||||
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.mapper.DocumentMapper;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.mapper.object.ObjectMapper;
|
||||
import org.elasticsearch.index.query.ParsedQuery;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.search.SearchParseElement;
|
||||
import org.elasticsearch.search.fetch.fielddata.FieldDataFieldsParseElement;
|
||||
|
@ -169,7 +168,7 @@ public class InnerHitsParseElement implements SearchParseElement {
|
|||
}
|
||||
|
||||
private ParseResult parseSubSearchContext(SearchContext searchContext, QueryParseContext parseContext, XContentParser parser) throws Exception {
|
||||
Query query = null;
|
||||
ParsedQuery query = null;
|
||||
Map<String, InnerHitsContext.BaseInnerHits> childInnerHits = null;
|
||||
SubSearchContext subSearchContext = new SubSearchContext(searchContext);
|
||||
String fieldName = null;
|
||||
|
@ -179,7 +178,8 @@ public class InnerHitsParseElement implements SearchParseElement {
|
|||
fieldName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if ("query".equals(fieldName)) {
|
||||
query = searchContext.queryParserService().parseInnerQuery(parseContext);
|
||||
Query q = searchContext.queryParserService().parseInnerQuery(parseContext);
|
||||
query = new ParsedQuery(q, parseContext.copyNamedQueries());
|
||||
} else if ("inner_hits".equals(fieldName)) {
|
||||
childInnerHits = parseInnerHits(parser, parseContext, searchContext);
|
||||
} else {
|
||||
|
@ -191,7 +191,7 @@ public class InnerHitsParseElement implements SearchParseElement {
|
|||
}
|
||||
|
||||
if (query == null) {
|
||||
query = new MatchAllDocsQuery();
|
||||
query = ParsedQuery.parsedMatchAllQuery();
|
||||
}
|
||||
return new ParseResult(subSearchContext, query, childInnerHits);
|
||||
}
|
||||
|
@ -199,10 +199,10 @@ public class InnerHitsParseElement implements SearchParseElement {
|
|||
private static final class ParseResult {
|
||||
|
||||
private final SubSearchContext context;
|
||||
private final Query query;
|
||||
private final ParsedQuery query;
|
||||
private final Map<String, InnerHitsContext.BaseInnerHits> childInnerHits;
|
||||
|
||||
private ParseResult(SubSearchContext context, Query query, Map<String, InnerHitsContext.BaseInnerHits> childInnerHits) {
|
||||
private ParseResult(SubSearchContext context, ParsedQuery query, Map<String, InnerHitsContext.BaseInnerHits> childInnerHits) {
|
||||
this.context = context;
|
||||
this.query = query;
|
||||
this.childInnerHits = childInnerHits;
|
||||
|
@ -212,7 +212,7 @@ public class InnerHitsParseElement implements SearchParseElement {
|
|||
return context;
|
||||
}
|
||||
|
||||
public Query query() {
|
||||
public ParsedQuery query() {
|
||||
return query;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.query.support.QueryInnerHitBuilder;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.search.sort.SortBuilders;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
|
@ -46,25 +47,9 @@ import java.util.List;
|
|||
|
||||
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.filteredQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAllSuccessful;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
|
||||
import static org.hamcrest.Matchers.arrayContaining;
|
||||
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
||||
import static org.hamcrest.Matchers.arrayWithSize;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
public class SimpleNestedTests extends ElasticsearchIntegrationTest {
|
||||
|
||||
|
@ -178,98 +163,6 @@ public class SimpleNestedTests extends ElasticsearchIntegrationTest {
|
|||
assertThat(searchResponse.getHits().totalHits(), equalTo(1l));
|
||||
}
|
||||
|
||||
@Test @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/10661")
|
||||
public void simpleNestedMatchQueries() throws Exception {
|
||||
XContentBuilder builder = jsonBuilder().startObject()
|
||||
.startObject("type1")
|
||||
.startObject("properties")
|
||||
.startObject("nested1")
|
||||
.field("type", "nested")
|
||||
.endObject()
|
||||
.startObject("field1")
|
||||
.field("type", "long")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject();
|
||||
assertAcked(prepareCreate("test").addMapping("type1", builder));
|
||||
ensureGreen();
|
||||
|
||||
List<IndexRequestBuilder> requests = new ArrayList<>();
|
||||
int numDocs = randomIntBetween(2, 35);
|
||||
requests.add(client().prepareIndex("test", "type1", "0").setSource(jsonBuilder().startObject()
|
||||
.field("field1", 0)
|
||||
.startArray("nested1")
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_1")
|
||||
.field("n_field2", "n_value2_1")
|
||||
.endObject()
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_2")
|
||||
.field("n_field2", "n_value2_2")
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject()));
|
||||
requests.add(client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject()
|
||||
.field("field1", 1)
|
||||
.startArray("nested1")
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_8")
|
||||
.field("n_field2", "n_value2_5")
|
||||
.endObject()
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_3")
|
||||
.field("n_field2", "n_value2_1")
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject()));
|
||||
|
||||
for (int i = 2; i < numDocs; i++) {
|
||||
requests.add(client().prepareIndex("test", "type1", String.valueOf(i)).setSource(jsonBuilder().startObject()
|
||||
.field("field1", i)
|
||||
.startArray("nested1")
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_8")
|
||||
.field("n_field2", "n_value2_5")
|
||||
.endObject()
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_2")
|
||||
.field("n_field2", "n_value2_2")
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject()));
|
||||
}
|
||||
|
||||
indexRandom(true, requests);
|
||||
waitForRelocation(ClusterHealthStatus.GREEN);
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch("test")
|
||||
.setQuery(nestedQuery("nested1", boolQuery()
|
||||
.should(termQuery("nested1.n_field1", "n_value1_1").queryName("test1"))
|
||||
.should(termQuery("nested1.n_field1", "n_value1_3").queryName("test2"))
|
||||
.should(termQuery("nested1.n_field2", "n_value2_2").queryName("test3"))
|
||||
))
|
||||
.setSize(numDocs)
|
||||
.addSort("field1", SortOrder.ASC)
|
||||
.get();
|
||||
assertNoFailures(searchResponse);
|
||||
assertAllSuccessful(searchResponse);
|
||||
assertThat(searchResponse.getHits().totalHits(), equalTo((long) numDocs));
|
||||
assertThat(searchResponse.getHits().getAt(0).id(), equalTo("0"));
|
||||
assertThat(searchResponse.getHits().getAt(0).matchedQueries(), arrayWithSize(2));
|
||||
assertThat(searchResponse.getHits().getAt(0).matchedQueries(), arrayContainingInAnyOrder("test1", "test3"));
|
||||
|
||||
assertThat(searchResponse.getHits().getAt(1).id(), equalTo("1"));
|
||||
assertThat(searchResponse.getHits().getAt(1).matchedQueries(), arrayWithSize(1));
|
||||
assertThat(searchResponse.getHits().getAt(1).matchedQueries(), arrayContaining("test2"));
|
||||
|
||||
for (int i = 2; i < numDocs; i++) {
|
||||
assertThat(searchResponse.getHits().getAt(i).id(), equalTo(String.valueOf(i)));
|
||||
assertThat(searchResponse.getHits().getAt(i).matchedQueries(), arrayWithSize(1));
|
||||
assertThat(searchResponse.getHits().getAt(i).matchedQueries(), arrayContaining("test3"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiNested() throws Exception {
|
||||
assertAcked(prepareCreate("test")
|
||||
|
|
|
@ -881,7 +881,6 @@ public class TopHitsTests extends ElasticsearchIntegrationTest {
|
|||
long version = searchHit.version();
|
||||
assertThat(version, equalTo(1l));
|
||||
|
||||
// Can't use named queries for the same reason explain doesn't work:
|
||||
assertThat(searchHit.matchedQueries(), arrayContaining("test"));
|
||||
|
||||
SearchHitField field = searchHit.field("comments.user");
|
||||
|
|
|
@ -20,13 +20,13 @@
|
|||
package org.elasticsearch.search.innerhits;
|
||||
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
|
||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.query.support.QueryInnerHitBuilder;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
|
@ -42,21 +42,9 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHit;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
/**
|
||||
*/
|
||||
|
@ -1004,4 +992,139 @@ public class InnerHitsTests extends ElasticsearchIntegrationTest {
|
|||
assertThat(innerInnerHits.getAt(0).getId(), equalTo("king"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchesQueries_nestedInnerHits() throws Exception {
|
||||
XContentBuilder builder = jsonBuilder().startObject()
|
||||
.startObject("type1")
|
||||
.startObject("properties")
|
||||
.startObject("nested1")
|
||||
.field("type", "nested")
|
||||
.endObject()
|
||||
.startObject("field1")
|
||||
.field("type", "long")
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject()
|
||||
.endObject();
|
||||
assertAcked(prepareCreate("test").addMapping("type1", builder));
|
||||
ensureGreen();
|
||||
|
||||
List<IndexRequestBuilder> requests = new ArrayList<>();
|
||||
int numDocs = randomIntBetween(2, 35);
|
||||
requests.add(client().prepareIndex("test", "type1", "0").setSource(jsonBuilder().startObject()
|
||||
.field("field1", 0)
|
||||
.startArray("nested1")
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_1")
|
||||
.field("n_field2", "n_value2_1")
|
||||
.endObject()
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_2")
|
||||
.field("n_field2", "n_value2_2")
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject()));
|
||||
requests.add(client().prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject()
|
||||
.field("field1", 1)
|
||||
.startArray("nested1")
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_8")
|
||||
.field("n_field2", "n_value2_5")
|
||||
.endObject()
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_3")
|
||||
.field("n_field2", "n_value2_1")
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject()));
|
||||
|
||||
for (int i = 2; i < numDocs; i++) {
|
||||
requests.add(client().prepareIndex("test", "type1", String.valueOf(i)).setSource(jsonBuilder().startObject()
|
||||
.field("field1", i)
|
||||
.startArray("nested1")
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_8")
|
||||
.field("n_field2", "n_value2_5")
|
||||
.endObject()
|
||||
.startObject()
|
||||
.field("n_field1", "n_value1_2")
|
||||
.field("n_field2", "n_value2_2")
|
||||
.endObject()
|
||||
.endArray()
|
||||
.endObject()));
|
||||
}
|
||||
|
||||
indexRandom(true, requests);
|
||||
waitForRelocation(ClusterHealthStatus.GREEN);
|
||||
|
||||
SearchResponse searchResponse = client().prepareSearch("test")
|
||||
.setQuery(nestedQuery("nested1", boolQuery()
|
||||
.should(termQuery("nested1.n_field1", "n_value1_1").queryName("test1"))
|
||||
.should(termQuery("nested1.n_field1", "n_value1_3").queryName("test2"))
|
||||
.should(termQuery("nested1.n_field2", "n_value2_2").queryName("test3"))
|
||||
).innerHit(new QueryInnerHitBuilder()))
|
||||
.setSize(numDocs)
|
||||
.addSort("field1", SortOrder.ASC)
|
||||
.get();
|
||||
assertNoFailures(searchResponse);
|
||||
assertAllSuccessful(searchResponse);
|
||||
assertThat(searchResponse.getHits().totalHits(), equalTo((long) numDocs));
|
||||
assertThat(searchResponse.getHits().getAt(0).id(), equalTo("0"));
|
||||
assertThat(searchResponse.getHits().getAt(0).getInnerHits().get("nested1").getTotalHits(), equalTo(2l));
|
||||
assertThat(searchResponse.getHits().getAt(0).getInnerHits().get("nested1").getAt(0).getMatchedQueries().length, equalTo(1));
|
||||
assertThat(searchResponse.getHits().getAt(0).getInnerHits().get("nested1").getAt(0).getMatchedQueries()[0], equalTo("test1"));
|
||||
assertThat(searchResponse.getHits().getAt(0).getInnerHits().get("nested1").getAt(1).getMatchedQueries().length, equalTo(1));
|
||||
assertThat(searchResponse.getHits().getAt(0).getInnerHits().get("nested1").getAt(1).getMatchedQueries()[0], equalTo("test3"));
|
||||
|
||||
|
||||
assertThat(searchResponse.getHits().getAt(1).id(), equalTo("1"));
|
||||
assertThat(searchResponse.getHits().getAt(1).getInnerHits().get("nested1").getTotalHits(), equalTo(1l));
|
||||
assertThat(searchResponse.getHits().getAt(1).getInnerHits().get("nested1").getAt(0).getMatchedQueries().length, equalTo(1));
|
||||
assertThat(searchResponse.getHits().getAt(1).getInnerHits().get("nested1").getAt(0).getMatchedQueries()[0], equalTo("test2"));
|
||||
|
||||
for (int i = 2; i < numDocs; i++) {
|
||||
assertThat(searchResponse.getHits().getAt(i).id(), equalTo(String.valueOf(i)));
|
||||
assertThat(searchResponse.getHits().getAt(i).getInnerHits().get("nested1").getTotalHits(), equalTo(1l));
|
||||
assertThat(searchResponse.getHits().getAt(i).getInnerHits().get("nested1").getAt(0).getMatchedQueries().length, equalTo(1));
|
||||
assertThat(searchResponse.getHits().getAt(i).getInnerHits().get("nested1").getAt(0).getMatchedQueries()[0], equalTo("test3"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchesQueries_parentChildInnerHits() throws Exception {
|
||||
assertAcked(prepareCreate("index").addMapping("child", "_parent", "type=parent"));
|
||||
List<IndexRequestBuilder> requests = new ArrayList<>();
|
||||
requests.add(client().prepareIndex("index", "parent", "1").setSource("{}"));
|
||||
requests.add(client().prepareIndex("index", "child", "1").setParent("1").setSource("field", "value1"));
|
||||
requests.add(client().prepareIndex("index", "child", "2").setParent("1").setSource("field", "value2"));
|
||||
requests.add(client().prepareIndex("index", "parent", "2").setSource("{}"));
|
||||
requests.add(client().prepareIndex("index", "child", "3").setParent("2").setSource("field", "value1"));
|
||||
indexRandom(true, requests);
|
||||
|
||||
SearchResponse response = client().prepareSearch("index")
|
||||
.setQuery(hasChildQuery("child", matchQuery("field", "value1").queryName("_name1")).innerHit(new QueryInnerHitBuilder()))
|
||||
.addSort("_uid", SortOrder.ASC)
|
||||
.get();
|
||||
assertHitCount(response, 2);
|
||||
assertThat(response.getHits().getAt(0).id(), equalTo("1"));
|
||||
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getTotalHits(), equalTo(1l));
|
||||
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1));
|
||||
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name1"));
|
||||
|
||||
assertThat(response.getHits().getAt(1).id(), equalTo("2"));
|
||||
assertThat(response.getHits().getAt(1).getInnerHits().get("child").getTotalHits(), equalTo(1l));
|
||||
assertThat(response.getHits().getAt(1).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1));
|
||||
assertThat(response.getHits().getAt(1).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name1"));
|
||||
|
||||
response = client().prepareSearch("index")
|
||||
.setQuery(hasChildQuery("child", matchQuery("field", "value2").queryName("_name2")).innerHit(new QueryInnerHitBuilder()))
|
||||
.addSort("_id", SortOrder.ASC)
|
||||
.get();
|
||||
assertHitCount(response, 1);
|
||||
assertThat(response.getHits().getAt(0).id(), equalTo("1"));
|
||||
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getTotalHits(), equalTo(1l));
|
||||
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1));
|
||||
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name2"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue