Elasticsearch と Kibana 7.5.1 Windows をインストールしてみる

[https://db-engines.com/en/ranking](https://db-engines.com/en/ranking) によると、サーチエンジンのElasticsearchはかなりいいところ（2019年12月付で全体の8位、サーチエンジンではトップ）につけています。

自前の全文検索システムを作りたくて、インストールしてみました。

作業記録をほぼリアルタイムでここに残しておきます。
年末年始の空き時間で作業を行いますので、作業と作業の間隔が空くことになるとは思います。

（環境）
プロセッサ：Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz 1.80GHz
実装RAM：16.0GB
システムの種類：64ビットオペレーティングシステム、x64 ベースプロセッサ
Windowsの仕様：Xindows 10 Home

（今回の目標とする着地点）
・1ノード、1クラスタ　（つまり no operation）
・最もシンプルな形でCRUDができる

elastic社サイトの　[Elasticsearchのデータ操作入門](https://www.elastic.co/jp/webinars/getting-started-elasticsearch)　を見ながらやってみます。

作業を開始します。

#インストール

[https://www.elastic.co/jp/downloads/elasticsearch](https://www.elastic.co/jp/downloads/elasticsearch)
からWindows を選択してダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/1f7e7d7d-df3d-0921-ec4e-f83e14a485fc.png)

ダウンロードフォルダに
elasticsearch-7.5.1-windows-x86_64.zip
が格納されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/75dffc45-1d41-a3de-3b3a-6f856f0942b8.png)

zipを解凍する。デスクトップにフォルダが作成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/2e836f96-6bbc-b3bf-378a-e0f2311fe61d.png)

デスクトップだと後々面倒なことが起こりそうなのでCドライブに移動させる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/ffa270b4-ee76-e7d3-fc2e-5845d6cdf05c.png)

jdkが既に組み込まれているようなので有難いです。
binフォルダに移動します。

elasticsearch.bat を起動してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/1ec796e0-8887-064f-b46b-6b41c631af01.png)

なんか起動したみたいです。Security is desabled というのはとりあえず置いておいて、
ポート9200で待ち受け状態になっているか確認してみます。

    PS C:\Users\xxx> curl http://localhost:9200
    
    StatusCode        : 200
    StatusDescription : OK
    Content           : {
                          "name" : "LAPTOP-XXXX9X99",
                          "cluster_name" : "elasticsearch",
                          "cluster_uuid" : "XXXXxxXXXxX9XxX9xxxxXX",
                          "version" : {
                            "number" : "7.5.1",
                            "build_flavor" : "default",
                            "build_type...
    RawContent        : HTTP/1.1 200 OK
                        Content-Length: 540
                        Content-Type: application/json; charset=UTF-8
    
                        {
                          "name" : "LAPTOP-XXXX9X99",
                          "cluster_name" : "elasticsearch",
                          "cluster_uuid" : "XXXXxxXXXxX9XxX9xxxxXX",
                        ...
    Forms             : {}
    Headers           : {[Content-Length, 540], [Content-Type, application/json; charset=UTF-8]}
    Images            : {}
    InputFields       : {}
    Links             : {}
    ParsedHtml        : mshtml.HTMLDocumentClass
    RawContentLength  : 540
    
大丈夫なようです。

　次は [https://www.elastic.co/jp/downloads/kibana](https://www.elastic.co/jp/downloads/kibana) からWindoswを選択してKibanaをダウンロードしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/1f3ee097-9739-8789-0e3c-30e4b1d51c9b.png)

Cドライブに解凍します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/d3e4bc25-0a65-fb0d-9134-0667331378a7.png)

kibana.yml を見てみると、Elasticsearchの接続初期値は http://localhost:9200 となっているようなのであらためての設定変更は必要なさそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/195fca15-7466-0a01-ddd9-810a5736dedd.png)

それじゃあ、binフォルダ内のkibana.bat を起動してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/4d451f71-663b-6281-dc04-ec986d472062.png)

ログの最後に
    http server running at http://localhost:5601
と出力されるのでブラウザから表示させてみます。
事前に Elastic Security の設定をしておくとIDとパスワードを聞いてくるようですが、ここは端折ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/2546df56-2d56-7bf4-6083-c4cfb0d4fb7e.png)

Elasticsearchが用意しているREST APIはHTTPプロトコルを利用した仕組みなので、検証のためのパケットキャプチャツールとしてFeddlerを利用しようと思っていました。
でも当面それは必要なくて、Kibanaで用意されているDev Tools というのを使うとかなりのことができそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/47b748f2-afb9-d2f1-0cd8-26e54995f631.png)

