見出し画像

Elasticsearchのbool クエリとminimum_should_matchについて

こんにちは。AiritechでElasticsearchを使った検索システムの開発改善を行っている、河村です。

Elasticsearchのクエリは、SQLと違ってJSONで記載するため、慣れないと分かりづらいですが、複雑な検索条件を指定できる仕組みになっています。

今回は、Elasticsearchのクエリの中で最も重要な、bool queryについて解説したいと思います。

bool queryとは

複数の条件を AND、OR、NOT で組み合わせた、複雑な条件を指定するためのクエリです。単にAND、OR、NOTを組み合わせるよりもさらに細かい条件を指定することも可能な仕組みになっています。
この後、具体的な例を用いて説明します。

Elasticsearchクエリの例

例に使用するインデックスには以下のデータが格納されています。


     {
       "_id" : "1",
       "_source" : {
         "author" : "村上春樹",
         "title" : "海辺のカフカ",
         "price" : 1200
       }
     },
     {
       "_id" : "2",
       "_source" : {
         "author" : "村上春樹",
         "title" : "ノルウェイの森",
         "price" : 1000
       }
     },
     {
       "_id" : "3",
       "_source" : {
         "author" : "川端康成",
         "title" : "舞姫",
         "price" : 1400
       }
     },
     {
       "_id" : "4",
       "_source" : {
         "author" : "川端康成",
         "title" : "雪国",
         "price" : 800
       }
     }

以下の3つのクエリA, B, C を用いて、
1. A and C
2. A and (not C)
3. A or C
4. A or (B and C)
5. (A or B) and (A or C)
6. A or B or C
7. A, B, Cの3つの条件のうちの少なくとも2つを満たす
の7通りのクエリの書き方を紹介します。

キーワードを著者のフィールドに対して検索をするmatchクエリ(A)


GET search_test/_search
{
 "query": {
   "match": {
     "author": "村上春樹"
   }
 }
}

実行結果の一部

    "hits" : [
     {
       "_id" : "2",
       "_score" : 1.1507283,
       "_source" : {
         "author" : "村上春樹",
         "title" : "ノルウェイの森",
         "price" : 1000
       }
     },
     {
       "_id" : "1",
       "_score" : 1.1507283,
       "_source" : {
         "author" : "村上春樹",
         "title" : "海辺のカフカ",
         "price" : 1200
       }
     }
   ]


キーワードをタイトルのフィールドに対して検索をするmatchクエリ (B)

GET search_test/_search
{
 "query": {
   "match": {
     "title": "雪国"
   }
 }
}

実行結果の一部


 "hits" : [
     {
       "_id" : "4",
       "_score" : 0.5753642,
       "_source" : {
         "author" : "川端康成",
         "title" : "雪国",
         "price" : 800
       }
     }
   ]

指定したフィールドに対して範囲でフィルタをかけるrangeクエリ (C)

以下の4つのオプションがあります。

・gte : 以上

・lte : 以下

・gt : より大きい

・lt : 未満

GET search_test/_search
{
 "query": {
   "range": {
     "price": {
       "gte": 500,
       "lte": 1000
     }
   }
 }
}

実行結果の一部

   "hits" : [
     {
       "_id" : "3",
       "_score" : 1.0,
       "_source" : {
         "author" : "川端康成",
         "title" : "雪国",
         "price" : 800
       }
     },
     {
       "_id" : "2",
       "_score" : 1.0,
       "_source" : {
         "author" : "村上春樹",
         "title" : "ノルウェイの森",
         "price" : 1000
       }
     }
   ]

boolクエリを使ったAND, OR, NOTの表現

boolクエリの条件式、AND,OR,NOT を組み合わせて、複雑な条件を指定できます。

以下の4種類のクエリがあります。

・filter : 配下の条件すべてを必須条件とする。検索結果のスコアに影響しない。
・must : 配下の条件すべてを必須条件とする。検索結果のスコアに影響する。
・must_not : 配下の条件すべてを否定条件とする。
・should : minimum_should_matchで指定した条件の数だけ一致した結果を取得する。OR条件を作るときに利用する。

例1 A and C

GET search_test/_search
{
 "query": {
   "bool": {
     "must": [
       {
         "match": {
           "author": "村上春樹"
         }
       },
       {
         "range": {
           "price": {
             "gte": 500,
             "lte": 1000
           }
         }
       }
     ]
   }
 }
}

