Elastic Search -- or と filter を組み合わせた検索を実装する
Tags: elasticsearch
Published: 2023-01-05 14:14:07


## why

https://andor.kb.asia-northeast1.gcp.cloud.es.io:9243/app/dev_tools#/console

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

この実装をしたい


https://medium.com/eureka-engineering/%E5%9F%BA%E7%A4%8E%E7%B7%A8-elasticsearch%E3%81%AE%E6%A4%9C%E7%B4%A2%E3%82%AF%E3%82%A8%E3%83%AA%E3%82%92%E4%BD%BF%E3%81%84%E3%81%93%E3%81%AA%E3%81%9D%E3%81%86-ace3e18c2174

複数一致と数値範囲は range / gte , これでフィルターできるらしい。

## データの作成

```json
POST /user/_doc/1
{
  "name": "kaede",
  "cash": "30000",
  "job_rank": "player",
  "credit": "green"
}
```

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

初期データを生成していく。

```json
POST /user/_doc/2
{
  "name": "tom",
  "cash": "100000",
  "job_rank": "manager",
  "credit": "gold"
}
```

```json
POST /user/_doc/3
{
  "name": "suzu",
  "cash": "200000",
  "job_rank": "player",
  "credit": "gold"
}
```

```json
POST /user/_doc/4
{
  "name": "yanagi",
  "cash": "1000000",
  "job_rank": "manager",
  "credit": "none"
}
```

100k あって manager で gold の tom
200k あるが player で gold の suzu
1000k あり manager で none の yanagi

これらのデータも追加し、

tom と suzu だけひっかかるようにする

---

## 職位 manager 以上

```json
{
  "query": {
    "bool": {
      "must": [
        { "match": { "job_rank": "manager" } }
      ]
    }
  }
}
```

```json
    "hits": [
      {
        "_index": "user",
        "_id": "2",
        "_score": 0.6931471,
        "_source": {
          "name": "tom",
          "cash": "100000",
          "job_rank": "manager",
          "credit": "gold"
        }
      },
      {
        "_index": "user",
        "_id": "4",
        "_score": 0.6931471,
        "_source": {
          "name": "yanagi",
          "cash": "1000000",
          "job_rank": "manager",
          "credit": "none"
        }
      }
    ]
```

tom と yanagi だけがひっかかる

ここから gold をフィルターする

```json
GET /user/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "job_rank": "manager" } }
      ],
      "filter": [
        { "match": { "credit": "gold"}}
      ]
    }
  }
}
```

```json
    "hits": [
      {
        "_index": "user",
        "_id": "2",
        "_score": 0.6931471,
        "_source": {
          "name": "tom",
          "cash": "100000",
          "job_rank": "manager",
          "credit": "gold"
        }
      }
    ]
```

bool の下には複数条件を置くことができる。

must だけでなく、filter も噛ませることで
クレジットカードが gold も持っている 
tom だけに絞り込めた。

ここから、職位が player でも金をもっていれば
ヒットするようにする

```json
GET /user/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "job_rank": "manager" } }
      ],
      "filter": [
        { "match": { "credit": "gold"}}
      ]
    }
  }
}
```

```json
    "hits": [
      {
        "_index": "user",
        "_id": "2",
        "_score": 0.6931471,
        "_source": {
          "name": "tom",
          "cash": "100000",
          "job_rank": "manager",
          "credit": "gold"
        }
      },
      {
        "_index": "user",
        "_id": "3",
        "_score": 0,
        "_source": {
          "name": "suzu",
          "cash": "200000",
          "job_rank": "player",
          "credit": "gold"
        }
      }
    ]
```

manager の条件に should を入れて
filter と並列にすると
should の中身が意味をなさなくなってしまう

```json
GET /user/_search
{
  "query": {
    "bool": {

      "must": [
        { "match": { "job_rank": "manager,player" } },
        { "match": { "cash": "100000, 200000" } }
      ],
      "filter": [
        { "match": { "credit": "gold"}}
      ]
      
    }
  }
}
```

なので、must の内部に条件を並べて、
その must を filter と並列に並べれば絞れる。

## まとめ

should { A1, A2, }