ランタイムフィールドを取得する
fields
パラメータを _search
API で使用して、ランタイムフィールドの値を取得します。ランタイムフィールドは _source
に表示されませんが、fields
API は、元の _source
の一部として送信されなかったフィールドを含むすべてのフィールドに対して機能します。
曜日を計算するランタイムフィールドを定義する
例えば、以下のリクエストは day_of_week
というランタイムフィールドを追加します。このランタイムフィールドには、@timestamp
フィールドの値に基づいて曜日を計算するスクリプトが含まれています。新しいフィールドがランタイムフィールドとしてマッピングに追加されるように、リクエストに "dynamic":"runtime"
を含めます。
Python
resp = client.indices.create(
index="my-index-000001",
mappings={
"dynamic": "runtime",
"runtime": {
"day_of_week": {
"type": "keyword",
"script": {
"source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ENGLISH))"
}
}
},
"properties": {
"@timestamp": {
"type": "date"
}
}
},
)
print(resp)
Js
const response = await client.indices.create({
index: "my-index-000001",
mappings: {
dynamic: "runtime",
runtime: {
day_of_week: {
type: "keyword",
script: {
source:
"emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ENGLISH))",
},
},
},
properties: {
"@timestamp": {
type: "date",
},
},
},
});
console.log(response);
Console
PUT my-index-000001/
{
"mappings": {
"dynamic": "runtime",
"runtime": {
"day_of_week": {
"type": "keyword",
"script": {
"source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ENGLISH))"
}
}
},
"properties": {
"@timestamp": {"type": "date"}
}
}
}
データを取り込む
サンプルデータを取り込み、@timestamp
と message
の2つのインデックスフィールドを生成します。
Python
resp = client.bulk(
index="my-index-000001",
refresh=True,
operations=[
{
"index": {}
},
{
"@timestamp": "2020-06-21T15:00:01-05:00",
"message": "211.11.9.0 - - [2020-06-21T15:00:01-05:00] \"GET /english/index.html HTTP/1.0\" 304 0"
},
{
"index": {}
},
{
"@timestamp": "2020-06-21T15:00:01-05:00",
"message": "211.11.9.0 - - [2020-06-21T15:00:01-05:00] \"GET /english/index.html HTTP/1.0\" 304 0"
},
{
"index": {}
},
{
"@timestamp": "2020-04-30T14:30:17-05:00",
"message": "40.135.0.0 - - [2020-04-30T14:30:17-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
},
{
"index": {}
},
{
"@timestamp": "2020-04-30T14:30:53-05:00",
"message": "232.0.0.0 - - [2020-04-30T14:30:53-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
},
{
"index": {}
},
{
"@timestamp": "2020-04-30T14:31:12-05:00",
"message": "26.1.0.0 - - [2020-04-30T14:31:12-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
},
{
"index": {}
},
{
"@timestamp": "2020-04-30T14:31:19-05:00",
"message": "247.37.0.0 - - [2020-04-30T14:31:19-05:00] \"GET /french/splash_inet.html HTTP/1.0\" 200 3781"
},
{
"index": {}
},
{
"@timestamp": "2020-04-30T14:31:27-05:00",
"message": "252.0.0.0 - - [2020-04-30T14:31:27-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"
},
{
"index": {}
},
{
"@timestamp": "2020-04-30T14:31:29-05:00",
"message": "247.37.0.0 - - [2020-04-30T14:31:29-05:00] \"GET /images/hm_brdl.gif HTTP/1.0\" 304 0"
},
{
"index": {}
},
{
"@timestamp": "2020-04-30T14:31:29-05:00",
"message": "247.37.0.0 - - [2020-04-30T14:31:29-05:00] \"GET /images/hm_arw.gif HTTP/1.0\" 304 0"
},
{
"index": {}
},
{
"@timestamp": "2020-04-30T14:31:32-05:00",
"message": "247.37.0.0 - - [2020-04-30T14:31:32-05:00] \"GET /images/nav_bg_top.gif HTTP/1.0\" 200 929"
},
{
"index": {}
},
{
"@timestamp": "2020-04-30T14:31:43-05:00",
"message": "247.37.0.0 - - [2020-04-30T14:31:43-05:00] \"GET /french/images/nav_venue_off.gif HTTP/1.0\" 304 0"
}
],
)
print(resp)
Ruby
response = client.bulk(
index: 'my-index-000001',
refresh: true,
body: [
{
index: {}
},
{
"@timestamp": '2020-06-21T15:00:01-05:00',
message: '211.11.9.0 - - [2020-06-21T15:00:01-05:00] "GET /english/index.html HTTP/1.0" 304 0'
},
{
index: {}
},
{
"@timestamp": '2020-06-21T15:00:01-05:00',
message: '211.11.9.0 - - [2020-06-21T15:00:01-05:00] "GET /english/index.html HTTP/1.0" 304 0'
},
{
index: {}
},
{
"@timestamp": '2020-04-30T14:30:17-05:00',
message: '40.135.0.0 - - [2020-04-30T14:30:17-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736'
},
{
index: {}
},
{
"@timestamp": '2020-04-30T14:30:53-05:00',
message: '232.0.0.0 - - [2020-04-30T14:30:53-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736'
},
{
index: {}
},
{
"@timestamp": '2020-04-30T14:31:12-05:00',
message: '26.1.0.0 - - [2020-04-30T14:31:12-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736'
},
{
index: {}
},
{
"@timestamp": '2020-04-30T14:31:19-05:00',
message: '247.37.0.0 - - [2020-04-30T14:31:19-05:00] "GET /french/splash_inet.html HTTP/1.0" 200 3781'
},
{
index: {}
},
{
"@timestamp": '2020-04-30T14:31:27-05:00',
message: '252.0.0.0 - - [2020-04-30T14:31:27-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736'
},
{
index: {}
},
{
"@timestamp": '2020-04-30T14:31:29-05:00',
message: '247.37.0.0 - - [2020-04-30T14:31:29-05:00] "GET /images/hm_brdl.gif HTTP/1.0" 304 0'
},
{
index: {}
},
{
"@timestamp": '2020-04-30T14:31:29-05:00',
message: '247.37.0.0 - - [2020-04-30T14:31:29-05:00] "GET /images/hm_arw.gif HTTP/1.0" 304 0'
},
{
index: {}
},
{
"@timestamp": '2020-04-30T14:31:32-05:00',
message: '247.37.0.0 - - [2020-04-30T14:31:32-05:00] "GET /images/nav_bg_top.gif HTTP/1.0" 200 929'
},
{
index: {}
},
{
"@timestamp": '2020-04-30T14:31:43-05:00',
message: '247.37.0.0 - - [2020-04-30T14:31:43-05:00] "GET /french/images/nav_venue_off.gif HTTP/1.0" 304 0'
}
]
)
puts response
Js
const response = await client.bulk({
index: "my-index-000001",
refresh: "true",
operations: [
{
index: {},
},
{
"@timestamp": "2020-06-21T15:00:01-05:00",
message:
'211.11.9.0 - - [2020-06-21T15:00:01-05:00] "GET /english/index.html HTTP/1.0" 304 0',
},
{
index: {},
},
{
"@timestamp": "2020-06-21T15:00:01-05:00",
message:
'211.11.9.0 - - [2020-06-21T15:00:01-05:00] "GET /english/index.html HTTP/1.0" 304 0',
},
{
index: {},
},
{
"@timestamp": "2020-04-30T14:30:17-05:00",
message:
'40.135.0.0 - - [2020-04-30T14:30:17-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736',
},
{
index: {},
},
{
"@timestamp": "2020-04-30T14:30:53-05:00",
message:
'232.0.0.0 - - [2020-04-30T14:30:53-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736',
},
{
index: {},
},
{
"@timestamp": "2020-04-30T14:31:12-05:00",
message:
'26.1.0.0 - - [2020-04-30T14:31:12-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736',
},
{
index: {},
},
{
"@timestamp": "2020-04-30T14:31:19-05:00",
message:
'247.37.0.0 - - [2020-04-30T14:31:19-05:00] "GET /french/splash_inet.html HTTP/1.0" 200 3781',
},
{
index: {},
},
{
"@timestamp": "2020-04-30T14:31:27-05:00",
message:
'252.0.0.0 - - [2020-04-30T14:31:27-05:00] "GET /images/hm_bg.jpg HTTP/1.0" 200 24736',
},
{
index: {},
},
{
"@timestamp": "2020-04-30T14:31:29-05:00",
message:
'247.37.0.0 - - [2020-04-30T14:31:29-05:00] "GET /images/hm_brdl.gif HTTP/1.0" 304 0',
},
{
index: {},
},
{
"@timestamp": "2020-04-30T14:31:29-05:00",
message:
'247.37.0.0 - - [2020-04-30T14:31:29-05:00] "GET /images/hm_arw.gif HTTP/1.0" 304 0',
},
{
index: {},
},
{
"@timestamp": "2020-04-30T14:31:32-05:00",
message:
'247.37.0.0 - - [2020-04-30T14:31:32-05:00] "GET /images/nav_bg_top.gif HTTP/1.0" 200 929',
},
{
index: {},
},
{
"@timestamp": "2020-04-30T14:31:43-05:00",
message:
'247.37.0.0 - - [2020-04-30T14:31:43-05:00] "GET /french/images/nav_venue_off.gif HTTP/1.0" 304 0',
},
],
});
console.log(response);
Console
POST /my-index-000001/_bulk?refresh
{ "index": {}}
{ "@timestamp": "2020-06-21T15:00:01-05:00", "message" : "211.11.9.0 - - [2020-06-21T15:00:01-05:00] \"GET /english/index.html HTTP/1.0\" 304 0"}
{ "index": {}}
{ "@timestamp": "2020-06-21T15:00:01-05:00", "message" : "211.11.9.0 - - [2020-06-21T15:00:01-05:00] \"GET /english/index.html HTTP/1.0\" 304 0"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:30:17-05:00", "message" : "40.135.0.0 - - [2020-04-30T14:30:17-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:30:53-05:00", "message" : "232.0.0.0 - - [2020-04-30T14:30:53-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:12-05:00", "message" : "26.1.0.0 - - [2020-04-30T14:31:12-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:19-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:19-05:00] \"GET /french/splash_inet.html HTTP/1.0\" 200 3781"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:27-05:00", "message" : "252.0.0.0 - - [2020-04-30T14:31:27-05:00] \"GET /images/hm_bg.jpg HTTP/1.0\" 200 24736"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:29-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:29-05:00] \"GET /images/hm_brdl.gif HTTP/1.0\" 304 0"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:29-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:29-05:00] \"GET /images/hm_arw.gif HTTP/1.0\" 304 0"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:32-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:32-05:00] \"GET /images/nav_bg_top.gif HTTP/1.0\" 200 929"}
{ "index": {}}
{ "@timestamp": "2020-04-30T14:31:43-05:00", "message" : "247.37.0.0 - - [2020-04-30T14:31:43-05:00] \"GET /french/images/nav_venue_off.gif HTTP/1.0\" 304 0"}
計算された曜日を検索する
以下のリクエストは、元のリクエストでマッピング内のランタイムフィールドとして定義された day_of_week
フィールドを取得するために検索APIを使用します。このフィールドの値は、ドキュメントを再インデックス化したり、day_of_week
フィールドをインデックス化したりすることなく、クエリ時に動的に計算されます。この柔軟性により、フィールドの値を変更することなくマッピングを変更できます。
Python
resp = client.search(
index="my-index-000001",
fields=[
"@timestamp",
"day_of_week"
],
source=False,
)
print(resp)
Ruby
response = client.search(
index: 'my-index-000001',
body: {
fields: [
'@timestamp',
'day_of_week'
],
_source: false
}
)
puts response
Js
const response = await client.search({
index: "my-index-000001",
fields: ["@timestamp", "day_of_week"],
_source: false,
});
console.log(response);
Console
GET my-index-000001/_search
{
"fields": [
"@timestamp",
"day_of_week"
],
"_source": false
}
前のリクエストは、すべての一致するドキュメントに対して day_of_week
フィールドを返します。client_ip
という別のランタイムフィールドを定義することもでき、message
フィールドに対しても操作し、クエリをさらに絞り込むことができます:
Python
resp = client.indices.put_mapping(
index="my-index-000001",
runtime={
"client_ip": {
"type": "ip",
"script": {
"source": "String m = doc[\"message\"].value; int end = m.indexOf(\" \"); emit(m.substring(0, end));"
}
}
},
)
print(resp)
Ruby
response = client.indices.put_mapping(
index: 'my-index-000001',
body: {
runtime: {
client_ip: {
type: 'ip',
script: {
source: 'String m = doc["message"].value; int end = m.indexOf(" "); emit(m.substring(0, end));'
}
}
}
}
)
puts response
Js
const response = await client.indices.putMapping({
index: "my-index-000001",
runtime: {
client_ip: {
type: "ip",
script: {
source:
'String m = doc["message"].value; int end = m.indexOf(" "); emit(m.substring(0, end));',
},
},
},
});
console.log(response);
Console
PUT /my-index-000001/_mapping
{
"runtime": {
"client_ip": {
"type": "ip",
"script" : {
"source" : "String m = doc[\"message\"].value; int end = m.indexOf(\" \"); emit(m.substring(0, end));"
}
}
}
}
別のクエリを実行しますが、client_ip
ランタイムフィールドを使用して特定のIPアドレスを検索します:
Python
resp = client.search(
index="my-index-000001",
size=1,
query={
"match": {
"client_ip": "211.11.9.0"
}
},
fields=[
"*"
],
)
print(resp)
Js
const response = await client.search({
index: "my-index-000001",
size: 1,
query: {
match: {
client_ip: "211.11.9.0",
},
},
fields: ["*"],
});
console.log(response);
Console
GET my-index-000001/_search
{
"size": 1,
"query": {
"match": {
"client_ip": "211.11.9.0"
}
},
"fields" : ["*"]
}
今回は、応答には2つのヒットのみが含まれます。day_of_week
(Sunday
) の値は、マッピングで定義されたランタイムスクリプトを使用してクエリ時に計算され、結果には 211.11.9.0
IPアドレスに一致するドキュメントのみが含まれます。
Console-Result
{
...
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "my-index-000001",
"_id" : "oWs5KXYB-XyJbifr9mrz",
"_score" : 1.0,
"_source" : {
"@timestamp" : "2020-06-21T15:00:01-05:00",
"message" : "211.11.9.0 - - [2020-06-21T15:00:01-05:00] \"GET /english/index.html HTTP/1.0\" 304 0"
},
"fields" : {
"@timestamp" : [
"2020-06-21T20:00:01.000Z"
],
"client_ip" : [
"211.11.9.0"
],
"message" : [
"211.11.9.0 - - [2020-06-21T15:00:01-05:00] \"GET /english/index.html HTTP/1.0\" 304 0"
],
"day_of_week" : [
"Sunday"
]
}
}
]
}
}
関連インデックスからフィールドを取得する
この機能は技術プレビュー中であり、将来のリリースで変更または削除される可能性があります。Elasticは問題を修正するために取り組みますが、技術プレビューの機能は公式GA機能のサポートSLAの対象ではありません。
fields
パラメータは、_search
API で、lookup
タイプのランタイムフィールドを介して関連インデックスからフィールドを取得するためにも使用できます。
lookup
タイプのランタイムフィールドによって取得されたフィールドは、検索応答のヒットを強化するために使用できます。これらのフィールドに対してクエリや集計を行うことはできません。
Python
resp = client.index(
index="ip_location",
refresh=True,
document={
"ip": "192.168.1.1",
"country": "Canada",
"city": "Montreal"
},
)
print(resp)
resp1 = client.index(
index="logs",
id="1",
refresh=True,
document={
"host": "192.168.1.1",
"message": "the first message"
},
)
print(resp1)
resp2 = client.index(
index="logs",
id="2",
refresh=True,
document={
"host": "192.168.1.2",
"message": "the second message"
},
)
print(resp2)
resp3 = client.search(
index="logs",
runtime_mappings={
"location": {
"type": "lookup",
"target_index": "ip_location",
"input_field": "host",
"target_field": "ip",
"fetch_fields": [
"country",
"city"
]
}
},
fields=[
"host",
"message",
"location"
],
source=False,
)
print(resp3)
Ruby
response = client.index(
index: 'ip_location',
refresh: true,
body: {
ip: '192.168.1.1',
country: 'Canada',
city: 'Montreal'
}
)
puts response
response = client.index(
index: 'logs',
id: 1,
refresh: true,
body: {
host: '192.168.1.1',
message: 'the first message'
}
)
puts response
response = client.index(
index: 'logs',
id: 2,
refresh: true,
body: {
host: '192.168.1.2',
message: 'the second message'
}
)
puts response
response = client.search(
index: 'logs',
body: {
runtime_mappings: {
location: {
type: 'lookup',
target_index: 'ip_location',
input_field: 'host',
target_field: 'ip',
fetch_fields: [
'country',
'city'
]
}
},
fields: [
'host',
'message',
'location'
],
_source: false
}
)
puts response
Js
const response = await client.index({
index: "ip_location",
refresh: "true",
document: {
ip: "192.168.1.1",
country: "Canada",
city: "Montreal",
},
});
console.log(response);
const response1 = await client.index({
index: "logs",
id: 1,
refresh: "true",
document: {
host: "192.168.1.1",
message: "the first message",
},
});
console.log(response1);
const response2 = await client.index({
index: "logs",
id: 2,
refresh: "true",
document: {
host: "192.168.1.2",
message: "the second message",
},
});
console.log(response2);
const response3 = await client.search({
index: "logs",
runtime_mappings: {
location: {
type: "lookup",
target_index: "ip_location",
input_field: "host",
target_field: "ip",
fetch_fields: ["country", "city"],
},
},
fields: ["host", "message", "location"],
_source: false,
});
console.log(response3);
Console
POST ip_location/_doc?refresh
{
"ip": "192.168.1.1",
"country": "Canada",
"city": "Montreal"
}
PUT logs/_doc/1?refresh
{
"host": "192.168.1.1",
"message": "the first message"
}
PUT logs/_doc/2?refresh
{
"host": "192.168.1.2",
"message": "the second message"
}
POST logs/_search
{
"runtime_mappings": {
"location": {
"type": "lookup",
"target_index": "ip_location",
"input_field": "host",
"target_field": "ip",
"fetch_fields": ["country", "city"]
}
},
"fields": [
"host",
"message",
"location"
],
"_source": false
}
lookup クエリを使用してターゲットインデックスからフィールドを取得するランタイムフィールドをメイン検索リクエストで定義します。 |
|
ルックアップクエリが実行されるターゲットインデックス | |
ルックアップタームクエリの入力値として使用されるメインインデックスのフィールド | |
ルックアップクエリが検索するルックアップインデックスのフィールド | |
ルックアップインデックスから取得するフィールドのリスト。検索リクエストの fields パラメータを参照してください。 |
上記の検索は、返された検索ヒットの各IPアドレスに対して ip_location
インデックスから国と都市を返します。
Console-Result
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "logs",
"_id": "1",
"_score": 1.0,
"fields": {
"host": [ "192.168.1.1" ],
"location": [
{
"city": [ "Montreal" ],
"country": [ "Canada" ]
}
],
"message": [ "the first message" ]
}
},
{
"_index": "logs",
"_id": "2",
"_score": 1.0,
"fields": {
"host": [ "192.168.1.2" ],
"message": [ "the second message" ]
}
}
]
}
}
ルックアップフィールドの応答は、ルックアップインデックスから各ドキュメントの独立性を維持するためにグループ化されます。各入力値のルックアップクエリは、ルックアップインデックス上で最大1つのドキュメントに一致することが期待されます。ルックアップクエリが複数のドキュメントに一致する場合、ランダムなドキュメントが選択されます。