1.Elasticsearch 特徴
- Apache Luceneをベースとした javaで書かれた全文検索ソフトウェア
- ログ収集・解析・分析プラットフォーム
- kibana、logstash
- 分散配置による高速、高可用性の実現
- クラスタ構成、分散ノード、シャード分割
RESTAPIアクセスによるリソース操作の明確化
- URLを参照すればどのリソースにアクセスしているか分かる
Elastic Stack
- Kibana
- バックエンドのElasticsearchにクエリ発行、可視化
- Elasticsearch
- Logstash
- Input, Filter, Output
- Beats
全文検索
- 索引型検索
- 転置インデックス(各単語と出現した文書IDの組み合わせをインデックスとして保存)
Doc1: イベントが東京で開催される
Doc2: 東京マラソンに参加する
単語 | DocId |
---|---|
東京 | 1, 2 |
イベント | 1 |
マラソン | 2 |
各単語は、英語の場合:空白区切り、日本語の場合:形態素解析
インデクサ (indexer)
- 対象ドキュメントから、単語を抽出し、インデックスのデータベースを構成
- メタデータとして、検索キーワードと関連ドキュメントを格納
サーチャー (searcher)
- インデクサが構成したインデックスに基づいて、検索クエリの機能を提供
- 検索サーバを利用するフロントエンドに対して、Java API、REST APIなどのインタフェースを公開
クローラー (crawler)
- 検索対象となるサイトからドキュメントを収集
- 定期巡回によるインデックス更新(インデクサに渡す)
1.Elasticsearch 基礎
ドキュメント (Document)
- RDBでいうところの1レコード
- 1つの文書
- Jsonオブジェクト形式
- ドキュメントをElasticsearchへ格納するときには、IDが採番される
- IDはインデックスへの格納時に明示的に指定することが可能
ドキュメントの例
{
"host" : "192.168....",
"user" : "MyName",
"date" : "2018-12-07T12:00:10"
}
フィールド
- ドキュメントの項目(Key,Value)のこと
- 転置インデックスは、フィールドごとに作成される
- クエリ実行時には、基本的にフィールド単位で検索することになる
- 文字列、数値、日付などの基本データ型、配列、ネスト構造などのデータ型もサポートされている
文字列
text型
- 文字列からなる文書を格納するデータ型
- ニュース記事の本文、商品説明、Blogエントリ本文などに使える
- 格納時に Analyzer によって単語に分割され、分割された単語ごとに転置インデックスが構成される
- クエリの際には、単語を指定することが可能
例:{"news" : "Powerful hurricane heads toward Ireland."}
keyword型
- text型と同様に文書を格納するデータ型
- Analyzer による分割処理は行われない
- クエリの際には、文書の完全一致で指定する
例:{"author" : "taro.yamada@example.com"}
数値
- long, short, integer, float
- 数値の大小比較、レンジ検索が可能
日付
- date(日付のみ、時刻、UNIXエポック表記のいずれか)
真偽値
- boolean(true, false)
オブジェクト
- 入れ子構造のJsonデータに対して定義可能
例:{"book" : {"title" : "elasticsearch guide", "price" : "500"} }
配列
- array
"ids" : [1,2,3] "city" : ["Tokyo", "Osaka", "Nagoya"] "vms" : [{"host" : "web1", "flavor": "small"}, {"host" : "web2", "flavor": "large"}]
マルチフィールド型
- 1つのフィールドに、text型、keyword型などの複数のデータ型を指定できる型
- マッピング定義で明示的に型を指定しない場合は、暗黙的にマルチフィールド型になる
インデックス
- ドキュメントの格納場所
- アナライザによる分割、転置インデックス情報など様々なデータ形式で格納される
ドキュメントタイプ
- ドキュメントの構造を表す抽象概念
- フィールドの型や属性情報などのデータ構造が定義されたもの
- 1つのインデックスに定義できるドキュメントタイプは1つ
マッピング
- ドキュメント内の各フィールドのデータ構造、データ型を記述した情報のこと
- マッピング定義をコマンドで行える
- 事前にマッピング定義しない場合、Elasticsearchが型推論によるマッピング定義を行う
物理概念
ノード
クラスタ
シャード
レプリカ
インデックスとドキュメントの基本操作
インデックス
- インデックス削除時に
"*"
、「_all」
を許可しない設定(誤動作防止)action.destructive_requires_name: true
ドキュメントタイプの管理
- ドキュメントの型、データ構造の定義
- 実際にバインドする場合をマッピングという(mapping句)
Json PUT /sandbox/_template/INDEX_NAME { "mappings": { "DOCUMENT_TYPE_NAME": { "properties": { "host": {"type": "keyword"}, "uri": {"type": "keyword"}, "method": {"type": "keyword"}, "accesstime": {"type": "date"} } } } }
インデックステンプレート
- 名前の異なるインデックス(日付が付与されるなど)間で共通のインデックステンプレートを作成することが可能
- インデックスを作成するタイミングで定義が反映される
GET /INDEX_NAME/DOCUMENT_TYPE_NAME/_mapping?pretty
で確認- テンプレートを複数定義した場合、
order
パラメータの小さい順で適用されるため、order
パラメータが最大のテンプレートで上書きされる可能性があることに注意する
Json PUT /sandbox/_template/my_template { "index_patterns": "accesslog-*", "settings": { "number_of_shards": 1 }, "mappings": { "accesslog_type": { "properties": { "host": {"type": "keyword"}, "uri": {"type": "keyword"}, "method": {"type": "keyword"}, "accesstime": {"type": "date"} } } } }
クエリ
範囲
GET API_ENDPOINT/INDEX_NAME/INDEX_TYPE_NAME/_search
/INDEX_NAME/_search
:INDEX_NAME
を対象に検索/INDEX_NAME/INDEX_TYPE_NAME/_search
:INDEX_TYPE_NAME
を対象に検索/INDEX_NAME1,INDEX_NAME2/_search
:INDEX_NAME1
、INDEX_NAME1
を対象に検索/INDEX_NAME*/_search
:INDEX_NAME
で始まるインデックスを対象に検索/_search
: クラスタ内の全てのインデックスを対象に検索
DSL
GET API_ENDPOINT/INDEX_NAME/INDEX_TYPE_NAME/_search
{
"query": {QUERY},
"from": 0,
"size": 10,
"sort": [検索結果のソート指定],
"_source": [検索結果に含めたいフィールド名を絞る]
}
query
: クエリ内容をJsonオブジェクトで記載from
: 検索結果の何番目から表示するのかsize
: 検索結果に含める件数sort
: 日付順や、複数フィールドにまたがったソートが可能_source
: 検索結果に含めたいフィールド名を絞る
クエリDSLの種類
全文検索クエリ
"match_all": {}
"match"
// 転置インデックスからの検索(text型)"operator": "and"
// AND 条件"minimum_should_match": 2
// 最低でも何件以上、何%以上"match_phrase": one two three
// 順番一致"query_string"
// Luceneシンタックス 低レベル検索用Termクエリ
"terms"
// 完全一致検索(keyword型)"range":
// 範囲指定- gte : 以上
- lte : 以下
- gt : より大きい
- lt : より小さい
{ "query": { "range": { "stock_price": { "gte": "15.00", "lte": "25.00" } } } }
// 日付指定 "birthday": { "gte": "2010-10-01", "lte": "2011-05-24" }
// 1週間以内 "manufactured_date": { "gte": "now-1w" }
Boolクエリ (複合クエリ)
{
"query": {
"bool": {
"must": [<基本クエリ>, <基本クエリ>,,,],
"should": [<基本クエリ>, <基本クエリ>,,,],
"must_not": [<基本クエリ>, <基本クエリ>,,,],
"filter": [<基本クエリ>, <基本クエリ>,,,]
}
}
}
}
"must"
: 必ず含まれているべきクエリ、AND条件と同じ意味"should"
: いずれかのクエリがヒットすればイイ、OR条件と同じ意味(minimum_should_match
を使うことも可能)"must_not"
: 除外クエリ、NOT条件と同じ意味"filter"
: スコアに関与しない除外(Filterコンテキスト、Queryコンテキスト)
ソート
フィールド名指定のソート
{
"query": {<クエリの検索条件>},
"sort": [
{"stock_price": {"order" : "desc"}}
]
}
フィールド名を複数指定したソード
{
"query": {<クエリの検索条件>},
"sort": [
{"stock_price": {"order" : "desc"}},
{"founded": {"order" : "asc"}}
]
}
スコアに基づいたソード
{
"query": {<クエリの検索条件>},
"sort": [
{"stock_price": {"order" : "desc"}},
"_score"
]
}
配列型データの計算結果に基づいたソート
- 配列の値の最小、最大、平均などの計算結果に基づいたソート
- “avg” : 平均
- “min” : 最小
- “max” : 最大
- “sum” : 合計
- “median” : メジアン
// この例では平均 "sort": [ {"dayoff": {"order" : "desc", "mode" : "avg"}} ]
4章 全文検索とAnalyzer
- インデックスへドキュメント(text型)の格納時(転置インデックスの作成)、検索時の検索文字に対して形態素解析を行う
ステミング
- 語形の変化を揃えて同一表現に統一する処理
- “dogs” -> “dog”
- “食べる”、”食べた”、”食べます” -> “食べ”
正規化
- 大文字、小文字、カタカナ、ひらがな、全角、半角を揃える処理
ストップワード
- 冠詞、前置詞、助詞などの単体で意味を持たない単語を除外する処理
- Elasticsearchは、標準で
English Analyzer
をサポートしている
Analyzerの定義
マッピング定義で定義
"mappings": {
"my_type": {
"properties": {
"blog_message": {
"type": "text",
"analyzer": "standard"
}
}
}
}
Analyzer内部構成
- Char filter
- 入力テキストの前処理
- 文字単位の変換処理
- HTML Strip Character Filter -> タグ除去(
とか) - Mapping Character Filter -> 入力文字に含まれる特定文字にマッピングルールを定義し、変換する(例 ”:)” -> “happy“)
- Pattern Replace Character Filter -> 正規表現ルールで入力文字を変換する(例 “123-456-789” -> “123_456_789”)
- Tokenizer
- Char filterの出力データを入力として、テキスト分割処理をし、トークン(単語)の列を生成する
- 単語分割用Tokenizer :
- N-gram分割用Tokenizer :
- 構造化テキスト分割用Tokenizer :
- Token filter
- Tokenizerが分割したトークン(単語)に対して、トークン単位での変換処理を行うためのフィルタ機能
- Lower case Token filter
- トークン文字を小文字に変換
- Stop Token filter
- ストップワードの除去を行うフィルタリング
- Stremer Token filter
- ステミング処理を行うフィルタ
- Synonym Token filter
- 類義語(シノニム)を正規化して1つの単語に変換するためのフィルタ
Analyzerのカスタム定義
- TODO
Aggregation
- 検索結果の集合に対して、分類や集計を行うことができる機能
- ドキュメントを特定のグループに分類することができる
- そのグループごとの件数、最大値、平均値といった統計量の値を返すことができる
- 任意のクエリでドキュメントをし盛り込みながら、同時にAggregationを実行する操作が1回のクエリで行える
Metrics
- 分類された各グループに対して、最小、最大、平均などの統計値を計算する
- SQLの
COUNT
に近い
Buckets
- ドキュメントをフィールド値に基づいてグループ化するための分類方法 (書籍の価格ごと、書籍のジャンルでグループ化)
- SQLの
GROUP BY
に近い
Pipeline
- Bucketsなどの他のAggregationの結果を用いて、さらに集計をする機能
Matrix
- 複数フィールドの値を対象に相関、共分散などの統計値を計算する機能
分類と集計の例
Aggregation Query
Book Index {
"タイトル": text,
"ジャンル": keyword,
"発売日": date,
"価格": logn
}
Bucktes(ビジネス) | Metrics(平均価格) |
---|---|
“ビジネス” | 3400 |
“文学” | 1350 |
“コンピュータ” | 3200 |
Aggregation文法
"aggregations": {
"<AGGREGATION_NAME>": {
"<AGGREGATION_TYPE>": {
"<AGGREGATION_BODY>"
}
}
}
"aggregations"
句は、"aggs"
と省略可能"<AGGREGATION_NAME>"
は任意の名前"<AGGREGATION_TYPE>"
は、"Metrics"
、"Buckets"
、"Pipeline"
、"Matrix"
の機能タイプを定義する
("Metrics"
タイプであれば、"sum"
、"avg"
、"Buckets"
タイプであれば、"range"
など)
Metrics文法
- query句を使う方法
- query句でデータセットを絞り込み、Metricsの集計を適用する
- Bucketsを使う方法
- Bucketsを使ってドキュメントをグループ化し、グループ化されたデータセットに対して、それぞれMetricsの集計を適用する
- 何も指定しない方法
- インデックスに格納されているドキュメント全体の統計値を計算する
"size"
に0を指定すると、"aggs"
の計算結果だけを返すことができる
// query句を使う方法 "size": 0, "query": { "match": { "office": "1" } }, "aggs": { "svg_hoge": { "avg": { "field": "salary" } } }