ElasticSearch（kuromoji）で日本語検索する

# 前提
- ElasticSearch 7.17.6
- 本記事のゴールは、text タイプのフィールドに日本語を入れて検索するところまで

```bash
$ sw_vers
ProductName:	macOS
ProductVersion:	12.3.1
BuildVersion:	21E258

$ docker -v
Docker version 20.10.11, build dea9396
```



# 導入
```bash
# Elasticsearch
$ docker network create elastic
$ docker pull docker.elastic.co/elasticsearch/elasticsearch:7.17.6
$ docker run --detach --name es01-test --net elastic -p 127.0.0.1:9200:9200 -p 127.0.0.1:9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.17.6

# Kibana
$ docker pull docker.elastic.co/kibana/kibana:7.17.6
$ docker run --detach --name kib01-test --net elastic -p 127.0.0.1:5601:5601 -e "ELASTICSEARCH_HOSTS=http://es01-test:9200" docker.elastic.co/kibana/kibana:7.17.6


# 補足
# コンテナ稼働状況の確認
# 停止含めて確認したい場合は、`--all` を付ける
$ docker ps

# コンテナ稼働（バックグラウンド実行）/停止
$ docker start [name]
$ docker stop [name]
```

http://localhost:5601 にアクセスできれば OK



# 実態確認
[構成要素](https://qiita.com/1592/items/97da0916947a5f34668d#%E6%A7%8B%E6%88%90%E8%A6%81%E7%B4%A0)について確認してみる

人が見やすいテキスト形式で出力してくれる [CAT API](https://www.elastic.co/guide/en/elasticsearch/reference/7.17/cat.html) を中心に見ていく

Kibana の `Dev Tools > Console` から API を実行できる

```bash
# ※以降のコマンド実行は、後で作成する sample_index がある前提


# クラスタの動作確認
# https://www.elastic.co/guide/en/elasticsearch/reference/7.17/cat-health.html
GET _cat/health?v
=>
epoch      timestamp cluster        status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1666620359 14:05:59  docker-cluster yellow          1         1     10  10    0    0        1             0                  -                 90.9%


# ノードの確認
# https://www.elastic.co/guide/en/elasticsearch/reference/7.17/cat-nodes.html
GET _cat/nodes?v
=>
ip         heap.percent ram.percent cpu load_1m load_5m load_15m node.role   master name
172.19.0.2           49          96   5    0.32    0.27     0.27 cdfhilmrstw *      adee89610057


# インデックスの確認
# https://www.elastic.co/guide/en/elasticsearch/reference/7.17/cat-indices.html
GET _cat/indices?v
=>
health status index                           uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   .geoip_databases                EC1kKQ0MSU2Z9l3bQf2Luw   1   0         41            0       39mb           39mb
green  open   .apm-custom-link                s_iOdeOsQwKTNjn4YNu4_Q   1   0          0            0       226b           226b
green  open   .kibana_task_manager_7.17.6_001 rn9iUROgSYyS197AO1-lyQ   1   0         17       167418     18.9mb         18.9mb
green  open   .apm-agent-configuration        PZ3GOlT2Qv-sURKpJYC5tg   1   0          0            0       226b           226b
yellow open   sample_index                    D35I3ylXTPugdK7FXg64tA   1   1       1065            0    788.5kb        788.5kb
green  open   .kibana_7.17.6_001              txA1LdEiRZSVv6gt4sK95g   1   0        330           41      2.4mb          2.4mb
green  open   .tasks                          K1p8v6KITnK6aFqokcq-eQ   1   0          4            0     27.4kb         27.4kb


# シャード配置の確認
# https://www.elastic.co/guide/en/elasticsearch/reference/7.17/cat-shards.html
GET _cat/shards?v
=>
index                                                         shard prirep state      docs   store ip         node
.kibana_7.17.6_001                                            0     p      STARTED     331   2.4mb 172.19.0.2 adee89610057
.ds-.logs-deprecation.elasticsearch-default-2022.10.15-000001 0     p      STARTED                 172.19.0.2 adee89610057
.geoip_databases                                              0     p      STARTED      41    39mb 172.19.0.2 adee89610057
.apm-agent-configuration                                      0     p      STARTED       0    226b 172.19.0.2 adee89610057
.kibana-event-log-7.17.6-000001                               0     p      STARTED                 172.19.0.2 adee89610057
.ds-ilm-history-5-2022.10.15-000001                           0     p      STARTED                 172.19.0.2 adee89610057
.kibana_task_manager_7.17.6_001                               0     p      STARTED      17  18.9mb 172.19.0.2 adee89610057
sample_index                                                  0     p      STARTED    1065 788.5kb 172.19.0.2 adee89610057
sample_index                                                  0     r      UNASSIGNED                         
.apm-custom-link                                              0     p      STARTED       0    226b 172.19.0.2 adee89610057
.tasks                                                        0     p      STARTED       4  27.4kb 172.19.0.2 adee89610057


# ドキュメントタイプの確認
GET sample_index/_mapping?pretty
=>
{
  "sample_index" : {
    "mappings" : {
      "properties" : {
        "contents" : {
          "type" : "text",
          "analyzer" : "kuromoji"
        },
        "title" : {
          "type" : "keyword"
        }
      }
    }
  }
}


# ドキュメントの確認
GET sample_index/_search?pretty
=>
...
    "hits" : [
      {
        "_index" : "sample_index",
        "_type" : "_doc",
        "_id" : "pdr634MBmKr2jjO6QdxX",
        "_score" : 1.0,
        "_source" : {
          "title" : "植物",
          "contents" : "植物（しょくぶつ、英:
...
```



# データ準備
## プラグイン導入
- 手軽に済ませるため、起動コンテナに直接 [kuromoji](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-kuromoji.html) を導入する
    - 日本語対応のAnalyzerの一つ
        - 全文検索するために文章を単語単位に分割する処理機能

```bash
$ docker exec -it [コンテナID] /bin/bash

（コンテナログイン後）> bin/elasticsearch-plugin install analysis-kuromoji

$ docker restart [コンテナID]

GET _nodes/plugins?pretty
=>
...
      "plugins" : [
        {
          "name" : "analysis-kuromoji",
          "version" : "7.17.6",
          "elasticsearch_version" : "7.17.6",
          "java_version" : "1.8",
          "description" : "The Japanese (kuromoji) Analysis plugin integrates Lucene kuromoji analysis module into elasticsearch.",
          "classname" : "org.elasticsearch.plugin.analysis.kuromoji.AnalysisKuromojiPlugin",
          "extended_plugins" : [ ],
          "has_native_controller" : false,
          "licensed" : false,
          "type" : "isolated"
        }
      ],
...


# アナライザーの動作確認
GET sample_index/_analyze
{
  "analyzer": "kuromoji",
  "text" : "植物（しょくぶつ、英: plant）とは、生物区分のひとつ。"
}
=>
{
  "tokens" : [
    {
      "token" : "植物",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "しょく",
      "start_offset" : 3,
      "end_offset" : 6,
      "type" : "word",
      "position" : 1
    },
...
```

## データ投入
```bash
# インデックス作成
PUT sample_index
{
  "mappings": {
    "properties": {
      "title": { "type": "keyword" },
      "contents": {
        "type": "text",
        "analyzer": "kuromoji"
      }
    }
  }
}


# バルク実行
# 文言の引用元: `https://ja.wikipedia.org/wiki/%E6%A4%8D%E7%89%A9`
POST sample_index/_bulk
{ "index" : { } }
{ "title" : "植物", "contents" : "植物（しょくぶつ、英: plant）とは、生物区分のひとつ。広辞苑の第5版によると「植物」は、草や木などのように、根があって場所が固定されて生きているような生物のことで、動物と対比させられた生物区分である[1]。それに対し、生物学にも歴史があり、二界説ないし五界説のような分類法が採用されていた時代があった。そこでは菌類（キノコやカビ）、褐藻（ワカメなど）なども植物と見なしていた。対してここ数十年の生物学では、分類群としての名称はあくまで「植物界」である為、現在も定義がひとつに定まっていない。陸上植物を含む単系統群として植物を定義するが、どの単系統を選ぶかにより複数の定義が並立している。狭い定義では陸上植物のみを植物として認めるが、より広い定義では緑色植物全体を植物としたり、紅色植物、灰色植物をも植物に含めたりする。また、「植物」と「植物界」という言葉の違いについても、乱暴に『「植物」は植物界のシノニムだ』と言ってしまう人と、『そうではない』という人[2]など、生物学者たちの中でも意見は分かれている。古い二界説や五界説では植物とみなされていた菌類や褐藻や光合成原生動物（ミドリムシや珪藻など）は、「系統が異なる」として、現在（2012年）では生物分類学上は植物とみなされていない。だが、さらにややこしいことに、生態学的には、こういう分類法では無い。例えば生態学では「光合成を行うワカメや珪藻は、植物（生産者）」とする。" }
```

# データ検索
```bash
# リクエストURI方式
GET sample_index/_search?q=キノコ&pretty


# リクエストボディ方式
GET sample_index/_search
{
  "query": {
    "match": {
      "contents": "キノコ"
    }
  }
}
```





# 終わりに
必要であれば後片付け

```bash
$ docker stop es01-test
$ docker stop kib01-test

$ docker network rm elastic
$ docker rm es01-test
$ docker rm kib01-test
```

今後はもう少し踏み込んだ機能について調べていく予定（[スコア計算](https://blog.linkode.co.jp/entry/2020/06/25/144701)とか気になる）



# 参考
- [公式ドキュメント Quick start（英語ver）](https://www.elastic.co/guide/en/elasticsearch/reference/7.17/getting-started.html)
- [公式ドキュメント Quick start（日本語ver）](https://www.elastic.co/guide/jp/elasticsearch/reference/current/getting-started.html)
- [Elasticsearch API 一覧](https://medium.com/hello-elasticsearch/elasticsearch-api-83760ce1424b)
- [ElasticSearchで日本語の文章を検索できるようにする](https://qiita.com/suzukil/items/5ffe3c29cbb1cdb9da41)
- [Elasticsearchで日本語検索を扱うためのマッピング定義](https://techblog.zozo.com/entry/elasticsearch-mapping-config-for-japanese-search)