Lookup Runtime Field　〜Elasticsearch 8.2 新機能〜

:::note warn
今回紹介する機能はElasticsearch 8.2ではTechnical Previewとしてのリリースです。将来変更となる可能性があります。
:::
# Lookup Runtime Fieldとは？
Elasticsearch 8.2新機能の一つであるLookup Runtime Fieldは、これまでもEnrich Policy + Ingest Pipelineで行っていた機能をRuntime Fieldで行えるようにしたものです。
Lookup自体はご存知の方が多いと思いますが、下記のように別のIndexから同じKeyを持つ別のFieldの値をとってくることです。
[公式のドキュメントはこちら](https://www.elastic.co/guide/en/elasticsearch/reference/8.2/runtime-retrieving-fields.html#lookup-runtime-fields)
![スクリーンショット 2022-06-15 12.08.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/f2a7f72a-7bd4-cec8-a7bf-a72c03c28a1b.png)

この例だと、Google Driveにアクセスしている社員を知りたいがログに社員氏名は当然記録されていないので、PC_name/host.nameをKeyにして資産管理DBから氏名を取ってくる、というものです。

# 環境作成
それでは実際に試してみましょう
Elasticsearchの環境が必要ですので、以下のリンクの手順に従ってまずはデプロイメントを作成してみてください。
[Elastic Cloud について　〜実際にデプロイメントを作ってみよう〜](https://qiita.com/tomo_s_el/items/3584d0b1fabb0bafa4fa)

# Dev Tools
デプロイメントが作成できたら早速Kibanaにアクセスして、Management -> Dev Toolsをクリックしましょう。
下図のような画面が開きます。
左側にクエリを記入して実行すると右側に結果が表示されます。
![スクリーンショット 2022-06-14 18.07.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2603229/86aa7cbe-babd-097e-ef76-dab4c804be55.png)

# テスト用のインデックスを作成
上の図にあるようなインデックスを作成します。
Dev Toolsの左側にコピーして実行(Mac: Command+Enter / Win: Ctrl+Enter)
## Lookup用の資産管理DB
```json
PUT pclist/_bulk
{ "index" : {} }
{"PC_name":"aaaa1","employee_name":"田中太郎"}
{ "index" : {} }
{"PC_name":"bbbb1","employee_name":"鈴木花子"}
```

## アクセスログ
```json
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のドキュメント](https://www.elastic.co/guide/en/elasticsearch/reference/8.2/docs-bulk.html)

# 検索してみよう！
それではGoogle Driveにアクセスしている社員をアクセスログから検索して表示してみましょう。
以下のクエリをDev Toolsで実行します。
```json
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のドキュメント](https://www.elastic.co/guide/en/elasticsearch/reference/8.2/runtime.html)
- 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
  これを指定しないとマッチしたドキュメントのすべてのフィールドが表示されます

## クエリ結果
このような結果が返ってきます
```json
{
  "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で実行してみましょう。
```json
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で実行すると以下のような結果が得られます。
```json
{
  "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 無料トライアル](https://cloud.elastic.co/)

手順は下記リンクをご参照ください
[Elastic Cloud について　〜実際にデプロイメントを作ってみよう〜](https://qiita.com/tomo_s_el/items/3584d0b1fabb0bafa4fa)