ランタイムフィールドのインデックス
ランタイムフィールドは、それが実行されるコンテキストによって定義されます。たとえば、検索クエリのコンテキストや、インデックスマッピングのruntime
セクション内でランタイムフィールドを定義できます。パフォーマンスを向上させるためにランタイムフィールドをインデックスすることを決定した場合は、完全なランタイムフィールド定義(スクリプトを含む)をインデックスマッピングのコンテキストに移動するだけです。Elasticsearchは自動的にこれらのインデックスフィールドを使用してクエリを実行し、迅速な応答時間を実現します。この機能により、スクリプトを一度だけ記述し、ランタイムフィールドをサポートする任意のコンテキストに適用できます。
その後、ランタイムフィールドを使用して、Elasticsearchが値を計算する必要があるフィールドの数を制限できます。インデックスフィールドとランタイムフィールドを併用することで、インデックスするデータと他のフィールドのクエリを定義する方法に柔軟性が提供されます。
ランタイムフィールドをインデックスした後、含まれているスクリプトを更新することはできません。スクリプトを変更する必要がある場合は、更新されたスクリプトを持つ新しいフィールドを作成してください。
たとえば、あなたの会社が古い圧力バルブを交換したいとします。接続されたセンサーは、真の読み取り値の一部しか報告できません。圧力バルブに新しいセンサーを取り付けるのではなく、報告された読み取り値に基づいて値を計算することに決めました。報告されたデータに基づいて、`````my-index-000001`````のマッピングに次のフィールドを定義します:
#### Python
``````python
resp = client.indices.create(
index="my-index-000001",
mappings={
"properties": {
"timestamp": {
"type": "date"
},
"temperature": {
"type": "long"
},
"voltage": {
"type": "double"
},
"node": {
"type": "keyword"
}
}
},
)
print(resp)
`
Ruby
response = client.indices.create(
index: 'my-index-000001',
body: {
mappings: {
properties: {
timestamp: {
type: 'date'
},
temperature: {
type: 'long'
},
voltage: {
type: 'double'
},
node: {
type: 'keyword'
}
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "my-index-000001",
mappings: {
properties: {
timestamp: {
type: "date",
},
temperature: {
type: "long",
},
voltage: {
type: "double",
},
node: {
type: "keyword",
},
},
},
});
console.log(response);
コンソール
PUT my-index-000001/
{
"mappings": {
"properties": {
"timestamp": {
"type": "date"
},
"temperature": {
"type": "long"
},
"voltage": {
"type": "double"
},
"node": {
"type": "keyword"
}
}
}
}
その後、センサーからのサンプルデータを一括インデックスします。このデータには、各センサーのvoltage
の読み取り値が含まれています:
Python
resp = client.bulk(
index="my-index-000001",
refresh=True,
operations=[
{
"index": {}
},
{
"timestamp": 1516729294000,
"temperature": 200,
"voltage": 5.2,
"node": "a"
},
{
"index": {}
},
{
"timestamp": 1516642894000,
"temperature": 201,
"voltage": 5.8,
"node": "b"
},
{
"index": {}
},
{
"timestamp": 1516556494000,
"temperature": 202,
"voltage": 5.1,
"node": "a"
},
{
"index": {}
},
{
"timestamp": 1516470094000,
"temperature": 198,
"voltage": 5.6,
"node": "b"
},
{
"index": {}
},
{
"timestamp": 1516383694000,
"temperature": 200,
"voltage": 4.2,
"node": "c"
},
{
"index": {}
},
{
"timestamp": 1516297294000,
"temperature": 202,
"voltage": 4,
"node": "c"
}
],
)
print(resp)
Ruby
response = client.bulk(
index: 'my-index-000001',
refresh: true,
body: [
{
index: {}
},
{
timestamp: 1_516_729_294_000,
temperature: 200,
voltage: 5.2,
node: 'a'
},
{
index: {}
},
{
timestamp: 1_516_642_894_000,
temperature: 201,
voltage: 5.8,
node: 'b'
},
{
index: {}
},
{
timestamp: 1_516_556_494_000,
temperature: 202,
voltage: 5.1,
node: 'a'
},
{
index: {}
},
{
timestamp: 1_516_470_094_000,
temperature: 198,
voltage: 5.6,
node: 'b'
},
{
index: {}
},
{
timestamp: 1_516_383_694_000,
temperature: 200,
voltage: 4.2,
node: 'c'
},
{
index: {}
},
{
timestamp: 1_516_297_294_000,
temperature: 202,
voltage: 4,
node: 'c'
}
]
)
puts response
Js
const response = await client.bulk({
index: "my-index-000001",
refresh: "true",
operations: [
{
index: {},
},
{
timestamp: 1516729294000,
temperature: 200,
voltage: 5.2,
node: "a",
},
{
index: {},
},
{
timestamp: 1516642894000,
temperature: 201,
voltage: 5.8,
node: "b",
},
{
index: {},
},
{
timestamp: 1516556494000,
temperature: 202,
voltage: 5.1,
node: "a",
},
{
index: {},
},
{
timestamp: 1516470094000,
temperature: 198,
voltage: 5.6,
node: "b",
},
{
index: {},
},
{
timestamp: 1516383694000,
temperature: 200,
voltage: 4.2,
node: "c",
},
{
index: {},
},
{
timestamp: 1516297294000,
temperature: 202,
voltage: 4,
node: "c",
},
],
});
console.log(response);
コンソール
POST my-index-000001/_bulk?refresh=true
{"index":{}}
{"timestamp": 1516729294000, "temperature": 200, "voltage": 5.2, "node": "a"}
{"index":{}}
{"timestamp": 1516642894000, "temperature": 201, "voltage": 5.8, "node": "b"}
{"index":{}}
{"timestamp": 1516556494000, "temperature": 202, "voltage": 5.1, "node": "a"}
{"index":{}}
{"timestamp": 1516470094000, "temperature": 198, "voltage": 5.6, "node": "b"}
{"index":{}}
{"timestamp": 1516383694000, "temperature": 200, "voltage": 4.2, "node": "c"}
{"index":{}}
{"timestamp": 1516297294000, "temperature": 202, "voltage": 4.0, "node": "c"}
数人の現場エンジニアと話した後、センサーは現在の値の少なくとも倍を報告する必要があることに気付きますが、さらに高くなる可能性があります。voltage_corrected
という名前のランタイムフィールドを作成し、現在の電圧を取得して2
で掛け算します:
Python
resp = client.indices.put_mapping(
index="my-index-000001",
runtime={
"voltage_corrected": {
"type": "double",
"script": {
"source": "\n emit(doc['voltage'].value * params['multiplier'])\n ",
"params": {
"multiplier": 2
}
}
}
},
)
print(resp)
Ruby
response = client.indices.put_mapping(
index: 'my-index-000001',
body: {
runtime: {
voltage_corrected: {
type: 'double',
script: {
source: "\n emit(doc['voltage'].value * params['multiplier'])\n ",
params: {
multiplier: 2
}
}
}
}
}
)
puts response
Js
const response = await client.indices.putMapping({
index: "my-index-000001",
runtime: {
voltage_corrected: {
type: "double",
script: {
source:
"\n emit(doc['voltage'].value * params['multiplier'])\n ",
params: {
multiplier: 2,
},
},
},
},
});
console.log(response);
コンソール
PUT my-index-000001/_mapping
{
"runtime": {
"voltage_corrected": {
"type": "double",
"script": {
"source": """
emit(doc['voltage'].value * params['multiplier'])
""",
"params": {
"multiplier": 2
}
}
}
}
}
計算された値は、_search
APIのfields
パラメータを使用して取得します:
Python
resp = client.search(
index="my-index-000001",
fields=[
"voltage_corrected",
"node"
],
size=2,
)
print(resp)
Ruby
response = client.search(
index: 'my-index-000001',
body: {
fields: [
'voltage_corrected',
'node'
],
size: 2
}
)
puts response
Js
const response = await client.search({
index: "my-index-000001",
fields: ["voltage_corrected", "node"],
size: 2,
});
console.log(response);
コンソール
GET my-index-000001/_search
{
"fields": [
"voltage_corrected",
"node"
],
"size": 2
}
センサーデータをレビューし、いくつかのテストを実行した後、報告されたセンサーデータの乗数は4
であるべきだと判断します。パフォーマンスを向上させるために、voltage_corrected
ランタイムフィールドを新しいmultiplier
パラメータでインデックスすることに決めました。
新しいインデックスmy-index-000001
に、voltage_corrected
ランタイムフィールドの定義を新しいインデックスのマッピングにコピーします。それはそれだけです!スクリプトがインデックス時にエラーをスローした場合に、ドキュメント全体を拒否するかどうかを決定するオプションのパラメータon_script_error
を追加できます(デフォルト)。
Python
resp = client.indices.create(
index="my-index-000001",
mappings={
"properties": {
"timestamp": {
"type": "date"
},
"temperature": {
"type": "long"
},
"voltage": {
"type": "double"
},
"node": {
"type": "keyword"
},
"voltage_corrected": {
"type": "double",
"on_script_error": "fail",
"script": {
"source": "\n emit(doc['voltage'].value * params['multiplier'])\n ",
"params": {
"multiplier": 4
}
}
}
}
},
)
print(resp)
Ruby
response = client.indices.create(
index: 'my-index-000001',
body: {
mappings: {
properties: {
timestamp: {
type: 'date'
},
temperature: {
type: 'long'
},
voltage: {
type: 'double'
},
node: {
type: 'keyword'
},
voltage_corrected: {
type: 'double',
on_script_error: 'fail',
script: {
source: "\n emit(doc['voltage'].value * params['multiplier'])\n ",
params: {
multiplier: 4
}
}
}
}
}
}
)
puts response
Js
const response = await client.indices.create({
index: "my-index-000001",
mappings: {
properties: {
timestamp: {
type: "date",
},
temperature: {
type: "long",
},
voltage: {
type: "double",
},
node: {
type: "keyword",
},
voltage_corrected: {
type: "double",
on_script_error: "fail",
script: {
source:
"\n emit(doc['voltage'].value * params['multiplier'])\n ",
params: {
multiplier: 4,
},
},
},
},
},
});
console.log(response);
コンソール
PUT my-index-000001/
{
"mappings": {
"properties": {
"timestamp": {
"type": "date"
},
"temperature": {
"type": "long"
},
"voltage": {
"type": "double"
},
"node": {
"type": "keyword"
},
"voltage_corrected": {
"type": "double",
"on_script_error": "fail",
"script": {
"source": """
emit(doc['voltage'].value * params['multiplier'])
""",
"params": {
"multiplier": 4
}
}
}
}
}
}
スクリプトがインデックス時にエラーをスローした場合、ドキュメント全体が拒否されます。値をignore に設定すると、フィールドがドキュメントの_ignored メタデータフィールドに登録され、インデックスが続行されます。 |
センサーからのサンプルデータをmy-index-000001
インデックスに一括インデックスします:
Python
resp = client.bulk(
index="my-index-000001",
refresh=True,
operations=[
{
"index": {}
},
{
"timestamp": 1516729294000,
"temperature": 200,
"voltage": 5.2,
"node": "a"
},
{
"index": {}
},
{
"timestamp": 1516642894000,
"temperature": 201,
"voltage": 5.8,
"node": "b"
},
{
"index": {}
},
{
"timestamp": 1516556494000,
"temperature": 202,
"voltage": 5.1,
"node": "a"
},
{
"index": {}
},
{
"timestamp": 1516470094000,
"temperature": 198,
"voltage": 5.6,
"node": "b"
},
{
"index": {}
},
{
"timestamp": 1516383694000,
"temperature": 200,
"voltage": 4.2,
"node": "c"
},
{
"index": {}
},
{
"timestamp": 1516297294000,
"temperature": 202,
"voltage": 4,
"node": "c"
}
],
)
print(resp)
Ruby
response = client.bulk(
index: 'my-index-000001',
refresh: true,
body: [
{
index: {}
},
{
timestamp: 1_516_729_294_000,
temperature: 200,
voltage: 5.2,
node: 'a'
},
{
index: {}
},
{
timestamp: 1_516_642_894_000,
temperature: 201,
voltage: 5.8,
node: 'b'
},
{
index: {}
},
{
timestamp: 1_516_556_494_000,
temperature: 202,
voltage: 5.1,
node: 'a'
},
{
index: {}
},
{
timestamp: 1_516_470_094_000,
temperature: 198,
voltage: 5.6,
node: 'b'
},
{
index: {}
},
{
timestamp: 1_516_383_694_000,
temperature: 200,
voltage: 4.2,
node: 'c'
},
{
index: {}
},
{
timestamp: 1_516_297_294_000,
temperature: 202,
voltage: 4,
node: 'c'
}
]
)
puts response
Js
const response = await client.bulk({
index: "my-index-000001",
refresh: "true",
operations: [
{
index: {},
},
{
timestamp: 1516729294000,
temperature: 200,
voltage: 5.2,
node: "a",
},
{
index: {},
},
{
timestamp: 1516642894000,
temperature: 201,
voltage: 5.8,
node: "b",
},
{
index: {},
},
{
timestamp: 1516556494000,
temperature: 202,
voltage: 5.1,
node: "a",
},
{
index: {},
},
{
timestamp: 1516470094000,
temperature: 198,
voltage: 5.6,
node: "b",
},
{
index: {},
},
{
timestamp: 1516383694000,
temperature: 200,
voltage: 4.2,
node: "c",
},
{
index: {},
},
{
timestamp: 1516297294000,
temperature: 202,
voltage: 4,
node: "c",
},
],
});
console.log(response);
コンソール
POST my-index-000001/_bulk?refresh=true
{ "index": {}}
{ "timestamp": 1516729294000, "temperature": 200, "voltage": 5.2, "node": "a"}
{ "index": {}}
{ "timestamp": 1516642894000, "temperature": 201, "voltage": 5.8, "node": "b"}
{ "index": {}}
{ "timestamp": 1516556494000, "temperature": 202, "voltage": 5.1, "node": "a"}
{ "index": {}}
{ "timestamp": 1516470094000, "temperature": 198, "voltage": 5.6, "node": "b"}
{ "index": {}}
{ "timestamp": 1516383694000, "temperature": 200, "voltage": 4.2, "node": "c"}
{ "index": {}}
{ "timestamp": 1516297294000, "temperature": 202, "voltage": 4.0, "node": "c"}
検索クエリで計算された値を取得できるようになり、正確な値に基づいてドキュメントを見つけることができます。次の範囲クエリは、計算されたvoltage_corrected
が16
以上、20
以下のすべてのドキュメントを返します。再度、fields
パラメータを_search
APIで使用して、必要なフィールドを取得します:
Python
resp = client.search(
index="my-index-000001",
query={
"range": {
"voltage_corrected": {
"gte": 16,
"lte": 20,
"boost": 1
}
}
},
fields=[
"voltage_corrected",
"node"
],
)
print(resp)
Js
const response = await client.search({
index: "my-index-000001",
query: {
range: {
voltage_corrected: {
gte: 16,
lte: 20,
boost: 1,
},
},
},
fields: ["voltage_corrected", "node"],
});
console.log(response);
コンソール
POST my-index-000001/_search
{
"query": {
"range": {
"voltage_corrected": {
"gte": 16,
"lte": 20,
"boost": 1.0
}
}
},
"fields": ["voltage_corrected", "node"]
}
応答には、計算された値に基づいて範囲クエリに一致するドキュメントのvoltage_corrected
フィールドが含まれます:
コンソール-結果
{
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "my-index-000001",
"_id" : "yoSLrHgBdg9xpPrUZz_P",
"_score" : 1.0,
"_source" : {
"timestamp" : 1516383694000,
"temperature" : 200,
"voltage" : 4.2,
"node" : "c"
},
"fields" : {
"voltage_corrected" : [
16.8
],
"node" : [
"c"
]
}
},
{
"_index" : "my-index-000001",
"_id" : "y4SLrHgBdg9xpPrUZz_P",
"_score" : 1.0,
"_source" : {
"timestamp" : 1516297294000,
"temperature" : 202,
"voltage" : 4.0,
"node" : "c"
},
"fields" : {
"voltage_corrected" : [
16.0
],
"node" : [
"c"
]
}
}
]
}
}