実行結果の一部

     "hits" : [
     {
       "_id" : "2",
       "_score" : 2.1507282,
       "_source" : {
         "author" : "村上春樹",
         "title" : "ノルウェイの森",
         "price" : 1000
       }
     }
   ]

例2 A and(notC)

GET search_test/_search
{
 "query": {
   "bool": {
     "must": [
       {
         "match": {
           "author": "村上春樹"
         }
       }
     ],
     "must_not": [
       {
         "range": {
           "price": {
             "gte": 500,
             "lte": 1000
           }
         }
       }
     ]
   }
 }
}

実行結果の一部

   "hits" : [
     {
       "_id" : "1",
       "_score" : 1.1507283,
       "_source" : {
         "author" : "村上春樹",
         "title" : "海辺のカフカ",
         "price" : 1200
       }
     }
   ]

例3 A or C

GET search_test/_search
{
 "query": {
   "bool": {
     "should": [
       {
         "match": {
           "author": "村上春樹"
         }
       },
       {
         "range": {
           "price": {
             "gte": 500,
             "lte": 1000
           }
         }
       }
     ],
     "minimum_should_match": 1
   }
 }
}

実行結果の一部

   "hits" : [
       {
       "_id" : "2",
       "_score" : 2.1507282,
       "_source" : {
         "author" : "村上春樹",
         "title" : "ノルウェイの森",
         "price" : 1000
       }
     },
     {
       "_id" : "1",
       "_score" : 1.1507283,
       "_source" : {
         "author" : "村上春樹",
         "title" : "海辺のカフカ",
         "price" : 1200
       }
     },
     {
       "_id" : "4",
       "_score" : 1.0,
       "_source" : {
         "author" : "川端康成",
         "title" : "雪国",
         "price" : 800
       }
     }
   ]

OR条件を作成するためには、shouldクエリとminimum_should_matchクエリを組み合わせます。

boolクエリは入れ子にすることができるので、さらに複雑な検索も可能です。

例4  A or (B and C)

GET search_test/_search
{
 "query": {
   "bool": {
     "should": [
       {
         "match": {
           "author": "村上春樹"
         }
       },
       {
         "bool": {
           "must": [
             {
               "match": {
                 "title": "雪国"
               }
             },
             {
               "range": {
                 "price": {
                   "gte": 500,
                   "lte": 1000
                 }
               }
             }
           ]
         }
       }
     ],
     "minimum_should_match": 1
   }
 }
}

実行結果の一部

   "hits" : [
     {
       "_id" : "3",
       "_score" : 1.5753641,
       "_source" : {
         "author" : "川端康成",
         "title" : "雪国",
         "price" : 800
       }
     },
     {
       "_id" : "2",
       "_score" : 1.1507283,
       "_source" : {
         "author" : "村上春樹",
         "title" : "海辺のカフカ",
         "price" : 1200
       }
     },
     {
       "_id" : "1",
       "_score" : 1.1507283,
       "_source" : {
         "author" : "村上春樹",
         "title" : "ノルウェイの森",
         "price" : 1000
       }
     }
   ]

例5 (A or B) and (A or C)

GET search_test/_search
{
 "query": {
   "bool": {
     "must": [
       {
         "bool": {
           "should": [
             {
               "match": {
                 "author": "村上春樹"
               }
             },
             {
               "match": {
                 "title": "雪国"
               }
             }
           ],
           "minimum_should_match": 1
         }
       },
       {
         "bool": {
           "should": [
             {
               "match": {
                 "author": "川端康成"
               }
             },
             {
               "range": {
                 "price": {
                   "gte": 500,
                   "lte": 1000
                 }
               }
             }
           ],
           "minimum_should_match": 1
         }
       }
     ]
   }
 }
}

実行結果の一部

      "hits" : [
     {
       "_id" : "4",
       "_score" : 2.7260923,
       "_source" : {
         "author" : "川端康成",
         "title" : "雪国",
         "price" : 800
       }
     },
     {
       "_id" : "2",
       "_score" : 2.1507282,
       "_source" : {
         "author" : "村上春樹",
         "title" : "ノルウェイの森",
         "price" : 1000
       }
     }
   ]

