Elastic Searchをざっくり理解する2
-
全文検索とは、複数文書を対象として、特定の文字列が含まれる文章を検索すること
-
全文検索は大きく分けて2種類あって、逐次検索(grepコマンドなど)と、索引型検索の2種類ある。
- 逐次検索はシンプルではあるが、検索の対象となる文書の数や量が大きいと現実的な時間内に処理が完了しない
- 索引型検索は事前に索引(= インデックス)を構成しておいて、検索時にはこのインデックスをもとにキーから目的の文章を探す。
- インデックスを作るのがめんどくさいが、検索対象のサイズが大きいときは索引型検索の方が効率的に検索できる。
-
ESは索引型検索を行うソフトウェア。

ElasticSearchにドキュメントを投入すると、ドキュメントのフィールドのテキストがアナライザーによってトークン化(特定のルールに従って分離したもの)して、それらのトークンとそれらのトークンを含む文書をマッピングしたインデックスが作られる(この種類のインデックスを転置インデックスと呼ぶ)。
この転置インデックスを使用して文書を検索するから、検索スピードがはやい。
The index option controls whether field values are indexed. It accepts true or false and defaults to true.
indexオプションは、フィールド値にインデックスを付けるかどうかを制御します。trueかfalseを受け取り、デフォルトはtrueです。
デフォルトでは、各フィールドに対してインデックスが作られる
そのため、クエリを実行する際には、基本的にはフィールド単位で検索をする
The analyzer parameter specifies the analyzer used for text analysis when indexing or searching a text field.
analyzerパラメータは、テキストフィールドのインデックス作成や検索時にテキスト解析に使用する解析器を指定します。
text型の値だけアナライザーによってトークン化される。keyword型の値はトークン化されると検索結果として出てきて欲しくないものが出てきてしまい、バイアスになるので、keyword型は完全一致での検索の用途で使われる
そして、テキストフィールドの検索の時だけ、アナライザーでトークン化される。
マルチフィールド型という特殊なデータ型があって、これを使うと1つのフィールドに同時に複数のデータ型を定義できる
- あるフィールドに対して、text型による形態素解析された単語単位の検索をしたい
- あるフィールドに対して、keyword型による完全一致検索をしたい
上の2つの要件を満たす際に、マルチフィールド型が必要になってくる。
This version of Elastic® is built on Apache Lucene 9.9,
ESはApatch Luceneをベースに作られている
ESでは、検索機能のコアの部分はApatch Luceneが担っていていて、それにプラスしてREST API経由での操作や分散処理対応できるような仕組みを提供している。
(LuceneはJavaを書いて実行する必要があるので、ESを使うと、REST APIのインターフェースでLuceneを操作できるから、そこが便利)
ESでインデックスを作成すると、シャードと呼ばれる単位で分割されて、ノードに配置される。
(デフォルトのシャード数は1)
シャードに分割して各ノードに配置するメリット
- シャードを複数のノードに分散して配置することで、ノード1台あたりのリソース負荷を減らすことができる(= シャーディング or パーティショニングと呼ばれている)
(格納するデータ量が増大するにつれて、サーバーのCPU、メモリ、I/O負荷が上昇して、性能が徐々に低下することがある) - インデックスの検索が分散されて並列で実行できるので、検索性能が向上する
また、可用性を高める仕組みとして、各シャードに対して、レプリカと呼ばれる複製を1つ以上持たせることができる(デフォルトでは各シャードに対して1つのレプリカが自動的に複製される)。このレプリカを使うことで、シャードを保持するノードが1台ダウンしても、レプリカをもとに自動復旧することができるようになる。
Logstashは、データ、ログを収集・加工・転送するためのデータ処理パイプラインを実現するツールです。
Logstashは「Input」「Filter」「Output」の3つの要素から構成されます
ESにおいてドキュメントを保存する場所がインデックス。
ドキュメントがそのままインデックスに格納されているわけではなくて、アナライザーで単語分割したりして、転置インデックス情報を構成した上で、保存されている。
ESにおいては、ESが動作するサーバのことをノードと呼ぶ。
特定idのドキュメントをreadするだけなら、queryキーとかいらない。ただAPIを叩けばいい。
_search APIなどの検索APIを叩く際にqueryキーをリクエストボディに指定する必要がある。
検索クエリは省略版と、明示的に書いた場合の2パターンある
# 明示的に書いた場合
curl -X GET "http://localhost:9200/articles/_search" -H "Content-Type: application/json" -d '{"query":{"match":{"pdf_attachments.pages.content":{"query":"test_content2"}}}}' | jq
# 省略して書いた場合
curl -X GET "http://localhost:9200/articles/_search" -H "Content-Type: application/json" -d '{"query":{"match":{"pdf_attachments.pages.content":"test_content2"}}}' | jq
このコマンド使えば、存在するindexを確認できる。
curl -X GET "http://localhost:9200/_cat/indices?v&bytes=mb"
mappingはproperties句を書いて定義する。
properties句の中にはインデックスに含まれる各データ型定義(フィールドおよびデータ型)やアナライザーを指定する。
{
"properties": {
"user_name": { "type": "text"}
}
}
以下APIでインデックスのマッピングを定義できる
curl -X GET "http://localhost:9200/articles-ja/_mapping" | jq
Elasticsearchでは、基本的に一度定義したマッピングを差し替えることはできないので注意してください。差し替えたい場合は、新しいマッピングを定義した新しいインデックスにデータを移し替える操作が必要となります。
なるほど
クエリDSLは大きく次のように分類できる
- 基本クエリ
- 全文検索クエリ
- Termレベルクエリ
- 複合クエリ
- Boolクエリ
形態素解析は辞書にない単語を認識できないので、新語や人名などに弱い。
また、品詞の抽出結果によっては細かい検索漏れが起こる可能性がある。
N-gramは意図しないクエリでヒットしてしまうので、検索精度の面で問題になることがある。
またインデックスデータのサイズが増大する傾向にある
Analyzerは以下の要素で構成されている。
- char filter(任意の数を指定できる)
- tokenizer(1つだけ必要)
- token filter(任意の数を指定できる)
char filterは文字単位の処理
token filterはトークン(単語)単位での処理
Analyzer構成のカスタム定義
まず、ビルトインのAnalyzerを使わずに、Analyzerの構成をカスタム定義する方法を説明します。カスタムAnalyzerを利用するためには、以下のようにインデックス定義の"settings"句のなかに"analyzer"句を記述して、その中でAnalyzerの構成を定義します。
再インデックス
再インデックスは、既存のインデックスにあるドキュメントを別のインデックスにコピーする機能です。単なるコピーに加えて、ある条件のデータのみをコピーする、コピー時にコピー先のインデックス定義を変更するといった様々な操作が可能です。
読み終わったのでクローズ