Elasticsearchを久しぶりに勉強したのでメモ
ELKをまとめて触る予定だったが、今のログ収集ツールの流れでいうとLogstashよりかはFluentdな気がしたのと、自前k8sクラスタに導入する予定だったがELKだとあまりにも簡単そうだったので、EFKを勉強することにした。
Elasticsearchの書籍が読みたくていい本ないかなーと思ってたら、Kindle UnlimitedにElasticsearch実践ガイドがあったのでこれを読んで気になった点を以下にメモした
環境準備
これ通りで準備できた
https://www.elastic.co/guide/en/elasticsearch/reference/current/docker.html#docker-compose-file
Splitted Brain
ノード数は奇数にしなければならない。例えば2台だとネットワーク障害が起こったときに両ノードが自分をMasterノードと設定し別々のクラスタが出来上がってしまうため。
設定が必要なファイル。項目
-
elasticsearch.yml
- cluster.name
- node.name
- path.conf
- path.data
- インデックスデータの格納場所
- path.logs
- ログファイルの格納場所
-
jvm.options.d
- ElasticsearchはJVMの上で動いている。そのためメモリの設定については
/usr/share/elasticsearch/config/jvm.options.d
に設定を配置
- ElasticsearchはJVMの上で動いている。そのためメモリの設定については
-
log4j2.properties
-
JVMのヒープサイズはminとmaxを必ず同じにする
-
OSのメモリサイズの半分が適切
ドキュメントタイプ
1インデックスでの複数ドキュメントタイプはv7.0から完全に廃止された
https://www.elastic.co/jp/blog/moving-from-types-to-typeless-apis-in-elasticsearch-7-0
POST http://localhost:9200/my_index_x/my_type
でインデックスを追加したタイミングで my_type
というドキュメントタイプが生成される、この後に別のドキュメントタイプを作成することや、既存ドキュメントタイプのマッピングを変更することはできない。
ただし、既存ドキュメントタイプに新しくフィールド追加すること自体はサポートされている
ドキュメントタイプの現在の状態はGET .../{インデックス}/_mappings
で取得可能
https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html
7.xでは、RESTのURLにドキュメントタイプを指定する方法は非推奨、_doc
として定義しておく
インデックスの作成
- シャード数・レプリカ数はインデックスごとに設定できる
- 存在しているシャード数・レプリカ数より多く設定してもエラーは出ない
- シャード数の変更は後からできないがレプリカ数は後から変更できる
クエリの種類
- 基本クエリ
- 全文検索クエリ
- match_all
- match
- 空白で複数検索、AND検索は
operator
指定 - 最低N個のキーワードが含まれているもののみ
minimum_should_match
で可能- 数値または%の指定が可能
- 空白で複数検索、AND検索は
- match_phrase
A B C
で検索かけるとB C A
は表示されないがA B C
は表示される
- query_string
- kuceneのDSLを利用する
- termベースクエリ
- termクエリ
- 完全一致検索
- termsクエリ
- termクエリのOR検索
- rangeクエリ
- 数値・日付型の範囲検索
- gte,lteなどが利用できる
- 日付型の場合、特殊なクエリ(1週間以内=
now-1w
)も記述できる
- termクエリ
- 全文検索クエリ
- 複合クエリ
- boolクエリ
- 複数の基本クエリを組み合わせる
- 4種類のクエリを利用
- must: 指定されたクエリを必ず満たす。scoreに関係する(=Queryコンテキスト)
- should: 指定されたクエリのうちいずれかを満たすもののみ、複数満たすものはscoreが高い(=Queryコンテキスト)。minimum_should_matchも指定できる(=Queryコンテキスト)
- must_not: NOT条件。scoreに関係する(=Queryコンテキスト)
- filter: オプション。合致するかしないかのみが返却される。scoreに関係しない(=Filterコンテキスト)
- boolクエリ
boolクエリのfilterクエリについて
Queryコンテキストの検索より先に検索され、足切りとして利用される。すなはちキャッシュされることで次回以降に高速に検索できる
ソート
スコアとドキュメントのプロパティの昇順降順を組み合わせることが可能。
また、配列内の集計結果によってソートすることも可能(ex: 平均数や合計数)
Analyzer
CharFilter(0..N)とTokenizer(1)とTokenFilter(0..N)によって構成される
CharFilter
入力された文字列を前もって加工するためのフィルタ処理
ビルドイン↓
- HTMLStripCharacterFilter
- MappingCharacterFilter
- PatternReplaceCharacterFilter
Tokenizer
テキストの分割処理。分割したものはTokenと呼ばれる
ビルドイン↓
- 単語分割用
- StandardTokenizer
- WhitespaceTokeninzer
- LetterTokenizerなど
- N-gram
- N-gramTokenizer
- EdgeN-gramTokenizer
- 構造化テキスト用(メアド・URLなど)
- PathTokenizer
- KeywordTokenizer
- その他…
TokenFilter
分割したTokenを加工する処理
ビルドイン↓
- LowercaseTokenFilter
- StopTokenFilter:指定文字を除去
- StemmerTokenFilter:ステミング処理を行う
- SynonymTokenFilter:類似語を正規化する
aggregation
集計することができるSQLでいうGROUPBYやSUM/MAXなどの機能。
metrics,bucket,pipeline(matrix)に分類できる
metrics
平均・最大・最小など
cardinality:格納されている値の種類の数、SQLでいうdistinct count(*)
のようなイメージ。大量のメモリを利用する可能性があるため、HyperLogLog++
というアルゴリズムが利用されて概算値が算出される
significant terms
突出した値・特徴を検索することができる機能。
どの程度突出しているかは、score
に出力される。
スクリプティング
簡単なスクリプトを書くことができる。言語はPainless
というもの。文字通り簡単にかける
// 特定のフィールドの上書き更新
POST .../painless_test/_doc/1/update
{
"script": {
"lang": "painless",
"source": "ctx._source.price = params.new_price",
"params": {
"new_price": 200
}
}
}
// 古いインデックスから新しいインデックスを生成
POST /_reindex
{
"dest": {
"index": "painless_old"
},
"source": {
"index": "painless_new"
},
"script": {
"lang": "painless",
"source": "ctx._source.price = params.price_raise",
"params": {
"price_raise": 100
}
}
}
内部で利用しているLuceneについて
ElasticsearchでいうシャードはLuceneのインデックスをさす
Luceneでは、ドキュメントが追加されてもすぐにインデックスに格納されずメモリバッファに保存される。それが増えてくると、Luceneはセグメントという構造化された転置インデックスデータ領域にドキュメントを格納する。
また、この段階では検索対象にならず、refresh操作が必要になる。
すぐにデータが反映されないことをNearRealTimeと呼ぶ。LuceneがNearRealTimeであるためにElasticsearchもNearRealTimeである
refreshは定期的に実行される。デフォルトだと1秒。手動で行うこともできる
その他
- 正式名称はElasticSearchではなくElasticsearchだった
- 書籍でのElasticsearchのバージョンが古くて、書かれている操作をするとドキュメントタイプ関連でエラーが出た