|
@@ -22,6 +22,7 @@ The structure looks like this:
|
|
|
}
|
|
|
}
|
|
|
--------------------------------------------------
|
|
|
+// NOTCONSOLE
|
|
|
|
|
|
If `inner_hits` is defined on a query that supports it then each search hit will contain an `inner_hits` json object with the following structure:
|
|
|
|
|
@@ -52,6 +53,7 @@ If `inner_hits` is defined on a query that supports it then each search hit will
|
|
|
...
|
|
|
]
|
|
|
--------------------------------------------------
|
|
|
+// NOTCONSOLE
|
|
|
|
|
|
==== Options
|
|
|
|
|
@@ -80,22 +82,50 @@ Inner hits also supports the following per document features:
|
|
|
|
|
|
The nested `inner_hits` can be used to include nested inner objects as inner hits to a search hit.
|
|
|
|
|
|
-The example below assumes that there is a nested object field defined with the name `comments`:
|
|
|
-
|
|
|
[source,js]
|
|
|
--------------------------------------------------
|
|
|
+PUT test
|
|
|
{
|
|
|
- "query" : {
|
|
|
- "nested" : {
|
|
|
- "path" : "comments",
|
|
|
- "query" : {
|
|
|
- "match" : {"comments.message" : "[actual query]"}
|
|
|
- },
|
|
|
- "inner_hits" : {} <1>
|
|
|
+ "mappings": {
|
|
|
+ "doc": {
|
|
|
+ "properties": {
|
|
|
+ "comments": {
|
|
|
+ "type": "nested"
|
|
|
}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+PUT test/doc/1?refresh
|
|
|
+{
|
|
|
+ "title": "Test title",
|
|
|
+ "comments": [
|
|
|
+ {
|
|
|
+ "author": "kimchy",
|
|
|
+ "text": "comment text"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "author": "nik9000",
|
|
|
+ "text": "words words words"
|
|
|
}
|
|
|
+ ]
|
|
|
+}
|
|
|
+
|
|
|
+POST test/_search
|
|
|
+{
|
|
|
+ "query": {
|
|
|
+ "nested": {
|
|
|
+ "path": "comments",
|
|
|
+ "query": {
|
|
|
+ "match": {"comments.text" : "words"}
|
|
|
+ },
|
|
|
+ "inner_hits": {} <1>
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
--------------------------------------------------
|
|
|
+// CONSOLE
|
|
|
|
|
|
<1> The inner hit definition in the nested query. No other options need to be defined.
|
|
|
|
|
@@ -103,35 +133,46 @@ An example of a response snippet that could be generated from the above search r
|
|
|
|
|
|
[source,js]
|
|
|
--------------------------------------------------
|
|
|
-...
|
|
|
-"hits": {
|
|
|
- ...
|
|
|
- "hits": [
|
|
|
- {
|
|
|
- "_index": "my-index",
|
|
|
- "_type": "question",
|
|
|
+{
|
|
|
+ ...,
|
|
|
+ "hits": {
|
|
|
+ "total": 1,
|
|
|
+ "max_score": 0.9651416,
|
|
|
+ "hits": [
|
|
|
+ {
|
|
|
+ "_index": "test",
|
|
|
+ "_type": "doc",
|
|
|
"_id": "1",
|
|
|
+ "_score": 0.9651416,
|
|
|
"_source": ...,
|
|
|
"inner_hits": {
|
|
|
- "comments": { <1>
|
|
|
- "hits": {
|
|
|
- "total": ...,
|
|
|
- "hits": [
|
|
|
- {
|
|
|
- "_nested": {
|
|
|
- "field": "comments",
|
|
|
- "offset": 2
|
|
|
- },
|
|
|
- "_source": ...
|
|
|
- },
|
|
|
- ...
|
|
|
- ]
|
|
|
- }
|
|
|
- }
|
|
|
+ "comments": { <1>
|
|
|
+ "hits": {
|
|
|
+ "total": 1,
|
|
|
+ "max_score": 0.9651416,
|
|
|
+ "hits": [
|
|
|
+ {
|
|
|
+ "_nested": {
|
|
|
+ "field": "comments",
|
|
|
+ "offset": 1
|
|
|
+ },
|
|
|
+ "_score": 0.9651416,
|
|
|
+ "_source": {
|
|
|
+ "author": "nik9000",
|
|
|
+ "text": "words words words"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- },
|
|
|
- ...
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+}
|
|
|
--------------------------------------------------
|
|
|
+// TESTRESPONSE[s/"_source": \.\.\./"_source": $body.hits.hits.0._source/]
|
|
|
+// TESTRESPONSE[s/\.\.\./"timed_out": false, "took": $body.took, "_shards": $body._shards/]
|
|
|
|
|
|
<1> The name used in the inner hit definition in the search request. A custom key can be used via the `name` option.
|
|
|
|
|
@@ -156,46 +197,111 @@ its `_source` field. To include the source of just the nested document, the sour
|
|
|
the relevant bit for the nested document is included as source in the inner hit. Doing this for each matching nested document
|
|
|
has an impact on the time it takes to execute the entire search request, especially when `size` and the inner hits' `size`
|
|
|
are set higher than the default. To avoid the relative expensive source extraction for nested inner hits, one can disable
|
|
|
-including the source and solely rely on stored fields.
|
|
|
-
|
|
|
-Enabled stored field for fields under the nested object field in your mapping:
|
|
|
+including the source and solely rely on stored fields. Like this:
|
|
|
|
|
|
[source,js]
|
|
|
--------------------------------------------------
|
|
|
+PUT test
|
|
|
{
|
|
|
- "properties": {
|
|
|
- "comment": {
|
|
|
- "type": "comments",
|
|
|
- "properties" : {
|
|
|
- "message" : {
|
|
|
- "type" : "text",
|
|
|
- "store" : true
|
|
|
+ "mappings": {
|
|
|
+ "doc": {
|
|
|
+ "properties": {
|
|
|
+ "comments": {
|
|
|
+ "type": "nested",
|
|
|
+ "properties": {
|
|
|
+ "text": {
|
|
|
+ "type": "text",
|
|
|
+ "store": true
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+PUT test/doc/1?refresh
|
|
|
+{
|
|
|
+ "title": "Test title",
|
|
|
+ "comments": [
|
|
|
+ {
|
|
|
+ "author": "kimchy",
|
|
|
+ "text": "comment text"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "author": "nik9000",
|
|
|
+ "text": "words words words"
|
|
|
}
|
|
|
+ ]
|
|
|
+}
|
|
|
+
|
|
|
+POST test/_search
|
|
|
+{
|
|
|
+ "query": {
|
|
|
+ "nested": {
|
|
|
+ "path": "comments",
|
|
|
+ "query": {
|
|
|
+ "match": {"comments.text" : "words"}
|
|
|
+ },
|
|
|
+ "inner_hits": {
|
|
|
+ "_source" : false,
|
|
|
+ "stored_fields" : ["comments.text"]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
--------------------------------------------------
|
|
|
+// CONSOLE
|
|
|
+
|
|
|
+////
|
|
|
|
|
|
-Disable including source and include specific stored fields in the inner hits definition:
|
|
|
+Response not included in text but tested for completeness sake.
|
|
|
|
|
|
[source,js]
|
|
|
--------------------------------------------------
|
|
|
{
|
|
|
- "query" : {
|
|
|
- "nested" : {
|
|
|
- "path" : "comments",
|
|
|
- "query" : {
|
|
|
- "match" : {"comments.message" : "[actual query]"}
|
|
|
- },
|
|
|
- "inner_hits" : {
|
|
|
- "_source" : false,
|
|
|
- "stored_fields" : ["comments.text"]
|
|
|
+ ...,
|
|
|
+ "hits": {
|
|
|
+ "total": 1,
|
|
|
+ "max_score": 0.9651416,
|
|
|
+ "hits": [
|
|
|
+ {
|
|
|
+ "_index": "test",
|
|
|
+ "_type": "doc",
|
|
|
+ "_id": "1",
|
|
|
+ "_score": 0.9651416,
|
|
|
+ "_source": ...,
|
|
|
+ "inner_hits": {
|
|
|
+ "comments": { <1>
|
|
|
+ "hits": {
|
|
|
+ "total": 1,
|
|
|
+ "max_score": 0.9651416,
|
|
|
+ "hits": [
|
|
|
+ {
|
|
|
+ "_nested": {
|
|
|
+ "field": "comments",
|
|
|
+ "offset": 1
|
|
|
+ },
|
|
|
+ "_score": 0.9651416,
|
|
|
+ "fields": {
|
|
|
+ "comments.text": [
|
|
|
+ "words words words"
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
}
|
|
|
--------------------------------------------------
|
|
|
+// TESTRESPONSE[s/"_source": \.\.\./"_source": $body.hits.hits.0._source/]
|
|
|
+// TESTRESPONSE[s/\.\.\./"timed_out": false, "took": $body.took, "_shards": $body._shards/]
|
|
|
+
|
|
|
+////
|
|
|
|
|
|
[[hierarchical-nested-inner-hits]]
|
|
|
==== Hierarchical levels of nested object fields and inner hits.
|
|
@@ -206,16 +312,113 @@ with the root hits then the following path can be defined:
|
|
|
|
|
|
[source,js]
|
|
|
--------------------------------------------------
|
|
|
+PUT test
|
|
|
{
|
|
|
- "query" : {
|
|
|
- "nested" : {
|
|
|
- "path" : "comments.votes",
|
|
|
- "query" : { ... },
|
|
|
- "inner_hits" : {}
|
|
|
+ "mappings": {
|
|
|
+ "doc": {
|
|
|
+ "properties": {
|
|
|
+ "comments": {
|
|
|
+ "type": "nested",
|
|
|
+ "properties": {
|
|
|
+ "message": {
|
|
|
+ "type": "text",
|
|
|
+ "store": true
|
|
|
+ },
|
|
|
+ "votes": {
|
|
|
+ "type": "nested"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+PUT test/doc/1?refresh
|
|
|
+{
|
|
|
+ "title": "Test title",
|
|
|
+ "comments": [
|
|
|
+ {
|
|
|
+ "author": "kimchy",
|
|
|
+ "text": "comment text",
|
|
|
+ "votes": []
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "author": "nik9000",
|
|
|
+ "text": "words words words",
|
|
|
+ "votes": [
|
|
|
+ {"value": 1 , "voter": "kimchy"},
|
|
|
+ {"value": -1, "voter": "other"}
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+}
|
|
|
+
|
|
|
+POST test/_search
|
|
|
+{
|
|
|
+ "query": {
|
|
|
+ "nested": {
|
|
|
+ "path": "comments.votes",
|
|
|
+ "query": {
|
|
|
+ "match": {
|
|
|
+ "comments.votes.voter": "kimchy"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ "inner_hits" : {}
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
--------------------------------------------------
|
|
|
+// CONSOLE
|
|
|
+
|
|
|
+Which would look like:
|
|
|
+
|
|
|
+[source,js]
|
|
|
+--------------------------------------------------
|
|
|
+{
|
|
|
+ ...,
|
|
|
+ "hits": {
|
|
|
+ "total": 1,
|
|
|
+ "max_score": 0.6931472,
|
|
|
+ "hits": [
|
|
|
+ {
|
|
|
+ "_index": "test",
|
|
|
+ "_type": "doc",
|
|
|
+ "_id": "1",
|
|
|
+ "_score": 0.6931472,
|
|
|
+ "_source": ...,
|
|
|
+ "inner_hits": {
|
|
|
+ "comments.votes": { <1>
|
|
|
+ "hits": {
|
|
|
+ "total": 1,
|
|
|
+ "max_score": 0.6931472,
|
|
|
+ "hits": [
|
|
|
+ {
|
|
|
+ "_nested": {
|
|
|
+ "field": "comments",
|
|
|
+ "offset": 1,
|
|
|
+ "_nested": {
|
|
|
+ "field": "votes",
|
|
|
+ "offset": 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ "_score": 0.6931472,
|
|
|
+ "_source": {
|
|
|
+ "value": 1,
|
|
|
+ "voter": "kimchy"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+}
|
|
|
+--------------------------------------------------
|
|
|
+// TESTRESPONSE[s/"_source": \.\.\./"_source": $body.hits.hits.0._source/]
|
|
|
+// TESTRESPONSE[s/\.\.\./"timed_out": false, "took": $body.took, "_shards": $body._shards/]
|
|
|
|
|
|
This indirect referencing is only supported for nested inner hits.
|
|
|
|
|
@@ -224,22 +427,49 @@ This indirect referencing is only supported for nested inner hits.
|
|
|
|
|
|
The parent/child `inner_hits` can be used to include parent or child
|
|
|
|
|
|
-The examples below assumes that there is a `_parent` field mapping in the `comment` type:
|
|
|
-
|
|
|
[source,js]
|
|
|
--------------------------------------------------
|
|
|
+PUT test
|
|
|
{
|
|
|
- "query" : {
|
|
|
- "has_child" : {
|
|
|
- "type" : "comment",
|
|
|
- "query" : {
|
|
|
- "match" : {"message" : "[actual query]"}
|
|
|
- },
|
|
|
- "inner_hits" : {} <1>
|
|
|
+ "settings": {
|
|
|
+ "mapping.single_type": false
|
|
|
+ },
|
|
|
+ "mappings": {
|
|
|
+ "my_parent": {},
|
|
|
+ "my_child": {
|
|
|
+ "_parent": {
|
|
|
+ "type": "my_parent"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+PUT test/my_parent/1?refresh
|
|
|
+{
|
|
|
+ "test": "test"
|
|
|
+}
|
|
|
+
|
|
|
+PUT test/my_child/1?parent=1&refresh
|
|
|
+{
|
|
|
+ "test": "test"
|
|
|
+}
|
|
|
+
|
|
|
+POST test/_search
|
|
|
+{
|
|
|
+ "query": {
|
|
|
+ "has_child": {
|
|
|
+ "type": "my_child",
|
|
|
+ "query": {
|
|
|
+ "match": {
|
|
|
+ "test": "test"
|
|
|
}
|
|
|
+ },
|
|
|
+ "inner_hits": {} <1>
|
|
|
}
|
|
|
+ }
|
|
|
}
|
|
|
--------------------------------------------------
|
|
|
+// CONSOLE
|
|
|
|
|
|
<1> The inner hit definition like in the nested example.
|
|
|
|
|
@@ -247,30 +477,42 @@ An example of a response snippet that could be generated from the above search r
|
|
|
|
|
|
[source,js]
|
|
|
--------------------------------------------------
|
|
|
-...
|
|
|
-"hits": {
|
|
|
- ...
|
|
|
- "hits": [
|
|
|
- {
|
|
|
- "_index": "my-index",
|
|
|
- "_type": "question",
|
|
|
+{
|
|
|
+ ...,
|
|
|
+ "hits": {
|
|
|
+ "total": 1,
|
|
|
+ "max_score": 1.0,
|
|
|
+ "hits": [
|
|
|
+ {
|
|
|
+ "_index": "test",
|
|
|
+ "_type": "my_parent",
|
|
|
"_id": "1",
|
|
|
+ "_score": 1.0,
|
|
|
"_source": ...,
|
|
|
"inner_hits": {
|
|
|
- "comment": {
|
|
|
- "hits": {
|
|
|
- "total": ...,
|
|
|
- "hits": [
|
|
|
- {
|
|
|
- "_type": "comment",
|
|
|
- "_id": "5",
|
|
|
- "_source": ...
|
|
|
- },
|
|
|
- ...
|
|
|
- ]
|
|
|
- }
|
|
|
- }
|
|
|
+ "my_child": {
|
|
|
+ "hits": {
|
|
|
+ "total": 1,
|
|
|
+ "max_score": 0.18232156,
|
|
|
+ "hits": [
|
|
|
+ {
|
|
|
+ "_type": "my_child",
|
|
|
+ "_id": "1",
|
|
|
+ "_score": 0.18232156,
|
|
|
+ "_routing": "1",
|
|
|
+ "_parent": "1",
|
|
|
+ "_source": {
|
|
|
+ "test": "test"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
- },
|
|
|
- ...
|
|
|
---------------------------------------------------
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+}
|
|
|
+--------------------------------------------------
|
|
|
+// TESTRESPONSE[s/"_source": \.\.\./"_source": $body.hits.hits.0._source/]
|
|
|
+// TESTRESPONSE[s/\.\.\./"timed_out": false, "took": $body.took, "_shards": $body._shards/]
|