Submit Request のためのショートカット Ctrl + Enter を実行すると画面の右側にGETコマンドの応答が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/31fcb73b-96c8-64d4-22ee-bf939f236c9e.png)

どうやら格納済のデータがあるようです。
ヒットしたのは
"_index" : ".kibana_1" 6件
"_index" : ".kibana_task_manager_1" 2件
の8件。
"_type" : "_doc" は Elasticsearch 7では固定のようです。
日付時刻はUTC（協定世界時）で表現されているようです。



    {
      "took" : 0,
      "timed_out" : false,
      "_shards" : {
        "total" : 3,
        "successful" : 3,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 8,
          "relation" : "eq"
        },
        "max_score" : 1.0,
        "hits" : [
          {
            "_index" : ".kibana_1",
            "_type" : "_doc",
            "_id" : "space:default",
            "_score" : 1.0,
            "_source" : {
              "space" : {
                "name" : "Default",
                "description" : "This is your default space!",
                "color" : "#00bfb3",
                "disabledFeatures" : [ ],
                "_reserved" : true
              },
              "type" : "space",
              "migrationVersion" : {
                "space" : "6.6.0"
              },
              "updated_at" : "2019-12-31T02:06:06.431Z"
            }
          },
          {
            "_index" : ".kibana_1",
            "_type" : "_doc",
            "_id" : "config:7.5.1",
            "_score" : 1.0,
            "_source" : {
              "config" : {
                "buildNum" : 27610
              },
              "type" : "config",
              "updated_at" : "2019-12-31T02:09:03.897Z"
            }
          },
          {
            "_index" : ".kibana_1",
            "_type" : "_doc",
            "_id" : "telemetry:telemetry",
            "_score" : 1.0,
            "_source" : {
              "telemetry" : {
                "userHasSeenNotice" : true
              },
              "type" : "telemetry",
              "updated_at" : "2019-12-31T02:09:09.681Z"
            }
          },
          {
            "_index" : ".kibana_1",
            "_type" : "_doc",
            "_id" : "ui-metric:kibana-user_agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36",
            "_score" : 1.0,
            "_source" : {
              "ui-metric" : {
                "count" : 1
              },
              "type" : "ui-metric",
              "updated_at" : "2019-12-31T02:11:32.153Z"
            }
          },
          {
            "_index" : ".kibana_1",
            "_type" : "_doc",
            "_id" : "ui-metric:Kibana_home:welcomeScreenMount",
            "_score" : 1.0,
            "_source" : {
              "ui-metric" : {
                "count" : 1
              },
              "type" : "ui-metric",
              "updated_at" : "2019-12-31T02:11:32.153Z"
            }
          },
          {
            "_index" : ".kibana_1",
            "_type" : "_doc",
            "_id" : "ui-metric:Kibana_home:sampleDataDecline",
            "_score" : 1.0,
            "_source" : {
              "ui-metric" : {
                "count" : 1
              },
              "type" : "ui-metric",
              "updated_at" : "2019-12-31T02:20:37.151Z"
            }
          },
          {
            "_index" : ".kibana_task_manager_1",
            "_type" : "_doc",
            "_id" : "task:oss_telemetry-vis_telemetry",
            "_score" : 1.0,
            "_source" : {
              "migrationVersion" : {
                "task" : "7.4.0"
              },
              "task" : {
                "taskType" : "vis_telemetry",
                "retryAt" : null,
                "runAt" : "2020-01-01T15:00:00.000Z",
                "startedAt" : null,
                "state" : """{"runs":3}""",
                "params" : "{}",
                "ownerId" : null,
                "scheduledAt" : "2019-12-31T02:06:09.626Z",
                "attempts" : 3,
                "status" : "failed"
              },
              "updated_at" : "2020-01-01T15:00:01.353Z",
              "type" : "task"
            }
          },
          {
            "_index" : ".kibana_task_manager_1",
            "_type" : "_doc",
            "_id" : "task:Lens-lens_telemetry",
            "_score" : 1.0,
            "_source" : {
              "migrationVersion" : {
                "task" : "7.4.0"
              },
              "task" : {
                "taskType" : "lens_telemetry",
                "retryAt" : null,
                "runAt" : "2020-01-02T15:00:00.000Z",
                "startedAt" : null,
                "state" : """{"runs":3,"byDate":{},"suggestionsByDate":{},"saved":{"saved_30_days":{},"saved_overall_total":0,"saved_30_days_total":0,"saved_90_days_total":0}}""",
                "params" : "{}",
                "ownerId" : null,
                "scheduledAt" : "2019-12-31T02:06:09.625Z",
                "attempts" : 0,
                "status" : "idle"
              },
              "updated_at" : "2020-01-01T15:00:02.522Z",
              "type" : "task"
            }
          }
        ]
      }
    }

