読者です 読者をやめる 読者になる 読者になる

ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

Elasticsearch の Query DSL の基本

Elasticsearch

この記事は 「Elasticsearch Advent Calendar 2013」 の 4 日目の記事です、とかしたかったけど Elasticsearch の Advent Calendar はなさそうなので普通に投稿します。

Elasticsearch でクエリを投げるときにお世話になる Query DSL。 とりあえず match クエリ ぐらいは見様見真似で書けていましたが、基本的な構造をちゃんと理解していなかったので調べてみました。

  • Query DSL って何?
  • クエリとフィルタって何が違うのか?

というような基礎的な話を公式ガイドを見ながらまとめました。 英語の理解が怪しかったりするので変なところは公式ガイドの方を見てください。

参照先ドキュメントの Elasticsearch のバージョン

Elasticsearch 0.90 のドキュメントを参照してこの記事を書きました。

しかしながら、文中のリンク先は最新版のドキュメントになっています。 将来的に Elasticsearch のバージョンが上がって本記事の内容とリンク先のドキュメントの内容がずれる可能性があります。

Query DSL

Query DSL の概要です。

  • Elasticsearch はクエリを記述するための JSON ベースの完全な (full) Query DSL を提供している
    • termprefix といった基本的なクエリもあれば、
    • bool クエリのような複合クエリ (compound queries) もある
  • Query DSL はクエリの抽象構文木とみなせる
  • 他のクエリを内部に持つことができるクエリ (例えば bool クエリ) もあれば、フィルタを持つことのできるクエリ (例えば constant_score クエリ) もあれば、両方を持つことができるもの (例えば filtered) もある
    • これらはそれぞれ、任意のクエリやフィルタを内部に持つことができるので、とても複雑な (そして興味深い) クエリを生成することが可能となっている
  • クエリもフィルタも、様々な API で使用することができる
  • 通常のクエリ (plain queries) と比べて桁違いに効率が良い *1 (スコアリングが行なわれず、自動的にキャッシュされるため) ので、フィルタはとても扱いやすい

最初に書いたように JSON ベースでクエリを記述する。 次の例は match query を用いたもの。

{
    "match" : {
        "message" : "this is a test"
    }
}

Queries

一般的には、次の場合にはフィルタではなくクエリを使うべきである:

  • 全文検索のために使用される場合
  • 結果が適合性スコア (relevance score) に依存する場合
クエリ一覧

公式ガイドの queries ページ (上に書いた参考のページと同一) にクエリ一覧がある: Queries

Filters

一般的には、次の場合にはクエリではなくフィルタを使うべきである:

  • 2 値の yes/no 検索に使用する場合
  • 完全一致での検索のクエリとして使用する場合 (for queries on exact values)
Filters and Caching
  • フィルタはキャッシュ対象の有力な候補である
    • フィルタの結果のキャッシングには多くのメモリは必要でない
    • キャッシュにより、同じフィルタ (同じパラメーター) に対するクエリ実行が著しく速くなる
  • いくつかのフィルタは、もともと (?) *2 キャッシュしやすい結果を生成する
    • 例として、termtermsprefixrange フィルタがここに含まれる
    • キャッシュするかどうかの違いは、キャッシュにその結果を保持するかどうかの違いでしかない (?)
    • デフォルトでキャッシュされるようになっている
    • 同じフィルタ (同じパラメータ) が複数の異なるクエリで使用される場合、これらのフィルタの使用が推奨される (?)
  • 他の、一般にメモリ上に読み込まれたフィールドデータを扱うフィルタは、デフォルトではキャッシュされない
    • 例として、geonumeric_range および script フィルタがここに含まれる
    • デフォルトでキャッシュされない理由は次の通り:
      • それらのフィルタは元々非常に高速である
      • 使用されたクエリとは別のクエリでも使用できるようにするために、キャッシュ処理に余分な処理が必要となる
  • 最後に、他のフィルタを扱うフィルタというものもある
    • andnot、そして or フィルタである
    • これらは基本的に内部のフィルタを処理するだけであるため、キャッシュされない
  • 明示的にキャッシュ処理を制御するため、すべてのフィルタには _cache 要素を設定することができる
  • 同様に、フィルタのキャッシュキーとして使用されるであろう _cache_key を設定することもできる
    • これはとても大きなフィルタを使うときに便利である
クエリ一覧

公式ガイドの filters ページ (上に書いた参考のページと同一) にクエリ一覧がある: Filters

参考になる書籍 (追記)

この記事を書いた当初は、日本語の Elasticsearch の書籍は 1 個もなかったのですが、現在では Elasticsearch の入門書が発売されています。 英語の公式ドキュメントを頑張って読むよりはわかりやすいですので、次の書籍を買うのも良いかと思います。

高速スケーラブル検索エンジン ElasticSearch Server

高速スケーラブル検索エンジン ElasticSearch Server

*1:もともと 「効率が良い」 とだけ書いていましたが、コメントを元に 「桁違いに」 を追記。 ここら辺英語がよくわかんないので違うかも。 原文は 『they perform an order of magnitude better than plain queries』

*2:『Some filters already produce a result that is easily cacheable』 の already ってなんなんだろう。