例6 A or B or C

GET search_test/_search
{
 "query": {
   "bool": {
     "must": [
       {
         "bool": {
           "should": [
             {
               "match": {
                 "author": "村上春樹"
               }
             },
             {
               "match": {
                 "title": "舞姫"
               }
             },
             {
               "range": {
                 "price": {
                   "gte": 500,
                   "lte": 1000
                 }
               }
             }
           ],
           "minimum_should_match": 1
         }
       }
     ]
   }
 }
}

実行結果の一部

"hits" : [
     {
       "_id" : "2",
       "_score" : 2.1507282,
       "_source" : {
         "author" : "村上春樹",
         "title" : "ノルウェイの森",
         "price" : 1000
       }
     },
     {
       "_id" : "1",
       "_score" : 1.1507283,
       "_source" : {
         "author" : "村上春樹",
         "title" : "海辺のカフカ",
         "price" : 1200
       }
     },
     {
       "_id" : "4",
       "_score" : 1.0,
       "_source" : {
         "author" : "川端康成",
         "title" : "雪国",
         "price" : 800
       }
     },
     {
       "_id" : "3",
       "_score" : 0.5753642,
       "_source" : {
         "author" : "川端康成",
         "title" : "舞姫",
         "price" : 1400
       }
     }
   ]

minimum_should_matchを使ってより複雑な検索条件を記述する

minimum_should_matchとは、shouldクエリを利用した際に、条件項の一致率(数)を指定するパラメータです。

例えば、3つのOR条件のうち2つが一致していればマッチしたとする、などができます。

例7A or B or Cのクエリで、minimum_should_matchに2を指定

GET search_test/_search
{
 "query": {
   "bool": {
     "must": [
       {
         "bool": {
           "should": [
             {
               "match": {
                 "author": "村上春樹"
               }
             },
             {
               "match": {
                 "title": "舞姫"
               }
             },
             {
                "range": {
                 "price": {
                   "gte": 500,
                   "lte": 1000
                 }
               }
             }
           ],
           "minimum_should_match": 2
         }
       }
     ]
   }
 }
}

実行結果の一部

   "hits" : [
     {
       "_id" : "2",
       "_score" : 2.1507282,
       "_source" : {
         "author" : "村上春樹",
         "title" : "ノルウェイの森",
         "price" : 1000
       }
     }
   ]

minimum_should_matchが2なので、少なくとも2つ以上の条件にマッチする必要があります。

minimum_should_matchパラメータのデフォルト値
boolクエリにmust句(must_not含む)またはfilter句が含まれている場合、minimum_should_matchのデフォルト値は0になり、それ以外では1になります。
複雑な条件を指定する際は、意図しない挙動を防ぐために、明示的に指定するのが無難です。
※公式ドキュメント

matchクエリにおけるminimum_should_matchパラメータ

shouldクエリでの利用方法とは別に、matchクエリでもminimum_should_matchをオプションとして指定できます。

文字列の一致率を指定し、曖昧さを決めることができます。詳細は別の機会で説明します。

minimum_should_matchの多彩な記載方法

一致した条件項や文字数を指定する以外に、一致度の割合を%で指定できます。

例えば、検索文字列と90%一致した文字列をヒット扱いにする、などの利用方法があります。

これも詳細は別の機会で説明します。

まとめ

Elasticsearchのクエリを書く際には、複数の条件を組み合わせるためにboolクエリを使います。
boolクエリは、ANDとORの組み合わせだけでなく、「n個の条件のうちのk個以上を満たす」というような複雑な条件指定も可能です。
minimum_should_matchのオプションも使いこなして、boolクエリを活用しましょう。

Airitechではビッグデータ解析ツール導入・支援のほか、トラブルシュートやシステム性能サービスなど、さまざまなサービスを提供しております。

UiPathユーザー向けElasticsearch・Kibanaのオンライントレーニングも行っています。Elasticsearch・Kibanaに興味のある方は、ぜひご参加ください。

Elasticsearch・Kibanaトレーニング(オンライン)

また、Elasticsearchエンジニアの募集も行っていますので興味のある方はぜひご応募ください。

Airitechの採用情報はこちら

ホームページ


この記事が気に入ったらサポートをしてみませんか?