DEV Community

kaede
kaede

Posted on

Elastic Search -- or と filter を組み合わせた検索を実装する

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 , これでフィルターできるらしい。

データの作成

POST /user/_doc/1
{
  "name": "kaede",
  "cash": "30000",
  "job_rank": "player",
  "credit": "green"
}
Enter fullscreen mode Exit fullscreen mode
{
  "_index": "user",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 2,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}
Enter fullscreen mode Exit fullscreen mode

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

POST /user/_doc/2
{
  "name": "tom",
  "cash": "100000",
  "job_rank": "manager",
  "credit": "gold"
}
Enter fullscreen mode Exit fullscreen mode
POST /user/_doc/3
{
  "name": "suzu",
  "cash": "200000",
  "job_rank": "player",
  "credit": "gold"
}
Enter fullscreen mode Exit fullscreen mode
POST /user/_doc/4
{
  "name": "yanagi",
  "cash": "1000000",
  "job_rank": "manager",
  "credit": "none"
}
Enter fullscreen mode Exit fullscreen mode

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

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

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


職位 manager 以上

{
  "query": {
    "bool": {
      "must": [
        { "match": { "job_rank": "manager" } }
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
    "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"
        }
      }
    ]
Enter fullscreen mode Exit fullscreen mode

tom と yanagi だけがひっかかる

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

GET /user/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "job_rank": "manager" } }
      ],
      "filter": [
        { "match": { "credit": "gold"}}
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
    "hits": [
      {
        "_index": "user",
        "_id": "2",
        "_score": 0.6931471,
        "_source": {
          "name": "tom",
          "cash": "100000",
          "job_rank": "manager",
          "credit": "gold"
        }
      }
    ]
Enter fullscreen mode Exit fullscreen mode

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

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

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

GET /user/_search
{
  "query": {
    "bool": {
      "should": [
        { "match": { "job_rank": "manager" } }
      ],
      "filter": [
        { "match": { "credit": "gold"}}
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
    "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"
        }
      }
    ]
Enter fullscreen mode Exit fullscreen mode

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

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

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

    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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

まとめ

should { A1, A2, }

Top comments (0)