今回紹介する機能はElasticsearch 8.2ではTechnical Previewとしてのリリースです。将来変更となる可能性があります。
Lookup Runtime Fieldとは?
Elasticsearch 8.2新機能の一つであるLookup Runtime Fieldは、これまでもEnrich Policy + Ingest Pipelineで行っていた機能をRuntime Fieldで行えるようにしたものです。
Lookup自体はご存知の方が多いと思いますが、下記のように別のIndexから同じKeyを持つ別のFieldの値をとってくることです。
公式のドキュメントはこちら
この例だと、Google Driveにアクセスしている社員を知りたいがログに社員氏名は当然記録されていないので、PC_name/host.nameをKeyにして資産管理DBから氏名を取ってくる、というものです。
環境作成
それでは実際に試してみましょう
Elasticsearchの環境が必要ですので、以下のリンクの手順に従ってまずはデプロイメントを作成してみてください。
Elastic Cloud について 〜実際にデプロイメントを作ってみよう〜
Dev Tools
デプロイメントが作成できたら早速Kibanaにアクセスして、Management -> Dev Toolsをクリックしましょう。
下図のような画面が開きます。
左側にクエリを記入して実行すると右側に結果が表示されます。
テスト用のインデックスを作成
上の図にあるようなインデックスを作成します。
Dev Toolsの左側にコピーして実行(Mac: Command+Enter / Win: Ctrl+Enter)
Lookup用の資産管理DB
PUT pclist/_bulk
{ "index" : {} }
{"PC_name":"aaaa1","employee_name":"田中太郎"}
{ "index" : {} }
{"PC_name":"bbbb1","employee_name":"鈴木花子"}
アクセスログ
PUT accesslog/_bulk
{ "index" : {} }
{"host.name":"aaaa1","access_to":"Google Drive"}
{ "index" : {} }
{"host.name":"bbbb1","access_to":"Qiita Web Site"}
_bulk
APIは複数のデータをまとめて投入したい時に重宝するAPIです。
興味のある方はこちらを是非ご覧ください。
_bulk
APIのドキュメント
検索してみよう!
それではGoogle Driveにアクセスしている社員をアクセスログから検索して表示してみましょう。
以下のクエリをDev Toolsで実行します。
GET accesslog/_search
{
"runtime_mappings": {
"emp_name": {
"type": "lookup",
"target_index": "pclist",
"input_field": "host.name",
"target_field": "PC_name",
"fetch_fields": ["employee_name"]
}
},
"query": {"match": {
"access_to": "google"
}},
"fields": [
"host.name","access_to","emp_name"
],
"_source": false
}
クエリの中身
- runtime_mappings
accesslog
には社員名のマッピングは存在しないためクエリと同時にruntimeとして作成します
runtimeはクエリ時に作成される情報のことです。詳しくはこちら。
runtime fieldのドキュメント - emp_name
社員名を格納するフィールド名 - "type": "lookup"
lookup
して他のインデックスを参照しに行くことを明示します。type
には他にはtext
やgeo_point
などがあります。 - "target_index": "pclist"
lookupしに行くインデックスを指定します。今回だと資産管理DBであるpclist
です - "input_field": "host.name"
lookupで突合するフィールドを指定します。今回だとaccesslog
のhost.name
をpc_list
のPC_name
と突合させますので、inputとしてhost.name
を指定します - "target_field": "PC_name"
上記の説明通りです - "fetch_fields": ["employee_name"]
突合した結果として参照するフィールドを指定します。複数指定できます。 - query
accesslog
のaccess_to
フィールドが"google"にマッチするもの - fields
結果として表示するフィールドを指定 - "_source": false
これを指定しないとマッチしたドキュメントのすべてのフィールドが表示されます
クエリ結果
このような結果が返ってきます
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.7549127,
"hits" : [
{
"_index" : "accesslog",
"_id" : "vuhmYYEBidyf9EvSKJLI",
"_score" : 0.7549127,
"fields" : {
"emp_name" : [
{
"employee_name" : [
"田中太郎"
]
}
],
"access_to" : [
"Google Drive"
],
"host.name" : [
"aaaa1"
]
}
}
]
}
}
accesslog
インデックスには社員名は入っていませんが、aaaa1
というPCを使用している社員が「田中太郎」であることをpclist
から取ってきているのがわかります。
runtime mapping
検索時に毎回指定するのは面倒臭いと思われる方もいらっしゃるでしょう。そんな方には予めruntimeをmappingしておく方法もご紹介いたします。
PUT <index名>/_mapping
で明示的に指定することができます。
以下をDev Toolsで実行してみましょう。
PUT accesslog/_mapping
{
"runtime": {
"emp_name": {
"type": "lookup",
"target_index": "pclist",
"input_field": "host.name",
"target_field": "PC_name",
"fetch_fields": ["employee_name"]
}
}
}
先ほどクエリ時に指定したruntime_mappings
と全く同じ内容です。
ではaccesslog
のmappingはどのようになっているでしょうか?
GET accesslog/_mapping
をDev Toolsで実行すると以下のような結果が得られます。
{
"accesslog" : {
"mappings" : {
"runtime" : {
"emp_name" : {
"type" : "lookup",
"target_index" : "pclist",
"input_field" : "host.name",
"target_field" : "PC_name",
"fetch_fields" : [
{
"field" : "employee_name"
}
]
}
},
"properties" : {
"access_to" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"host" : {
"properties" : {
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
}
}
properties
以下は一番最初にインデックスを作成した時に自動的に作成されたものです。
runtime
部分が追加されており、クエリ時にlookupが行われます。
これによりクエリ時にruntime_mappings
を指定する必要がなくなります。
注意点
同じkeyが複数ある場合、例えばaaaa1
というPCの所有者情報として、現在は「田中太郎」だがその前に「佐藤一郎」が使用していてその情報が残ったまま、というケースがあてはまります。このような場合は「田中太郎」が返ってくるか「佐藤一郎」が返ってくるかはランダムです。
またlookup runtimeに対してqueryやaggregationを行えません。
上記の例ですとaccesslog
に対して検索をかけるときに、emp_name.employee_name
フィールドに「田中太郎」と指定したりすることはできません。
lookup 先の値で検索したい場合は、依然として enrich processor を利用したり、 Elasticsearch に取り込む前に JSON に enrich しておく必要があります。
用途に応じてlookupとenrich processorを使い分けましょう。
まとめ
これまではEnrich Processor + Ingest Pipelineでインデックスとして作成しなければできなかったことがクエリ時に行えるようになり、データが頻繁に変更される場合にもLookupが行えるようになりました。
是非ともお試しください。
Elastic Cloud 無料トライアル
こちらからElastic Cloudの14日間無料トライアルを是非お試しください
Elastic Cloud 無料トライアル
手順は下記リンクをご参照ください
Elastic Cloud について 〜実際にデプロイメントを作ってみよう〜