Elastic Search の index(table) を作成して部分 { 一致, 不一致 } 検索をする
Tags: elasticsearch
Published: 2022-07-29 15:22:00


## why

柔軟に日本語を分解して検索できる Elastic Search を使って
複雑な条件でも自由自在に検索できるようになりたいから。

And, Or, Filter, これらをマスターしたい。

# 環境構築

アカウント作成してログインするだけなので簡単。
14 日しか使えないけど。

## Elastic Search のアカウント作成、ログイン

https://www.elastic.co/guide/en/welcome-to-elastic/current/getting-started-general-purpose.html#gp-gs-prereqs

新規登録すればクラウドトライアルで試しうちできるらしい。
なので登録してログインする

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fna1tph1gnustqw6y6bj.png)
 
14 日間使えるらしい。

---

## アプリ作成

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7q0dh0p2tcrpzwa8ztl8.png)
 
NorthEast1 ( Japan ) を選択して
andOr というアプリ名で作成

クラウドプロバイダーが選択できるので、
ES はプラットフォームではないらしい。

作成されると、UserName と Pass が発行される

ローカルに作らなくても、もうこれでクエリを叩きまくって遊ぶことができる。

---
---

# コンソールで基礎的な POST / GET を試す

## Dev Tools にアクセスしてコンソールを開く

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gxb1fif3xokxkstx9mk2.png)

Java やプラグインは一切追加せずとも

左下の Management / Dev tools にアクセスすれば

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3c0l1qmw26ta2mpdm0hk.png)

Elastic Search を叩くクエリを書けて
かつ実行できるエディタが開く。

---

## コンソールに新しい index を追加して同時にデータも追加する

https://www.elastic.co/guide/en/welcome-to-elastic/current/getting-started-general-purpose.html#gp-gs-add-data

チュートリアルに従って

```json
POST /customer/_doc/1
{
  "name": "kaede"
}
```

name: kaede の json を POST で /customer/ の _doc/1 に送ると

```json
POST /customer/_doc/1
{
  "name": "kaede"
}
```

customer という index (table 相当) が作成され
同時に
Document ID を 1 として name: kaede のデータも登録された。

2, 3 に john, dan, これらの名前のデータも登録した

```json
{
  "_index": "customer",
  "_id": "zAPpVIIB6_QPx1u8MGaH",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 2,
    "failed": 0
  },
  "_seq_no": 3,
  "_primary_term": 1
}
```

なお、ID の指定をしないと UUID で作成される。

---

## ID: 1 の kaede だけ GET する

```json
GET /customer/_doc/1
```

customer インデックスの DocID 1 を GET すると

```json
{
  "_index": "customer",
  "_id": "1",
  "_version": 1,
  "_seq_no": 0,
  "_primary_term": 1,
  "found": true,
  "_source": {
    "name": "kaede"
  }
}
```

kaede が取れた。REST っぽいね。

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ufjd2c7utjpdgzvowcm9.png)
 
HTTP Status もかかった時間もわかる。

これで基礎的な GET/POST は動作確認できた。

---
---

# 検索をする

indexName/_search
query
bool, must, match

これらを使うことで Elastic Search では検索ができる。

簡単な完全一致、完全不一致検索まで動作確認する。

## index の中身を全て見る

```json
GET /customer/_search
```
 
indexName に _search をつけると

```json
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 3,
      "relation": "eq"
    },
    "max_score": 1,
    "hits": [
      {
        "_index": "customer",
        "_id": "1",
        "_score": 1,
        "_source": {
          "name": "kaede"
        }
      },
      {
        "_index": "customer",
        "_id": "2",
        "_score": 1,
        "_source": {
          "name": "john"
        }
      },
      {
        "_index": "customer",
        "_id": "3",
        "_score": 1,
        "_source": {
          "name": "dan"
        }
      }
    ]
  }
}
```

index の中のデータが全て取れる。
これに query をつけることで、検索を実現できる。

---

## 名前で完全一致検索する

https://www.elastic.co/guide/en/welcome-to-elastic/current/getting-started-general-purpose.html#gp-gs-search-data

```json
GET /customer/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "name": "dan" } }
      ]
    }
  }
}
```

公式ガイドを参考に query/bool/must/match で
項目: 値 で絞る。

query 事態を { } で囲わないと GET と紐付かないので注意。

```json
{
  "took": 3,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.9808291,
    "hits": [
      {
        "_index": "customer",
        "_id": "3",
        "_score": 0.9808291,
        "_source": {
          "name": "dan"
        }
      }
    ]
  }
}
```

するとしっかり名前が dan のデータが絞り込めた。
大文字小文字を区別はしない。
ID は検索するフィールドではないのでこのやり方では絞り込めない。

なお、 dan はこれ以上区切られないので、da では引っかからないが

```json
        { "match": { "name": "良" } }
```

```json
    "hits": [
      {
        "_index": "customer",
        "_id": "zAPpVIIB6_QPx1u8MGaH",
        "_score": 0.85443234,
        "_source": {
          "name": "良太郎"
        }
      }
    ]
```

良太郎 は漢字なので 良,太,郎 どれでも引っかかる。


---

## 名前で部分不一致検索する

逆に must_not を使うとそれを含まないデータを出せる

```json
  "query": {
    "bool": {
      "must_not": [
        { "match": { "name": "dan" } }
      ]
    }
  }
```

先程のを must_not に変えると

```json
    "hits": [
      {
        "_index": "customer",
        "_id": "1",
        "_score": 0,
        "_source": {
          "name": "kaede"
        }
      },
      {
        "_index": "customer",
        "_id": "2",
        "_score": 0,
        "_source": {
          "name": "john"
        }
      }
    ]
```

dan 以外が返ってくる。

---
---

# まとめ

Elastic Search は Google でアカウント連携するだけで
簡単に実行環境を手に入れて勉強できる。

Mangement/Devtools にアクセスして

```json
POST /{indexName}/_doc/{docId}
{
  "{keyName}": "{valueName}"
}
```

これを打つだけでインデックス(テーブル)
と初期データが登録できる。
同じインデックスにこれを打つと追加できる。

```json
GET /customer/_search
```

これでインデックスの中身を全てみれる

```json
GET /customer/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "name": "dan" } }
      ]
    }
  }
}
```

こうやってクエリを渡すことで絞り込める。

dan は d や a では検索できないが
良太郎は どの文字でも検索できる。

以上。

---

## 次回

複雑な OR と AND をもつクエリも書きたい。

複数の key value を持つデータで、
所持金が 100k 以上または、職位が Manager 以上で、
クレジットカードのランクが Gold