#CREATE
インデックスについては、１件目のデータを登録すると勝手に作られるようです。

新規登録用にこんなのを作ってみました。
ちゃんとエラーを指摘してくれます。これは有難い。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/5ad87fa1-d414-7dec-dd14-92eebbb5acd6.png)


エラーを訂正してもう一度やってみます。

    POST /j_literature/_doc
    {
      "title": "走れメロス",
      "authors": ["太宰治"],
      "sentences": [
         "メロスは激怒した。",
         "必ず、かの邪智暴虐の王を除かなければならぬと決意した。",
         "メロスには政治がわからぬ。",
         "メロスは、村の牧人である。",
         "メロスには政治がわからぬ。",
         "笛を吹き、羊と遊んで暮して来た。",
         "けれども邪悪に対しては、人一倍に敏感であった。"
       ]
    }

うまくいきました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/fe20e4f3-e1b9-fb5f-d92b-9bf9984ce1be.png)


"_seq_no" : 0
から始まるのでしょうか。
リクエストは1つなのに
"total" : 2
というのはどういうことでしょうか。
もしかしたら インデックス作成とデータ登録で 2　なのかな。
一応できたので、？のまま先に進みます。

    {
      "_index" : "j_literature",
      "_type" : "_doc",
      "_id" : "65XhaG8B71ysKG-2olXg",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 0,
      "_primary_term" : 1
    }

この調子であといくつか登録してみます。
"total" については？のままです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/c84032a1-cad3-1995-c45c-e1e10d7cbbe4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/d43f4c96-837b-e85a-2266-7e3a89a2100d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/80bc078c-940f-71d4-cd13-7286932f075a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/bfede285-98c1-a206-75db-1fa2e1f60b19.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/7179601c-c445-f48c-0d68-3dde79ed7962.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/0f0d4fe7-2c66-66ae-eea9-a4cb3fb8e28e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/50c528a0-755d-5da5-90ec-8716506a1a88.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/217d4730-d9e1-e5b1-0681-7d28706a48c6.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/4fc32f71-a964-f2ea-75f8-44a5f0c62053.png)


ここまでに10件を登録しました。
なお、[Elasticsearchのデータ操作入門](https://www.elastic.co/jp/webinars/getting-started-elasticsearch)　の 0:44:00 から bulk API の解説がありました。
本番で大量のデータをバッチ的に登録するにはその方式がいいかと思います。

#READ

では登録した10件のデータを使って、READの実験をしてみます。

    GET j_literature/_doc/_search

のコマンドで、登録されているデータを確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/d97c9abc-25ff-3199-11a8-2247849c02db.png)
（中略）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/44947927-c5f0-6f35-ae3f-e3cf4ec4d35d.png)

    "value" : 10,
とあるので10件がヒットしたことがわかります。
応答の先頭に

    #! Deprecation: [types removal] Specifying types in search requests is deprecated.

があります。
今後廃止する機能を使っている場合にこのようなワーニングが出力されるようです。

    GET j_literature/_search

としてもう一度やっておきます。
これでいいみたいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/aa8f2dda-956d-144e-a0e6-e7027a9448ca.png)

"title": "少年"
で絞って検索してみます。

    GET j_literature/_search
    {
      "query" : {
        "match": {
          "title": "少年"
        }
      }
    }

"少年探偵団" と "不良少年とキリスト" がヒットしました。OKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/541c35ed-456e-1629-03c9-c3fae5717dde.png)

"authors": "太宰"
で絞って検索してみます。

    GET j_literature/_search
    {
      "query" : {
        "match": {
          "authors": "太宰"
        }
      }
    }

