From 9de267abb40410b9d14057a12a03649c8555ecec Mon Sep 17 00:00:00 2001 From: Mayya Sharipova Date: Wed, 4 Jul 2018 15:58:02 -0400 Subject: [PATCH 1/2] Add second level of field collapsing Closes #24855 --- .../search/request/collapse.asciidoc | 102 +++++++++++++ .../search/115_multiple_field_collapsing.yml | 141 ++++++++++++++++++ .../action/search/ExpandSearchPhase.java | 8 +- .../search/collapse/CollapseBuilder.java | 38 ++++- 4 files changed, 284 insertions(+), 5 deletions(-) create mode 100644 rest-api-spec/src/main/resources/rest-api-spec/test/search/115_multiple_field_collapsing.yml diff --git a/docs/reference/search/request/collapse.asciidoc b/docs/reference/search/request/collapse.asciidoc index 97d8532933027..23f9e0ff32989 100644 --- a/docs/reference/search/request/collapse.asciidoc +++ b/docs/reference/search/request/collapse.asciidoc @@ -116,3 +116,105 @@ The default is based on the number of data nodes and the default search thread p WARNING: `collapse` cannot be used in conjunction with <>, <> or <>. + +==== Second level of collapsing + +Second level of collapsing is also supported and is applied to `inner_hits`. +For example, the following request finds the top scored tweets for +each country, and within each country finds the top scored tweets +for each user. + +[source,js] +-------------------------------------------------- +GET /twitter/_search +{ + "query": { + "match": { + "message": "elasticsearch" + } + }, + "collapse" : { + "field" : "country", + "inner_hits" : { + "name": "by_location", + "size": 3 + }, + "collapse" : {"field" : "user"} + } +} +-------------------------------------------------- +// NOTCONSOLE + + +Response: +[source,js] +-------------------------------------------------- +{ + ... + "hits": [ + { + "_index": "twitter", + "_type": "_doc", + "_id": "9", + "_score": ..., + "_source": {...}, + "fields": {"country": ["UK"]}, + "inner_hits":{ + "by_location": { + "hits": { + ..., + "hits": [ + { + ... + "fields": {"user" : ["user124"]} + }, + { + ... + "fields": {"user" : ["user589"]} + }, + { + ... + "fields": {"user" : ["user001"]} + } + ] + } + } + } + }, + { + "_index": "twitter", + "_type": "_doc", + "_id": "1", + "_score": .., + "_source": {...}, + "fields": {"country": ["Canada"]}, + "inner_hits":{ + "by_location": { + "hits": { + ..., + "hits": [ + { + ... + "fields": {"user" : ["user444"]} + }, + { + ... + "fields": {"user" : ["user1111"]} + }, + { + ... + "fields": {"user" : ["user999"]} + } + ] + } + } + } + + }, + .... + ] +} +-------------------------------------------------- +// NOTCONSOLE + +NOTE: Second level of of collapsing doesn't allow `inner_hits`. \ No newline at end of file diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search/115_multiple_field_collapsing.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/search/115_multiple_field_collapsing.yml new file mode 100644 index 0000000000000..252d97ebb3da8 --- /dev/null +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search/115_multiple_field_collapsing.yml @@ -0,0 +1,141 @@ +--- +"two levels fields collapsing": + - skip: + version: " - 6.99.99" + reason: using multiple field collapsing from 7.0 on + - do: + indices.create: + index: addresses + body: + settings: + number_of_shards: 1 + number_of_replicas: 1 + mappings: + _doc: + properties: + country: {"type": "keyword"} + city: {"type": "keyword"} + address: {"type": "text"} + + - do: + bulk: + refresh: true + body: + - '{ "index" : { "_index" : "addresses", "_type" : "_doc", "_id" : "1" } }' + - '{"country" : "Canada", "city" : "Saskatoon", "address" : "701 Victoria Avenue" }' + - '{ "index" : { "_index" : "addresses", "_type" : "_doc", "_id" : "2" } }' + - '{"country" : "Canada", "city" : "Toronto", "address" : "74 Victoria Street, Suite, 74 Victoria Street, Suite 300" }' + - '{ "index" : { "_index" : "addresses", "_type" : "_doc", "_id" : "3" } }' + - '{"country" : "Canada", "city" : "Toronto", "address" : "350 Victoria St" }' + - '{ "index" : { "_index" : "addresses", "_type" : "_doc", "_id" : "4" } }' + - '{"country" : "Canada", "city" : "Toronto", "address" : "20 Victoria Street" }' + - '{ "index" : { "_index" : "addresses", "_type" : "_doc", "_id" : "5" } }' + - '{"country" : "UK", "city" : "London", "address" : "58 Victoria Street" }' + - '{ "index" : { "_index" : "addresses", "_type" : "_doc", "_id" : "6" } }' + - '{"country" : "UK", "city" : "London", "address" : "Victoria Street Victoria Palace Theatre" }' + - '{ "index" : { "_index" : "addresses", "_type" : "_doc", "_id" : "7" } }' + - '{"country" : "UK", "city" : "Manchester", "address" : "75 Victoria street Westminster" }' + - '{ "index" : { "_index" : "addresses", "_type" : "_doc", "_id" : "8" } }' + - '{"country" : "UK", "city" : "London", "address" : "Victoria Station Victoria Arcade" }' + + + # ************* error if internal collapse contains inner_hits + - do: + catch: /parse_exception/ + search: + index: addresses + body: + query: { "match" : { "address" : "victoria" }} + collapse: + field: country + inner_hits: {} + collapse: + field : city + inner_hits: {} + + + # ************* error if internal collapse contains another collapse + - do: + catch: /parse_exception/ + search: + index: addresses + body: + query: { "match" : { "address" : "victoria" }} + collapse: + field: country + inner_hits: {} + collapse: + field : city + collapse: { field: city } + + + + # ************* top scored + - do: + search: + index: addresses + body: + query: { "match" : { "address" : "victoria" }} + collapse: + field: country + inner_hits: + name: by_location + size: 3 + collapse: + field : city + + - match: { hits.total: 8 } + - length: { hits.hits: 2 } + - match: { hits.hits.0.fields.country: ["UK"] } + - match: { hits.hits.0.inner_hits.by_location.hits.total: 4 } + # 2 inner hits returned instead of requested 3 as they are collapsed by city + - length: { hits.hits.0.inner_hits.by_location.hits.hits : 2} + - match: { hits.hits.0.inner_hits.by_location.hits.hits.0._id: "8" } + - match: { hits.hits.0.inner_hits.by_location.hits.hits.0.fields.city: ["London"] } + - match: { hits.hits.0.inner_hits.by_location.hits.hits.1._id: "7" } + - match: { hits.hits.0.inner_hits.by_location.hits.hits.1.fields.city: ["Manchester"] } + + - match: { hits.hits.1.fields.country: ["Canada"] } + - match: { hits.hits.1.inner_hits.by_location.hits.total: 4 } + # 2 inner hits returned instead of requested 3 as they are collapsed by city + - length: { hits.hits.1.inner_hits.by_location.hits.hits : 2 } + - match: { hits.hits.1.inner_hits.by_location.hits.hits.0._id: "1" } + - match: { hits.hits.1.inner_hits.by_location.hits.hits.0.fields.city: ["Saskatoon"] } + - match: { hits.hits.1.inner_hits.by_location.hits.hits.1._id: "3" } + - match: { hits.hits.1.inner_hits.by_location.hits.hits.1.fields.city: ["Toronto"] } + + + # ************* sorted + - do: + search: + index: addresses + body: + query: { "match" : { "address" : "victoria" }} + collapse: + field: country + inner_hits: + name: by_location + size: 3 + sort: [{ "city": "desc" }] + collapse: + field : city + + - match: { hits.total: 8 } + - length: { hits.hits: 2 } + - match: { hits.hits.0.fields.country: ["UK"] } + - match: { hits.hits.0.inner_hits.by_location.hits.total: 4 } + # 2 inner hits returned instead of requested 3 as they are collapsed by city + - length: { hits.hits.0.inner_hits.by_location.hits.hits : 2} + - match: { hits.hits.0.inner_hits.by_location.hits.hits.0._id: "7" } + - match: { hits.hits.0.inner_hits.by_location.hits.hits.0.fields.city: ["Manchester"] } + - match: { hits.hits.0.inner_hits.by_location.hits.hits.1._id: "5" } + - match: { hits.hits.0.inner_hits.by_location.hits.hits.1.fields.city: ["London"] } + + - match: { hits.hits.1.fields.country: ["Canada"] } + - match: { hits.hits.1.inner_hits.by_location.hits.total: 4 } + # 2 inner hits returned instead of requested 3 as they are collapsed by city + - length: { hits.hits.1.inner_hits.by_location.hits.hits : 2 } + - match: { hits.hits.1.inner_hits.by_location.hits.hits.0._id: "2" } + - match: { hits.hits.1.inner_hits.by_location.hits.hits.0.fields.city: ["Toronto"] } + - match: { hits.hits.1.inner_hits.by_location.hits.hits.1._id: "1" } + - match: { hits.hits.1.inner_hits.by_location.hits.hits.1.fields.city: ["Saskatoon"] } diff --git a/server/src/main/java/org/elasticsearch/action/search/ExpandSearchPhase.java b/server/src/main/java/org/elasticsearch/action/search/ExpandSearchPhase.java index a6a99137dc945..7e95d9c3ab1da 100644 --- a/server/src/main/java/org/elasticsearch/action/search/ExpandSearchPhase.java +++ b/server/src/main/java/org/elasticsearch/action/search/ExpandSearchPhase.java @@ -69,6 +69,7 @@ public void run() throws IOException { if (isCollapseRequest() && searchResponse.hits().getHits().length > 0) { SearchRequest searchRequest = context.getRequest(); CollapseBuilder collapseBuilder = searchRequest.source().collapse(); + CollapseBuilder innerCollapseBuilder = collapseBuilder.getInnerCollapseBuilder(); final List innerHitBuilders = collapseBuilder.getInnerHits(); MultiSearchRequest multiRequest = new MultiSearchRequest(); if (collapseBuilder.getMaxConcurrentGroupRequests() > 0) { @@ -87,7 +88,7 @@ public void run() throws IOException { groupQuery.must(origQuery); } for (InnerHitBuilder innerHitBuilder : innerHitBuilders) { - SearchSourceBuilder sourceBuilder = buildExpandSearchSourceBuilder(innerHitBuilder) + SearchSourceBuilder sourceBuilder = buildExpandSearchSourceBuilder(innerHitBuilder, innerCollapseBuilder) .query(groupQuery) .postFilter(searchRequest.source().postFilter()); SearchRequest groupRequest = buildExpandSearchRequest(searchRequest, sourceBuilder); @@ -135,7 +136,7 @@ private SearchRequest buildExpandSearchRequest(SearchRequest orig, SearchSourceB return groupRequest; } - private SearchSourceBuilder buildExpandSearchSourceBuilder(InnerHitBuilder options) { + private SearchSourceBuilder buildExpandSearchSourceBuilder(InnerHitBuilder options, CollapseBuilder innerCollapseBuilder) { SearchSourceBuilder groupSource = new SearchSourceBuilder(); groupSource.from(options.getFrom()); groupSource.size(options.getSize()); @@ -167,6 +168,9 @@ private SearchSourceBuilder buildExpandSearchSourceBuilder(InnerHitBuilder optio groupSource.explain(options.isExplain()); groupSource.trackScores(options.isTrackScores()); groupSource.version(options.isVersion()); + if (innerCollapseBuilder != null) { + groupSource.collapse(innerCollapseBuilder); + } return groupSource; } } diff --git a/server/src/main/java/org/elasticsearch/search/collapse/CollapseBuilder.java b/server/src/main/java/org/elasticsearch/search/collapse/CollapseBuilder.java index 90e35c34e28f8..e303b0e044337 100644 --- a/server/src/main/java/org/elasticsearch/search/collapse/CollapseBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/collapse/CollapseBuilder.java @@ -51,8 +51,11 @@ public class CollapseBuilder implements Writeable, ToXContentObject { public static final ParseField FIELD_FIELD = new ParseField("field"); public static final ParseField INNER_HITS_FIELD = new ParseField("inner_hits"); public static final ParseField MAX_CONCURRENT_GROUP_REQUESTS_FIELD = new ParseField("max_concurrent_group_searches"); + public static final ParseField COLLAPSE_FIELD = new ParseField("collapse"); private static final ObjectParser PARSER = new ObjectParser<>("collapse", CollapseBuilder::new); + private static final ObjectParser INNER_COLLAPSE_PARSER = + new ObjectParser<>("inner collapse", CollapseBuilder::new); static { PARSER.declareString(CollapseBuilder::setField, FIELD_FIELD); @@ -70,15 +73,25 @@ public class CollapseBuilder implements Writeable, ToXContentObject { throw new ParsingException(parser.getTokenLocation(), "Invalid token in inner_hits array"); } } - builder.setInnerHits(innerHitBuilders); } }, INNER_HITS_FIELD, ObjectParser.ValueType.OBJECT_ARRAY); + + INNER_COLLAPSE_PARSER.declareString(CollapseBuilder::setField, FIELD_FIELD); + PARSER.declareField((parser, builder, context) -> { + XContentParser.Token currentToken = parser.currentToken(); + if (currentToken == XContentParser.Token.START_OBJECT) { + builder.setInnerCollapse(INNER_COLLAPSE_PARSER.apply(parser, null)); + } else { + throw new ParsingException(parser.getTokenLocation(), "Invalid token in the inner collapse"); + } + }, COLLAPSE_FIELD, ObjectParser.ValueType.OBJECT); } private String field; private List innerHits = Collections.emptyList(); private int maxConcurrentGroupRequests = 0; + private CollapseBuilder innerCollapseBuilder = null; private CollapseBuilder() {} @@ -104,6 +117,9 @@ public CollapseBuilder(StreamInput in) throws IOException { this.innerHits = Collections.emptyList(); } } + if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + this.innerCollapseBuilder = in.readOptionalWriteable(CollapseBuilder::new); + } } @Override @@ -119,6 +135,9 @@ public void writeTo(StreamOutput out) throws IOException { innerHits.get(0).writeToCollapseBWC(out); } } + if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + out.writeOptionalWriteable(innerCollapseBuilder); + } } public static CollapseBuilder fromXContent(XContentParser parser) { @@ -144,6 +163,11 @@ public CollapseBuilder setInnerHits(List innerHits) { return this; } + public CollapseBuilder setInnerCollapse(CollapseBuilder innerCollapseBuilder) { + this.innerCollapseBuilder = innerCollapseBuilder; + return this; + } + public CollapseBuilder setMaxConcurrentGroupRequests(int num) { if (num < 1) { throw new IllegalArgumentException("maxConcurrentGroupRequests` must be positive"); @@ -166,6 +190,10 @@ public List getInnerHits() { return this.innerHits; } + public CollapseBuilder getInnerCollapseBuilder() { + return innerCollapseBuilder; + } + /** * Returns the amount of group requests that are allowed to be ran concurrently in the inner_hits phase. */ @@ -197,6 +225,9 @@ private void innerToXContent(XContentBuilder builder) throws IOException { builder.endArray(); } } + if (innerCollapseBuilder != null) { + builder.field(COLLAPSE_FIELD.getPreferredName(), innerCollapseBuilder); + } } @Override @@ -208,12 +239,13 @@ public boolean equals(Object o) { if (maxConcurrentGroupRequests != that.maxConcurrentGroupRequests) return false; if (!field.equals(that.field)) return false; - return Objects.equals(innerHits, that.innerHits); + if (Objects.equals(innerHits, that.innerHits) == false) return false; + return Objects.equals(innerCollapseBuilder, that.innerCollapseBuilder); } @Override public int hashCode() { - int result = Objects.hash(field, innerHits); + int result = Objects.hash(field, innerHits, innerCollapseBuilder); result = 31 * result + maxConcurrentGroupRequests; return result; } From b3c9b6be08bae0b989b1232ab66bd9d5319fc36f Mon Sep 17 00:00:00 2001 From: Mayya Sharipova Date: Fri, 6 Jul 2018 09:23:37 -0400 Subject: [PATCH 2/2] Put second level collapse under inner_hits --- .../search/request/collapse.asciidoc | 4 +- .../search/115_multiple_field_collapsing.yml | 24 ++++----- .../action/search/ExpandSearchPhase.java | 2 +- .../index/query/InnerHitBuilder.java | 49 ++++++++++++++++++- .../search/collapse/CollapseBuilder.java | 38 ++------------ 5 files changed, 65 insertions(+), 52 deletions(-) diff --git a/docs/reference/search/request/collapse.asciidoc b/docs/reference/search/request/collapse.asciidoc index 23f9e0ff32989..192495e5d6d0d 100644 --- a/docs/reference/search/request/collapse.asciidoc +++ b/docs/reference/search/request/collapse.asciidoc @@ -137,9 +137,9 @@ GET /twitter/_search "field" : "country", "inner_hits" : { "name": "by_location", + "collapse" : {"field" : "user"}, "size": 3 - }, - "collapse" : {"field" : "user"} + } } } -------------------------------------------------- diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search/115_multiple_field_collapsing.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/search/115_multiple_field_collapsing.yml index 252d97ebb3da8..212ce6785a1ba 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search/115_multiple_field_collapsing.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search/115_multiple_field_collapsing.yml @@ -48,10 +48,10 @@ query: { "match" : { "address" : "victoria" }} collapse: field: country - inner_hits: {} - collapse: - field : city - inner_hits: {} + inner_hits: + collapse: + field : city + inner_hits: {} # ************* error if internal collapse contains another collapse @@ -63,10 +63,10 @@ query: { "match" : { "address" : "victoria" }} collapse: field: country - inner_hits: {} - collapse: - field : city - collapse: { field: city } + inner_hits: + collapse: + field : city + collapse: { field: city } @@ -81,8 +81,8 @@ inner_hits: name: by_location size: 3 - collapse: - field : city + collapse: + field : city - match: { hits.total: 8 } - length: { hits.hits: 2 } @@ -117,8 +117,8 @@ name: by_location size: 3 sort: [{ "city": "desc" }] - collapse: - field : city + collapse: + field : city - match: { hits.total: 8 } - length: { hits.hits: 2 } diff --git a/server/src/main/java/org/elasticsearch/action/search/ExpandSearchPhase.java b/server/src/main/java/org/elasticsearch/action/search/ExpandSearchPhase.java index 7e95d9c3ab1da..917ff06c5737c 100644 --- a/server/src/main/java/org/elasticsearch/action/search/ExpandSearchPhase.java +++ b/server/src/main/java/org/elasticsearch/action/search/ExpandSearchPhase.java @@ -69,7 +69,6 @@ public void run() throws IOException { if (isCollapseRequest() && searchResponse.hits().getHits().length > 0) { SearchRequest searchRequest = context.getRequest(); CollapseBuilder collapseBuilder = searchRequest.source().collapse(); - CollapseBuilder innerCollapseBuilder = collapseBuilder.getInnerCollapseBuilder(); final List innerHitBuilders = collapseBuilder.getInnerHits(); MultiSearchRequest multiRequest = new MultiSearchRequest(); if (collapseBuilder.getMaxConcurrentGroupRequests() > 0) { @@ -88,6 +87,7 @@ public void run() throws IOException { groupQuery.must(origQuery); } for (InnerHitBuilder innerHitBuilder : innerHitBuilders) { + CollapseBuilder innerCollapseBuilder = innerHitBuilder.getInnerCollapseBuilder(); SearchSourceBuilder sourceBuilder = buildExpandSearchSourceBuilder(innerHitBuilder, innerCollapseBuilder) .query(groupQuery) .postFilter(searchRequest.source().postFilter()); diff --git a/server/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java b/server/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java index 92da1bc3b65f9..6bdc55d31cdc9 100644 --- a/server/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java @@ -37,6 +37,7 @@ import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.sort.SortBuilder; +import org.elasticsearch.search.collapse.CollapseBuilder; import java.io.IOException; import java.util.ArrayList; @@ -55,6 +56,8 @@ public final class InnerHitBuilder implements Writeable, ToXContentObject { public static final ParseField NAME_FIELD = new ParseField("name"); public static final ParseField IGNORE_UNMAPPED = new ParseField("ignore_unmapped"); public static final QueryBuilder DEFAULT_INNER_HIT_QUERY = new MatchAllQueryBuilder(); + public static final ParseField COLLAPSE_FIELD = new ParseField("collapse"); + public static final ParseField FIELD_FIELD = new ParseField("field"); private static final ObjectParser PARSER = new ObjectParser<>("inner_hits", InnerHitBuilder::new); @@ -91,6 +94,28 @@ public final class InnerHitBuilder implements Writeable, ToXContentObject { }, SearchSourceBuilder._SOURCE_FIELD, ObjectParser.ValueType.OBJECT_ARRAY_BOOLEAN_OR_STRING); PARSER.declareObject(InnerHitBuilder::setHighlightBuilder, (p, c) -> HighlightBuilder.fromXContent(p), SearchSourceBuilder.HIGHLIGHT_FIELD); + PARSER.declareField((parser, builder, context) -> { + Boolean isParsedCorrectly = false; + String field; + if (parser.currentToken() == XContentParser.Token.START_OBJECT) { + if (parser.nextToken() == XContentParser.Token.FIELD_NAME) { + if (FIELD_FIELD.match(parser.currentName(), parser.getDeprecationHandler())) { + if (parser.nextToken() == XContentParser.Token.VALUE_STRING){ + field = parser.text(); + if (parser.nextToken() == XContentParser.Token.END_OBJECT){ + isParsedCorrectly = true; + CollapseBuilder cb = new CollapseBuilder(field); + builder.setInnerCollapse(cb); + } + } + } + } + } + if (isParsedCorrectly == false) { + throw new ParsingException(parser.getTokenLocation(), "Invalid token in the inner collapse"); + } + + }, COLLAPSE_FIELD, ObjectParser.ValueType.OBJECT); } private String name; @@ -109,6 +134,7 @@ public final class InnerHitBuilder implements Writeable, ToXContentObject { private Set scriptFields; private HighlightBuilder highlightBuilder; private FetchSourceContext fetchSourceContext; + private CollapseBuilder innerCollapseBuilder = null; public InnerHitBuilder() { this.name = null; @@ -173,6 +199,9 @@ public InnerHitBuilder(StreamInput in) throws IOException { boolean hasChildren = in.readBoolean(); assert hasChildren == false; } + if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + this.innerCollapseBuilder = in.readOptionalWriteable(CollapseBuilder::new); + } } @Override @@ -218,6 +247,9 @@ public void writeTo(StreamOutput out) throws IOException { } } out.writeOptionalWriteable(highlightBuilder); + if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + out.writeOptionalWriteable(innerCollapseBuilder); + } } /** @@ -501,6 +533,15 @@ QueryBuilder getQuery() { return query; } + public InnerHitBuilder setInnerCollapse(CollapseBuilder innerCollapseBuilder) { + this.innerCollapseBuilder = innerCollapseBuilder; + return this; + } + + public CollapseBuilder getInnerCollapseBuilder() { + return innerCollapseBuilder; + } + @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); @@ -550,6 +591,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws if (highlightBuilder != null) { builder.field(SearchSourceBuilder.HIGHLIGHT_FIELD.getPreferredName(), highlightBuilder, params); } + if (innerCollapseBuilder != null) { + builder.field(COLLAPSE_FIELD.getPreferredName(), innerCollapseBuilder); + } builder.endObject(); return builder; } @@ -572,13 +616,14 @@ public boolean equals(Object o) { Objects.equals(scriptFields, that.scriptFields) && Objects.equals(fetchSourceContext, that.fetchSourceContext) && Objects.equals(sorts, that.sorts) && - Objects.equals(highlightBuilder, that.highlightBuilder); + Objects.equals(highlightBuilder, that.highlightBuilder) && + Objects.equals(innerCollapseBuilder, that.innerCollapseBuilder); } @Override public int hashCode() { return Objects.hash(name, ignoreUnmapped, from, size, explain, version, trackScores, - storedFieldsContext, docValueFields, scriptFields, fetchSourceContext, sorts, highlightBuilder); + storedFieldsContext, docValueFields, scriptFields, fetchSourceContext, sorts, highlightBuilder, innerCollapseBuilder); } public static InnerHitBuilder fromXContent(XContentParser parser) throws IOException { diff --git a/server/src/main/java/org/elasticsearch/search/collapse/CollapseBuilder.java b/server/src/main/java/org/elasticsearch/search/collapse/CollapseBuilder.java index e303b0e044337..90e35c34e28f8 100644 --- a/server/src/main/java/org/elasticsearch/search/collapse/CollapseBuilder.java +++ b/server/src/main/java/org/elasticsearch/search/collapse/CollapseBuilder.java @@ -51,11 +51,8 @@ public class CollapseBuilder implements Writeable, ToXContentObject { public static final ParseField FIELD_FIELD = new ParseField("field"); public static final ParseField INNER_HITS_FIELD = new ParseField("inner_hits"); public static final ParseField MAX_CONCURRENT_GROUP_REQUESTS_FIELD = new ParseField("max_concurrent_group_searches"); - public static final ParseField COLLAPSE_FIELD = new ParseField("collapse"); private static final ObjectParser PARSER = new ObjectParser<>("collapse", CollapseBuilder::new); - private static final ObjectParser INNER_COLLAPSE_PARSER = - new ObjectParser<>("inner collapse", CollapseBuilder::new); static { PARSER.declareString(CollapseBuilder::setField, FIELD_FIELD); @@ -73,25 +70,15 @@ public class CollapseBuilder implements Writeable, ToXContentObject { throw new ParsingException(parser.getTokenLocation(), "Invalid token in inner_hits array"); } } + builder.setInnerHits(innerHitBuilders); } }, INNER_HITS_FIELD, ObjectParser.ValueType.OBJECT_ARRAY); - - INNER_COLLAPSE_PARSER.declareString(CollapseBuilder::setField, FIELD_FIELD); - PARSER.declareField((parser, builder, context) -> { - XContentParser.Token currentToken = parser.currentToken(); - if (currentToken == XContentParser.Token.START_OBJECT) { - builder.setInnerCollapse(INNER_COLLAPSE_PARSER.apply(parser, null)); - } else { - throw new ParsingException(parser.getTokenLocation(), "Invalid token in the inner collapse"); - } - }, COLLAPSE_FIELD, ObjectParser.ValueType.OBJECT); } private String field; private List innerHits = Collections.emptyList(); private int maxConcurrentGroupRequests = 0; - private CollapseBuilder innerCollapseBuilder = null; private CollapseBuilder() {} @@ -117,9 +104,6 @@ public CollapseBuilder(StreamInput in) throws IOException { this.innerHits = Collections.emptyList(); } } - if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { - this.innerCollapseBuilder = in.readOptionalWriteable(CollapseBuilder::new); - } } @Override @@ -135,9 +119,6 @@ public void writeTo(StreamOutput out) throws IOException { innerHits.get(0).writeToCollapseBWC(out); } } - if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { - out.writeOptionalWriteable(innerCollapseBuilder); - } } public static CollapseBuilder fromXContent(XContentParser parser) { @@ -163,11 +144,6 @@ public CollapseBuilder setInnerHits(List innerHits) { return this; } - public CollapseBuilder setInnerCollapse(CollapseBuilder innerCollapseBuilder) { - this.innerCollapseBuilder = innerCollapseBuilder; - return this; - } - public CollapseBuilder setMaxConcurrentGroupRequests(int num) { if (num < 1) { throw new IllegalArgumentException("maxConcurrentGroupRequests` must be positive"); @@ -190,10 +166,6 @@ public List getInnerHits() { return this.innerHits; } - public CollapseBuilder getInnerCollapseBuilder() { - return innerCollapseBuilder; - } - /** * Returns the amount of group requests that are allowed to be ran concurrently in the inner_hits phase. */ @@ -225,9 +197,6 @@ private void innerToXContent(XContentBuilder builder) throws IOException { builder.endArray(); } } - if (innerCollapseBuilder != null) { - builder.field(COLLAPSE_FIELD.getPreferredName(), innerCollapseBuilder); - } } @Override @@ -239,13 +208,12 @@ public boolean equals(Object o) { if (maxConcurrentGroupRequests != that.maxConcurrentGroupRequests) return false; if (!field.equals(that.field)) return false; - if (Objects.equals(innerHits, that.innerHits) == false) return false; - return Objects.equals(innerCollapseBuilder, that.innerCollapseBuilder); + return Objects.equals(innerHits, that.innerHits); } @Override public int hashCode() { - int result = Objects.hash(field, innerHits, innerCollapseBuilder); + int result = Objects.hash(field, innerHits); result = 31 * result + maxConcurrentGroupRequests; return result; }