Elasticsearch

Elasticsearchのbool queryを利用してAND OR NOTを書いてみる

More than 1 year has passed since last update.

初めてElasticsearchのクエリをビルドしたのでいろいろハマりました。SQLの世界観とちょっと違っていて、なれるまで時間がかかると思います。でも、なれたら複雑な検索条件をSQLより簡単に書けるかも知れません。

では、Elasticsearchの基礎クエリの一つ、Bool Queryを解説してみます。


Bool Queryについて

Elasticsearch 2.0からandクエリorクエリは全部非推奨になり、その代わりにboolクエリの方が推奨されます。Boolクエリは複数のクエリを組み合わせる(つまりAND、OR、NOTで結合)のに使います。

Boolクエリは4種類があります:must、 filter、 should、 must_notです。

クエリ
説明

must
ANDとして使います。小クエリは総合スコアに影響を与えます

filter
mustと同じくANDです。ただし、スコアは無視されます(総合スコアに影響を与えません)。

should
ORとして使えます。 minimum_should_matchパラメータで最低マッチする条項の数が指定できます1

must_not
NOTです。


使用例


AND条件

例えば、SQLはこういうSELECT文があります。

SELECT * FROM users WHERE age >= 25 AND salary >= 500000;

Elasticsearchのクエリに書き直すと、

{

"query": {
"bool" : {
"must" : [
{ "range" : { "age" : { "gte": 25 } } },
{ "range" : { "salary" : { "gte": 500000 } } }
]
}
}
}

になります。今回はmustを使いますが、スコア無視したい場合はfilterを使えばいいのです。


OR条件

SELECT * FROM users WHERE age >= 25 OR salary >= 500000;

Elasticsearchのクエリに書き直すと、

{

"query": {
"bool" : {
"should" : [
{ "range" : { "age" : { "gte": 25 } } },
{ "range" : { "salary" : { "gte": 500000 } } }
],
"minimum_should_match" : 1
}
}
}

になります。


NOT条件

SELECT * FROM users WHERE user_id NOT BETWEEN 525 AND 600;

Elasticsearchのクエリに書き直すと、

{

"query": {
"bool" : {
"must_not" : {
"range" : { "user_id" : { "gte": 525, "lte": 600 } }
}
}
}
}

になります。


AND、OR、NOTを組み合わせてみる

SELECT * FROM users WHERE (salary >= 500000 AND status = 'active')

OR (user_id NOT BETWEEN 525 AND 600);

Elasticsearchのクエリに書き直すと、

{

"query": {
"bool" : {
"should" : [
{
"bool" : {
"must": [
{ "range": { "salary" : { "gte": 500000 } } },
{ "term": {"status": "active" } }
]
}
},
{
"bool": {
"must_not" : {
"range" : { "user_id" : { "gte": 525, "lte": 600 } }
}
}
}
]
}
}
}

になります。

注意したいのはboolクエリはネストができるため、いくら複雑な条件にしても表現できます。


まとめ

条件
SQL
Elasticsearch

AND
WHERE A AND B
{"bool": {"must": [A,B]}

OR
WHERE A OR B
{"bool": {"should": [A,B]}

NOT
WHERE NOT A
{"bool": {"must_not": A}


おまけ

Elasticsearchクエリはポーランド記法と似ていますね。

例えば、3+4だったら+ 3 4になり、(1 + 5) * (2 + 3)だったら(* (+ 1 5) (+ 2 3))になりますね。なかなか面白いです!

では、よいサーチライフを!


参考文献





  1. 公式ドキュメントには書いてないがおそらくデフォルト値は1です。