Include the _index, _type and _id to nested search hits in the top_hits and inner_hits response.

Also include _type and _id for parent/child hits inside inner hits.

In the case of top_hits aggregation the nested search hits are
directly returned and are not grouped by a root or parent document, so
it is important to include the _id and _index attributes in order to know
to what documents these nested search hits belong to.

Closes #27053
This commit is contained in:
Martijn van Groningen 2017-11-01 07:34:14 +01:00
parent a165d1df40
commit cb1204774b
No known key found for this signature in database
GPG Key ID: AB236F4FCF2AF12A
6 changed files with 119 additions and 17 deletions

View File

@ -328,6 +328,14 @@ public final class SearchHit implements Streamable, ToXContentObject, Iterable<D
}
public void shard(SearchShardTarget target) {
if (innerHits != null) {
for (SearchHits innerHits : innerHits.values()) {
for (SearchHit innerHit : innerHits) {
innerHit.shard(target);
}
}
}
this.shard = target;
if (target != null) {
this.index = target.getIndex();
@ -414,18 +422,17 @@ public final class SearchHit implements Streamable, ToXContentObject, Iterable<D
builder.field(Fields._SHARD, shard.getShardId());
builder.field(Fields._NODE, shard.getNodeIdText());
}
if (index != null) {
builder.field(Fields._INDEX, RemoteClusterAware.buildRemoteIndexName(clusterAlias, index));
}
if (type != null) {
builder.field(Fields._TYPE, type);
}
if (id != null) {
builder.field(Fields._ID, id);
}
if (nestedIdentity != null) {
nestedIdentity.toXContent(builder, params);
} else {
if (index != null) {
builder.field(Fields._INDEX, RemoteClusterAware.buildRemoteIndexName(clusterAlias, index));
}
if (type != null) {
builder.field(Fields._TYPE, type);
}
if (id != null) {
builder.field(Fields._ID, id);
}
}
if (version != -1) {
builder.field(Fields._VERSION, version);
@ -840,9 +847,9 @@ public final class SearchHit implements Streamable, ToXContentObject, Iterable<D
private static final String FIELD = "field";
private static final String OFFSET = "offset";
private Text field;
private int offset;
private NestedIdentity child;
private final Text field;
private final int offset;
private final NestedIdentity child;
public NestedIdentity(String field, int offset, NestedIdentity child) {
this.field = new Text(field);

View File

@ -323,6 +323,9 @@ Top hits response snippet with a nested hit, which resides in the first slot of
"max_score": 0.2876821,
"hits": [
{
"_index": "sales",
"_type" : "product",
"_id": "1",
"_nested": {
"field": "comments", <1>
"offset": 0 <2>

View File

@ -152,6 +152,9 @@ An example of a response snippet that could be generated from the above search r
"max_score": 1.0,
"hits": [
{
"_index": "test",
"_type": "doc",
"_id": "1",
"_nested": {
"field": "comments",
"offset": 1
@ -278,6 +281,9 @@ Response not included in text but tested for completeness sake.
"max_score": 1.0444683,
"hits": [
{
"_index": "test",
"_type": "doc",
"_id": "1",
"_nested": {
"field": "comments",
"offset": 1
@ -394,6 +400,9 @@ Which would look like:
"max_score": 0.6931472,
"hits": [
{
"_index": "test",
"_type": "doc",
"_id": "1",
"_nested": {
"field": "comments",
"offset": 1,
@ -505,6 +514,7 @@ An example of a response snippet that could be generated from the above search r
"max_score": 1.0,
"hits": [
{
"_index": "test",
"_type": "doc",
"_id": "2",
"_score": 1.0,

View File

@ -41,6 +41,6 @@ setup:
- match: { hits.total: 1 }
- match: { hits.hits.0._index: "test" }
- match: { hits.hits.0._id: "1" }
- is_false: hits.hits.0.inner_hits.child.hits.hits.0._index
- match: { hits.hits.0.inner_hits.child.hits.hits.0._index: "test"}
- match: { hits.hits.0.inner_hits.child.hits.hits.0._id: "2" }
- is_false: hits.hits.0.inner_hits.child.hits.hits.0._nested

View File

@ -0,0 +1,82 @@
---
"top_hits aggregation with nested documents":
- skip:
version: "5.99.99 - "
reason: "5.x nodes don't include index or id in nested top hits"
- do:
indices.create:
index: my-index
body:
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
doc:
properties:
users:
type: nested
- do:
index:
index: my-index
type: doc
id: 1
refresh: true
body: |
{
"group" : "fans",
"users" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
}
- do:
index:
index: my-index
type: doc
id: 2
refresh: true
body: |
{
"group" : "fans",
"users" : [
{
"first" : "Mark",
"last" : "Doe"
}
]
}
- do:
search:
body:
aggs:
to-users:
nested:
path: users
aggs:
users:
top_hits:
sort: "users.last.keyword"
- match: { hits.total: 2 }
- length: { aggregations.to-users.users.hits.hits: 3 }
- match: { aggregations.to-users.users.hits.hits.0._id: "2" }
- match: { aggregations.to-users.users.hits.hits.0._index: my-index }
- match: { aggregations.to-users.users.hits.hits.0._nested.field: users }
- match: { aggregations.to-users.users.hits.hits.0._nested.offset: 0 }
- match: { aggregations.to-users.users.hits.hits.1._id: "1" }
- match: { aggregations.to-users.users.hits.hits.1._index: my-index }
- match: { aggregations.to-users.users.hits.hits.1._nested.field: users }
- match: { aggregations.to-users.users.hits.hits.1._nested.offset: 0 }
- match: { aggregations.to-users.users.hits.hits.2._id: "1" }
- match: { aggregations.to-users.users.hits.hits.2._index: my-index }
- match: { aggregations.to-users.users.hits.hits.2._nested.field: users }
- match: { aggregations.to-users.users.hits.hits.2._nested.offset: 1 }

View File

@ -34,9 +34,9 @@ setup:
- match: { hits.hits.0._index: "test" }
- match: { hits.hits.0._type: "type_1" }
- match: { hits.hits.0._id: "1" }
- is_false: hits.hits.0.inner_hits.nested_field.hits.hits.0._index
- is_false: hits.hits.0.inner_hits.nested_field.hits.hits.0._type
- is_false: hits.hits.0.inner_hits.nested_field.hits.hits.0._id
- match: { hits.hits.0.inner_hits.nested_field.hits.hits.0._index: "test" }
- match: { hits.hits.0.inner_hits.nested_field.hits.hits.0._type: "type1" }
- match: { hits.hits.0.inner_hits.nested_field.hits.hits.0._id: "1" }
- match: { hits.hits.0.inner_hits.nested_field.hits.hits.0._nested.field: "nested_field" }
- match: { hits.hits.0.inner_hits.nested_field.hits.hits.0._nested.offset: 0 }
- is_false: hits.hits.0.inner_hits.nested_field.hits.hits.0._nested.child