Skip to content

Commit f29c743

Browse files
authored
Support the 'fields' option in inner_hits and top_hits. (#62259)
This PR adds support for the 'fields' option in the following places: * Anytime `inner_hits` is used, for both fetching nested/ child docs and field collapsing * The `top_hits` aggregation Addresses #61949.
1 parent 916a272 commit f29c743

File tree

15 files changed

+299
-83
lines changed

15 files changed

+299
-83
lines changed

docs/reference/aggregations/metrics/tophits-aggregation.asciidoc

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ The top_hits aggregation returns regular search hits, because of this many per h
2424
* <<highlighting,Highlighting>>
2525
* <<request-body-search-explain,Explain>>
2626
* <<named-queries,Named queries>>
27+
* <<search-fields-param,Search fields>>
2728
* <<source-filtering,Source filtering>>
2829
* <<stored-fields,Stored fields>>
2930
* <<script-fields,Script fields>>
@@ -41,7 +42,7 @@ by aggregations, use a <<query-dsl-function-score-query,`function_score`>> or
4142

4243
==== Example
4344

44-
In the following example we group the sales by type and per type we show the last sale.
45+
In the following example we group the sales by type and per type we show the last sale.
4546
For each sale only the date and price fields are being included in the source.
4647

4748
[source,console]

docs/reference/search/search-your-data/retrieve-inner-hits.asciidoc

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Inner hits also supports the following per document features:
7373

7474
* <<highlighting,Highlighting>>
7575
* <<request-body-search-explain,Explain>>
76+
* <<search-fields-param,Search fields>>
7677
* <<request-body-search-source-filtering,Source filtering>>
7778
* <<script-fields,Script fields>>
7879
* <<docvalue-fields,Doc value fields>>

modules/parent-join/src/internalClusterTest/java/org/elasticsearch/join/query/InnerHitsIT.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ public void testSimpleParentChild() throws Exception {
171171
.setQuery(
172172
hasChildQuery("comment", matchQuery("message", "fox"), ScoreMode.None).innerHit(
173173
new InnerHitBuilder()
174-
.addDocValueField("message")
174+
.addFetchField("message")
175175
.setHighlightBuilder(new HighlightBuilder().field("message"))
176176
.setExplain(true).setSize(1)
177177
.addScriptField("script", new Script(ScriptType.INLINE, MockScriptEngine.NAME, "5",
@@ -182,8 +182,18 @@ public void testSimpleParentChild() throws Exception {
182182
assertThat(innerHits.getHits().length, equalTo(1));
183183
assertThat(innerHits.getAt(0).getHighlightFields().get("message").getFragments()[0].string(), equalTo("<em>fox</em> eat quick"));
184184
assertThat(innerHits.getAt(0).getExplanation().toString(), containsString("weight(message:fox"));
185-
assertThat(innerHits.getAt(0).getFields().get("message").getValue().toString(), equalTo("eat"));
185+
assertThat(innerHits.getAt(0).getFields().get("message").getValue().toString(), equalTo("fox eat quick"));
186186
assertThat(innerHits.getAt(0).getFields().get("script").getValue().toString(), equalTo("5"));
187+
188+
response = client().prepareSearch("articles")
189+
.setQuery(
190+
hasChildQuery("comment", matchQuery("message", "fox"), ScoreMode.None).innerHit(
191+
new InnerHitBuilder().addDocValueField("message").setSize(1)
192+
)).get();
193+
assertNoFailures(response);
194+
innerHits = response.getHits().getAt(0).getInnerHits().get("comment");
195+
assertThat(innerHits.getHits().length, equalTo(1));
196+
assertThat(innerHits.getAt(0).getFields().get("message").getValue().toString(), equalTo("eat"));
187197
}
188198

189199
public void testRandomParentChild() throws Exception {

rest-api-spec/src/main/resources/rest-api-spec/test/search/110_field_collapsing.yml

+41-6
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,50 @@ setup:
66
mappings:
77
properties:
88
numeric_group: { type: integer }
9+
tag: { type: keyword }
910

1011
- do:
1112
index:
1213
index: test
1314
id: 1
1415
version_type: external
1516
version: 11
16-
body: { numeric_group: 1, sort: 10 }
17+
body: { numeric_group: 1, tag: A, sort: 10 }
1718
- do:
1819
index:
1920
index: test
2021
id: 2
2122
version_type: external
2223
version: 22
23-
body: { numeric_group: 1, sort: 6 }
24+
body: { numeric_group: 1, tag: B, sort: 6 }
2425
- do:
2526
index:
2627
index: test
2728
id: 3
2829
version_type: external
2930
version: 33
30-
body: { numeric_group: 1, sort: 24 }
31+
body: { numeric_group: 1, tag: A, sort: 24 }
3132
- do:
3233
index:
3334
index: test
3435
id: 4
3536
version_type: external
3637
version: 44
37-
body: { numeric_group: 25, sort: 10 }
38+
body: { numeric_group: 25, tag: B, sort: 10 }
3839
- do:
3940
index:
4041
index: test
4142
id: 5
4243
version_type: external
4344
version: 55
44-
body: { numeric_group: 25, sort: 5 }
45+
body: { numeric_group: 25, tag: A, sort: 5 }
4546
- do:
4647
index:
4748
index: test
4849
id: 6
4950
version_type: external
5051
version: 66
51-
body: { numeric_group: 3, sort: 36 }
52+
body: { numeric_group: 3, tag: B, sort: 36 }
5253
- do:
5354
indices.refresh:
5455
index: test
@@ -139,6 +140,40 @@ setup:
139140
- match: { hits.hits.2.inner_hits.sub_hits.hits.hits.0._id: "5" }
140141
- match: { hits.hits.2.inner_hits.sub_hits.hits.hits.1._id: "4" }
141142

143+
---
144+
"field collapsing, inner_hits, and fields":
145+
- skip:
146+
version: " - 7.99.99"
147+
reason: the enhancement is not yet backported to 7.x
148+
- do:
149+
search:
150+
rest_total_hits_as_int: true
151+
index: test
152+
body:
153+
collapse:
154+
field: numeric_group
155+
inner_hits:
156+
name: sub_hits
157+
size: 2
158+
sort: [{ sort: asc }]
159+
fields: ["tag"]
160+
sort: [{ sort: desc }]
161+
162+
- length: { hits.hits: 3 }
163+
- length: { hits.hits.0.inner_hits.sub_hits.hits.hits: 1 }
164+
- match: { hits.hits.0.inner_hits.sub_hits.hits.hits.0._id: "6" }
165+
- match: { hits.hits.0.inner_hits.sub_hits.hits.hits.0.fields.tag: ["B"]}
166+
- length: { hits.hits.1.inner_hits.sub_hits.hits.hits: 2 }
167+
- match: { hits.hits.1.inner_hits.sub_hits.hits.hits.0._id: "2" }
168+
- match: { hits.hits.1.inner_hits.sub_hits.hits.hits.0.fields.tag: ["B"]}
169+
- match: { hits.hits.1.inner_hits.sub_hits.hits.hits.1._id: "1" }
170+
- match: { hits.hits.1.inner_hits.sub_hits.hits.hits.1.fields.tag: ["A"]}
171+
- length: { hits.hits.2.inner_hits.sub_hits.hits.hits: 2 }
172+
- match: { hits.hits.2.inner_hits.sub_hits.hits.hits.0._id: "5" }
173+
- match: { hits.hits.2.inner_hits.sub_hits.hits.hits.0.fields.tag: ["A"]}
174+
- match: { hits.hits.2.inner_hits.sub_hits.hits.hits.1._id: "4" }
175+
- match: { hits.hits.2.inner_hits.sub_hits.hits.hits.1.fields.tag: ["B"]}
176+
142177
---
143178
"field collapsing, inner_hits and maxConcurrentGroupRequests":
144179

server/src/internalClusterTest/java/org/elasticsearch/search/aggregations/metrics/TopHitsIT.java

+12-7
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ public void setupSuiteScopeCluster() throws Exception {
166166
.field(SORT_FIELD, i + 1)
167167
.field("text", "some text to entertain")
168168
.field("field1", 5)
169+
.field("field2", 2.71)
169170
.endObject()));
170171
}
171172

@@ -315,7 +316,7 @@ public void testBasics() throws Exception {
315316
assertThat((Long) hits.getAt(1).getSortValues()[0], equalTo(higestSortValue - 1));
316317
assertThat((Long) hits.getAt(2).getSortValues()[0], equalTo(higestSortValue - 2));
317318

318-
assertThat(hits.getAt(0).getSourceAsMap().size(), equalTo(4));
319+
assertThat(hits.getAt(0).getSourceAsMap().size(), equalTo(5));
319320
}
320321
}
321322

@@ -402,7 +403,7 @@ public void testBreadthFirstWithScoreNeeded() throws Exception {
402403
assertThat(hits.getTotalHits().value, equalTo(10L));
403404
assertThat(hits.getHits().length, equalTo(3));
404405

405-
assertThat(hits.getAt(0).getSourceAsMap().size(), equalTo(4));
406+
assertThat(hits.getAt(0).getSourceAsMap().size(), equalTo(5));
406407
}
407408
}
408409

@@ -433,7 +434,7 @@ public void testBreadthFirstWithAggOrderAndScoreNeeded() throws Exception {
433434
assertThat(hits.getTotalHits().value, equalTo(10L));
434435
assertThat(hits.getHits().length, equalTo(3));
435436

436-
assertThat(hits.getAt(0).getSourceAsMap().size(), equalTo(4));
437+
assertThat(hits.getAt(0).getSourceAsMap().size(), equalTo(5));
437438
id--;
438439
}
439440
}
@@ -597,6 +598,7 @@ public void testFetchFeatures() {
597598
.explain(true)
598599
.storedField("text")
599600
.docValueField("field1")
601+
.fetchField("field2")
600602
.scriptField("script",
601603
new Script(ScriptType.INLINE, MockScriptEngine.NAME, "5", Collections.emptyMap()))
602604
.fetchSource("text", null)
@@ -639,13 +641,16 @@ public void testFetchFeatures() {
639641

640642
assertThat(hit.getMatchedQueries()[0], equalTo("test"));
641643

642-
DocumentField field = hit.field("field1");
643-
assertThat(field.getValue().toString(), equalTo("5"));
644+
DocumentField field1 = hit.field("field1");
645+
assertThat(field1.getValue(), equalTo(5L));
646+
647+
DocumentField field2 = hit.field("field2");
648+
assertThat(field2.getValue(), equalTo(2.71f));
644649

645650
assertThat(hit.getSourceAsMap().get("text").toString(), equalTo("some text to entertain"));
646651

647-
field = hit.field("script");
648-
assertThat(field.getValue().toString(), equalTo("5"));
652+
field2 = hit.field("script");
653+
assertThat(field2.getValue().toString(), equalTo("5"));
649654

650655
assertThat(hit.getSourceAsMap().size(), equalTo(1));
651656
assertThat(hit.getSourceAsMap().get("text").toString(), equalTo("some text to entertain"));

server/src/internalClusterTest/java/org/elasticsearch/search/fetch/subphase/InnerHitsIT.java

+12-2
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public void testSimpleNested() throws Exception {
165165
.setQuery(nestedQuery("comments", matchQuery("comments.message", "fox"), ScoreMode.Avg).innerHit(
166166
new InnerHitBuilder().setHighlightBuilder(new HighlightBuilder().field("comments.message"))
167167
.setExplain(true)
168-
.addDocValueField("comments.mes*")
168+
.addFetchField("comments.mes*")
169169
.addScriptField("script",
170170
new Script(ScriptType.INLINE, MockScriptEngine.NAME, "5", Collections.emptyMap()))
171171
.setSize(1))).get();
@@ -176,8 +176,18 @@ public void testSimpleNested() throws Exception {
176176
assertThat(innerHits.getAt(0).getHighlightFields().get("comments.message").getFragments()[0].string(),
177177
equalTo("<em>fox</em> eat quick"));
178178
assertThat(innerHits.getAt(0).getExplanation().toString(), containsString("weight(comments.message:fox in"));
179-
assertThat(innerHits.getAt(0).getFields().get("comments.message").getValue().toString(), equalTo("eat"));
179+
assertThat(innerHits.getAt(0).getFields().get("comments.message").getValue().toString(), equalTo("fox eat quick"));
180180
assertThat(innerHits.getAt(0).getFields().get("script").getValue().toString(), equalTo("5"));
181+
182+
response = client().prepareSearch("articles")
183+
.setQuery(nestedQuery("comments", matchQuery("comments.message", "fox"), ScoreMode.Avg).innerHit(
184+
new InnerHitBuilder()
185+
.addDocValueField("comments.mes*")
186+
.setSize(1))).get();
187+
assertNoFailures(response);
188+
innerHits = response.getHits().getAt(0).getInnerHits().get("comments");
189+
assertThat(innerHits.getHits().length, equalTo(1));
190+
assertThat(innerHits.getAt(0).getFields().get("comments.message").getValue().toString(), equalTo("eat"));
181191
}
182192

183193
public void testRandomNested() throws Exception {

server/src/main/java/org/elasticsearch/action/search/ExpandSearchPhase.java

+3
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ private SearchSourceBuilder buildExpandSearchSourceBuilder(InnerHitBuilder optio
136136
options.getFetchSourceContext().excludes());
137137
}
138138
}
139+
if (options.getFetchFields() != null) {
140+
options.getFetchFields().forEach(ff -> groupSource.fetchField(ff.field, ff.format));
141+
}
139142
if (options.getDocValueFields() != null) {
140143
options.getDocValueFields().forEach(ff -> groupSource.docValueField(ff.field, ff.format));
141144
}

0 commit comments

Comments
 (0)