内部ヒットの取得
parent-join および nested 機能は、異なるスコープに一致するドキュメントを返すことを可能にします。親/子のケースでは、親ドキュメントは子ドキュメントの一致に基づいて返されるか、子ドキュメントは親ドキュメントの一致に基づいて返されます。ネストされたケースでは、ネストされた内部オブジェクトの一致に基づいてドキュメントが返されます。
どちらの場合も、ドキュメントが返される原因となった異なるスコープ内の実際の一致は隠されています。多くの場合、特定の情報が返される原因となった内部ネストされたオブジェクト(ネストされた場合)や子/親ドキュメント(親/子の場合)を知ることは非常に有用です。内部ヒット機能はこれに使用できます。この機能は、検索応答内の各検索ヒットに対して、異なるスコープで検索ヒットが一致する原因となった追加のネストされたヒットを返します。
内部ヒットは、inner_hits
定義を nested
、has_child
または has_parent
クエリおよびフィルターに定義することで使用できます。構造は次のようになります:
Js
"<query>" : {
"inner_hits" : {
<inner_hits_options>
}
}
もし inner_hits
がそれをサポートするクエリに定義されている場合、各検索ヒットには次の構造を持つ inner_hits
JSON オブジェクトが含まれます:
Js
"hits": [
{
"_index": ...,
"_type": ...,
"_id": ...,
"inner_hits": {
"<inner_hits_name>": {
"hits": {
"total": ...,
"hits": [
{
"_id": ...,
...
},
...
]
}
}
},
...
},
...
]
オプション
内部ヒットは次のオプションをサポートします:
from |
返される通常の検索ヒットの各 inner_hits に対して取得する最初のヒットのオフセット。 |
size |
各 inner_hits に対して返す最大ヒット数。デフォルトでは、上位3つの一致するヒットが返されます。 |
sort |
各 inner_hits に対して内部ヒットをどのようにソートするか。デフォルトでは、ヒットはスコアによってソートされます。 |
name |
応答内の特定の内部ヒット定義に使用される名前。単一の検索リクエストで複数の内部ヒットが定義されている場合に便利です。デフォルトは、内部ヒットが定義されているクエリによって異なります。has_child クエリおよびフィルターの場合、これは子タイプであり、has_parent クエリおよびフィルターの場合、これは親タイプであり、ネストされたクエリおよびフィルターの場合、これはネストされたパスです。 |
内部ヒットは、次のドキュメントごとの機能もサポートします:
ネストされた内部ヒット
ネストされた inner_hits
は、検索ヒットに対する内部ヒットとしてネストされた内部オブジェクトを含めるために使用できます。
Python
resp = client.indices.create(
index="test",
mappings={
"properties": {
"comments": {
"type": "nested"
}
}
},
)
print(resp)
resp1 = client.index(
index="test",
id="1",
refresh=True,
document={
"title": "Test title",
"comments": [
{
"author": "kimchy",
"number": 1
},
{
"author": "nik9000",
"number": 2
}
]
},
)
print(resp1)
resp2 = client.search(
index="test",
query={
"nested": {
"path": "comments",
"query": {
"match": {
"comments.number": 2
}
},
"inner_hits": {}
}
},
)
print(resp2)
Ruby
response = client.indices.create(
index: 'test',
body: {
mappings: {
properties: {
comments: {
type: 'nested'
}
}
}
}
)
puts response
response = client.index(
index: 'test',
id: 1,
refresh: true,
body: {
title: 'Test title',
comments: [
{
author: 'kimchy',
number: 1
},
{
author: 'nik9000',
number: 2
}
]
}
)
puts response
response = client.search(
index: 'test',
body: {
query: {
nested: {
path: 'comments',
query: {
match: {
'comments.number' => 2
}
},
inner_hits: {}
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "test",
mappings: {
properties: {
comments: {
type: "nested",
},
},
},
});
console.log(response);
const response1 = await client.index({
index: "test",
id: 1,
refresh: "true",
document: {
title: "Test title",
comments: [
{
author: "kimchy",
number: 1,
},
{
author: "nik9000",
number: 2,
},
],
},
});
console.log(response1);
const response2 = await client.search({
index: "test",
query: {
nested: {
path: "comments",
query: {
match: {
"comments.number": 2,
},
},
inner_hits: {},
},
},
});
console.log(response2);
コンソール
PUT test
{
"mappings": {
"properties": {
"comments": {
"type": "nested"
}
}
}
}
PUT test/_doc/1?refresh
{
"title": "Test title",
"comments": [
{
"author": "kimchy",
"number": 1
},
{
"author": "nik9000",
"number": 2
}
]
}
POST test/_search
{
"query": {
"nested": {
"path": "comments",
"query": {
"match": {"comments.number" : 2}
},
"inner_hits": {}
}
}
}
ネストされたクエリ内の内部ヒット定義。他のオプションは定義する必要はありません。 |
上記の検索リクエストから生成される可能性のある応答スニペットの例:
コンソール-結果
{
...,
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "test",
"_id": "1",
"_score": 1.0,
"_source": ...,
"inner_hits": {
"comments": {
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "test",
"_id": "1",
"_nested": {
"field": "comments",
"offset": 1
},
"_score": 1.0,
"_source": {
"author": "nik9000",
"number": 2
}
}
]
}
}
}
}
]
}
}
検索リクエスト内の内部ヒット定義で使用される名前。カスタムキーは name オプションを介して使用できます。 |
上記の例では、_nested
メタデータは重要です。なぜなら、どの内部ネストされたオブジェクトからこの内部ヒットが来たのかを定義するからです。field
は、ネストされたヒットがどのオブジェクト配列フィールドから来ているかを定義し、offset
は _source
内の位置に対して相対的です。ソートとスコアリングのため、inner_hits
内のヒットオブジェクトの実際の位置は、ネストされた内部オブジェクトが定義された位置とは通常異なります。
デフォルトでは、_source
は inner_hits
内のヒットオブジェクトにも返されますが、これは変更可能です。_source
フィルタリング機能を介して、ソースの一部を返すか無効にすることができます。ネストされたレベルでストレージフィールドが定義されている場合、これらも fields
機能を介して返すことができます。
重要なデフォルトは、_source
が inner_hits
内のヒットで返されるのは _nested
メタデータに対して相対的であるということです。したがって、上記の例では、ネストされたヒットごとにコメント部分のみが返され、コメントを含むトップレベルドキュメントの全体のソースは返されません。
ネストされた内部ヒットと _source
ネストされたドキュメントには _source
フィールドがありません。なぜなら、ドキュメントの全体のソースがその _source
フィールドの下にルートドキュメントと共に保存されているからです。ネストされたドキュメントのソースのみを含めるために、ルートドキュメントのソースが解析され、ネストされたドキュメントに関連する部分のみが内部ヒットのソースとして含まれます。各一致するネストされたドキュメントに対してこれを行うことは、特に size
および内部ヒットの size
がデフォルトよりも高く設定されている場合、全体の検索リクエストを実行するのにかかる時間に影響を与えます。ネストされた内部ヒットのために比較的高価なソース抽出を避けるために、ソースを含めることを無効にし、ドキュメント値フィールドのみに依存することができます。次のように:
Python
resp = client.indices.create(
index="test",
mappings={
"properties": {
"comments": {
"type": "nested"
}
}
},
)
print(resp)
resp1 = client.index(
index="test",
id="1",
refresh=True,
document={
"title": "Test title",
"comments": [
{
"author": "kimchy",
"text": "comment text"
},
{
"author": "nik9000",
"text": "words words words"
}
]
},
)
print(resp1)
resp2 = client.search(
index="test",
query={
"nested": {
"path": "comments",
"query": {
"match": {
"comments.text": "words"
}
},
"inner_hits": {
"_source": False,
"docvalue_fields": [
"comments.text.keyword"
]
}
}
},
)
print(resp2)
Ruby
response = client.indices.create(
index: 'test',
body: {
mappings: {
properties: {
comments: {
type: 'nested'
}
}
}
}
)
puts response
response = client.index(
index: 'test',
id: 1,
refresh: true,
body: {
title: 'Test title',
comments: [
{
author: 'kimchy',
text: 'comment text'
},
{
author: 'nik9000',
text: 'words words words'
}
]
}
)
puts response
response = client.search(
index: 'test',
body: {
query: {
nested: {
path: 'comments',
query: {
match: {
'comments.text' => 'words'
}
},
inner_hits: {
_source: false,
docvalue_fields: [
'comments.text.keyword'
]
}
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "test",
mappings: {
properties: {
comments: {
type: "nested",
},
},
},
});
console.log(response);
const response1 = await client.index({
index: "test",
id: 1,
refresh: "true",
document: {
title: "Test title",
comments: [
{
author: "kimchy",
text: "comment text",
},
{
author: "nik9000",
text: "words words words",
},
],
},
});
console.log(response1);
const response2 = await client.search({
index: "test",
query: {
nested: {
path: "comments",
query: {
match: {
"comments.text": "words",
},
},
inner_hits: {
_source: false,
docvalue_fields: ["comments.text.keyword"],
},
},
},
});
console.log(response2);
コンソール
PUT test
{
"mappings": {
"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": {
"_source" : false,
"docvalue_fields" : [
"comments.text.keyword"
]
}
}
}
}
ネストされたオブジェクトフィールドと内部ヒットの階層レベル。
マッピングに複数の階層ネストされたオブジェクトフィールドがある場合、各レベルはドット表記のパスを介してアクセスできます。たとえば、comments
ネストフィールドが votes
ネストフィールドを含み、投票がルートヒットと直接返されるべき場合、次のパスを定義できます:
Python
resp = client.indices.create(
index="test",
mappings={
"properties": {
"comments": {
"type": "nested",
"properties": {
"votes": {
"type": "nested"
}
}
}
}
},
)
print(resp)
resp1 = client.index(
index="test",
id="1",
refresh=True,
document={
"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"
}
]
}
]
},
)
print(resp1)
resp2 = client.search(
index="test",
query={
"nested": {
"path": "comments.votes",
"query": {
"match": {
"comments.votes.voter": "kimchy"
}
},
"inner_hits": {}
}
},
)
print(resp2)
Ruby
response = client.indices.create(
index: 'test',
body: {
mappings: {
properties: {
comments: {
type: 'nested',
properties: {
votes: {
type: 'nested'
}
}
}
}
}
}
)
puts response
response = client.index(
index: 'test',
id: 1,
refresh: true,
body: {
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'
}
]
}
]
}
)
puts response
response = client.search(
index: 'test',
body: {
query: {
nested: {
path: 'comments.votes',
query: {
match: {
'comments.votes.voter' => 'kimchy'
}
},
inner_hits: {}
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "test",
mappings: {
properties: {
comments: {
type: "nested",
properties: {
votes: {
type: "nested",
},
},
},
},
},
});
console.log(response);
const response1 = await client.index({
index: "test",
id: 1,
refresh: "true",
document: {
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",
},
],
},
],
},
});
console.log(response1);
const response2 = await client.search({
index: "test",
query: {
nested: {
path: "comments.votes",
query: {
match: {
"comments.votes.voter": "kimchy",
},
},
inner_hits: {},
},
},
});
console.log(response2);
コンソール
PUT test
{
"mappings": {
"properties": {
"comments": {
"type": "nested",
"properties": {
"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" : {}
}
}
}
コンソール-結果
{
...,
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.6931471,
"hits": [
{
"_index": "test",
"_id": "1",
"_score": 0.6931471,
"_source": ...,
"inner_hits": {
"comments.votes": {
"hits": {
"total" : {
"value": 1,
"relation": "eq"
},
"max_score": 0.6931471,
"hits": [
{
"_index": "test",
"_id": "1",
"_nested": {
"field": "comments",
"offset": 1,
"_nested": {
"field": "votes",
"offset": 0
}
},
"_score": 0.6931471,
"_source": {
"value": 1,
"voter": "kimchy"
}
}
]
}
}
}
}
]
}
}
この間接参照は、ネストされた内部ヒットにのみサポートされています。
親/子内部ヒット
親/子 inner_hits
は、親または子を含めるために使用できます:
Python
resp = client.indices.create(
index="test",
mappings={
"properties": {
"my_join_field": {
"type": "join",
"relations": {
"my_parent": "my_child"
}
}
}
},
)
print(resp)
resp1 = client.index(
index="test",
id="1",
refresh=True,
document={
"number": 1,
"my_join_field": "my_parent"
},
)
print(resp1)
resp2 = client.index(
index="test",
id="2",
routing="1",
refresh=True,
document={
"number": 1,
"my_join_field": {
"name": "my_child",
"parent": "1"
}
},
)
print(resp2)
resp3 = client.search(
index="test",
query={
"has_child": {
"type": "my_child",
"query": {
"match": {
"number": 1
}
},
"inner_hits": {}
}
},
)
print(resp3)
Ruby
response = client.indices.create(
index: 'test',
body: {
mappings: {
properties: {
my_join_field: {
type: 'join',
relations: {
my_parent: 'my_child'
}
}
}
}
}
)
puts response
response = client.index(
index: 'test',
id: 1,
refresh: true,
body: {
number: 1,
my_join_field: 'my_parent'
}
)
puts response
response = client.index(
index: 'test',
id: 2,
routing: 1,
refresh: true,
body: {
number: 1,
my_join_field: {
name: 'my_child',
parent: '1'
}
}
)
puts response
response = client.search(
index: 'test',
body: {
query: {
has_child: {
type: 'my_child',
query: {
match: {
number: 1
}
},
inner_hits: {}
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "test",
mappings: {
properties: {
my_join_field: {
type: "join",
relations: {
my_parent: "my_child",
},
},
},
},
});
console.log(response);
const response1 = await client.index({
index: "test",
id: 1,
refresh: "true",
document: {
number: 1,
my_join_field: "my_parent",
},
});
console.log(response1);
const response2 = await client.index({
index: "test",
id: 2,
routing: 1,
refresh: "true",
document: {
number: 1,
my_join_field: {
name: "my_child",
parent: "1",
},
},
});
console.log(response2);
const response3 = await client.search({
index: "test",
query: {
has_child: {
type: "my_child",
query: {
match: {
number: 1,
},
},
inner_hits: {},
},
},
});
console.log(response3);
コンソール
PUT test
{
"mappings": {
"properties": {
"my_join_field": {
"type": "join",
"relations": {
"my_parent": "my_child"
}
}
}
}
}
PUT test/_doc/1?refresh
{
"number": 1,
"my_join_field": "my_parent"
}
PUT test/_doc/2?routing=1&refresh
{
"number": 1,
"my_join_field": {
"name": "my_child",
"parent": "1"
}
}
POST test/_search
{
"query": {
"has_child": {
"type": "my_child",
"query": {
"match": {
"number": 1
}
},
"inner_hits": {}
}
}
}
ネストされた例のような内部ヒット定義。 |
上記の検索リクエストから生成される可能性のある応答スニペットの例:
コンソール-結果
{
...,
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "test",
"_id": "1",
"_score": 1.0,
"_source": {
"number": 1,
"my_join_field": "my_parent"
},
"inner_hits": {
"my_child": {
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "test",
"_id": "2",
"_score": 1.0,
"_routing": "1",
"_source": {
"number": 1,
"my_join_field": {
"name": "my_child",
"parent": "1"
}
}
}
]
}
}
}
}
]
}
}