"太宰治" の ”走れメロス" がヒットしました。OKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/743fab19-69f9-cd38-df26-05b4203d9cf3.png)

今度は
"title": "少年"
"sentences": "太宰"
で絞った検索をしてみます。

    GET j_literature/_search
    {
      "query": {
        "bool": {
          "must": [
            {
              "match": {
              "title": "少年"
              }
            },
            {
              "match_phrase": {
              "sentences": "太宰"
              }
            }
          ]
        }
      }
    }

"不良少年とキリスト" だけがヒットしました。OKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/6ca29422-167c-65e4-1833-5f85da3e4bf1.png)

今度は
"authors": "太宰"
"sentences": "太宰"
どちらかが該当する作品を検索してみます。

    GET j_literature/_search
    {
      "query": {
        "bool": {
          "should": [
            {
              "match": {
              "authors": "太宰"
              }
            },
            {
              "match_phrase": {
              "sentences": "太宰"
              }　
            }
          ]
        }
      }
    }

”走れメロス" と "不良少年とキリスト" がヒットしました。OKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/474e9a20-6d46-63aa-0391-870aeec12734.png)

こんなふうに SQL も使えるようですが、

    POST _sql?format=txt
    {
      "query" : "SELECT title, authors FROM j_literature WHERE authors like '%太宰%' OR sentences like '%太宰%' ORDER BY title"
    }

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/32417adf-f890-2b00-0d12-1c32c6f77347.png)

さすがに SELECT句に配列 sentences を指定することはできないようです。

    POST _sql?format=txt
    {
      "query" : "SELECT title, authors, sentences FROM j_literature WHERE authors like '%太宰%' OR sentences like '%太宰%' ORDER BY title"
    }

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/52253dbc-d0e6-cde8-23fc-a7d6f15ae2d2.png)

でも"query"を同じにしてエンドポイントを
POST _sql/translate
に変えると SQL から Elasticsearch の query に変換をかけた json の値が返ってきます。
Elasticsearch の query に慣れないうちはこれで確認しながらやると良さそうです。

    POST _sql/translate
    {
      "query" : "SELECT title, authors, sentences FROM j_literature WHERE authors like '%太宰%' OR sentences like '%太宰%' ORDER BY title"
    }

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/d62c8e40-5b7a-f59d-e33f-9233736db40e.png)


#UPDATE

"走れメロス" の sentences に
"メロスには政治がわからぬ。"
が重複して存在していました。
このデータを UPDATE するにはIDが必要みたいなので、

    GET j_literature/_search
    {
      "query" : {
        "match": {
          "title": "走れメロス"
        }
      }
    }

でIDを取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/45059713-f61b-4c9c-0d18-af85330f7e55.png)

取得した

    "_id" : "65XhaG8B71ysKG-2olXg",

を使って、queryを投げます。

    POST j_literature/_update/65XhaG8B71ysKG-2olXg
    {
      "doc": {
        "sentences": [
           "メロスは激怒した。",
           "必ず、かの邪智暴虐の王を除かなければならぬと決意した。",
           "メロスには政治がわからぬ。",
           "メロスは、村の牧人である。",
           "笛を吹き、羊と遊んで暮して来た。",
           "けれども邪悪に対しては、人一倍に敏感であった。"
         ]
      }
    }

うまくいきました。OKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/aee7a2ff-e861-d40f-c884-821ebf08c6f8.png)

ちゃんと更新できていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/6c4ac3e2-1d24-c5cd-9d88-5fb61657ef6a.png)

#DELETE

sentences に "猫" の文字列があるものを検索してみると

    POST j_literature/_search
    {
      "query" : {
        "match": {
          "sentences": "猫"
        }
      }
    }

"吾輩は猫である" が1件ヒットしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/7d5f85e1-7775-4f02-1fc4-1d9fd840f4b1.png)

これを削除してみることにします。

    POST j_literature/_delete_by_query
    {
      "query" : {
        "match": {
          "sentences": "猫"
        }
      }
    }　

エラーなく1件が削除されたようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/cd480256-c433-cd6a-98b8-d0636ab1f7ea.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/225878/ab0f2241-309a-b590-4936-7326e650880f.png)

これで、今回目標とする
・最もシンプルな形でCRUDができる
に着地することができました。

[Elasticsearch に「銀の匙」を登録して検索してみる](https://qiita.com/azumabashi/items/cb6cdceebd673d5da699) に続きます。