Elasticsearchをメモ

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に設定を配置
  • 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で可能
            • 数値または%の指定が可能
      • 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)も記述できる
  • 複合クエリ
    • boolクエリ
      • 複数の基本クエリを組み合わせる
      • 4種類のクエリを利用
        • must: 指定されたクエリを必ず満たす。scoreに関係する(=Queryコンテキスト)
        • should: 指定されたクエリのうちいずれかを満たすもののみ、複数満たすものはscoreが高い(=Queryコンテキスト)。minimum_should_matchも指定できる(=Queryコンテキスト)
        • must_not: NOT条件。scoreに関係する(=Queryコンテキスト)
        • filter: オプション。合致するかしないかのみが返却される。scoreに関係しない(=Filterコンテキスト)

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のバージョンが古くて、書かれている操作をするとドキュメントタイプ関連でエラーが出た

See also