The Definitive Guide から学ぶ Elasticsearch(You Know, for Search…)
前回の続き。このペースだと終わらないのでペースアップ。
You Know, for Search…
ここでは Elasticsearch の概要を学びます。Elasticsearch は Apache Lucene を内部で利用した検索エンジンです。Apache Lucene は Java 実装の OSS 検索ライブラリです。Elasticsearch だけでなく、Apache Solr でも利用されています。
Apache Lucene 自体でも以下のような機能を持ちます。
- 転置インデックス
- 検索
- スコアリング(ランキング)
- ソート
- 集計(Facet)
しかし、Apache Lucene 自体では以下のような機能は持ちません。
そこで Elasticsearch で Apache Lucene をラップすることで以下を可能としています。
Installing and Running Elasticsearch
ここでは Elasticsearch のインストール・起動について学びます。Elasticsearch の動作要件は最新バージョンの Java がインストールされていることだけです。Java さえインストールされていれば、Linux、Windows、Mac どこでも動作します。インストールも非常に簡単です。OS に応じたパッケージをダウンロードし、起動プログラムを実行するだけでインストールが完了します。
Sense という Elasticsearch の操作を簡単に行うことができる Kibana のプラグインのインストール方法が合わせて紹介されていますが、Kibana 5.0.0 以降から Console という名称で標準搭載しています。これから Elasticsearch を触られる方は気にしなくていいです。ただ Console は非常に便利なのでコマンドベースで操作している方は Console を利用されることをオススメします。
ここでは Elasticsearch の操作について学びます。最初に Java Client について紹介されていますが、今は HTTP ベースのクライアントがリリースされていますので紹介されているのは気にしなくていいです。Transport Client に関しても今後は新機能は実装されなくなるのでこれから使い始める方は Java REST Client を覚えましょう。
ここからが本題です。Elasticsearch は RESTful API で操作します。Elasticsearch がデフォルト設定で LISTEN するポートは tpc/9200 です。操作内容は HTTPメソッド、URLパス、JSON 形式の HTTP リクエストボディで決まります。いくつかcurl
コマンドベースの例です。
index という名前のインデックス作成
$ curl -XPUT http://localhost:9200/index
index という名前のインデックスの設定内容取得
$ curl -XGET http://localhost:9200/index
インデックス「index」のタイプ「type」に ID「1」でフィールド「name」の値が「elasticsearch」のデータを登録
$ curl -XPUT http://localhost:9200/index/type/1 -d '{ "name": "elasticsearch" }'
インデックス「index」を検索
$ curl -XGET http://localhost:9200/index/_search -d '{ "query": { "match": { "name": "elasticsearch" } } }'
Document Oriented
ここでは Elasticsearch が扱うデータについて学びます。Elasticsearch はドキュメントベース(JSON 形式)でデータを操作、管理します。ドキュメントベースは非常に扱い易いです。RDBMS ではシステム上データを扱う際にそのまま扱うことはほとんどできず、データを正規化して、分割して扱う必要がありました。Elasticsearch では配列やオブジェクトをそのまま扱うことができます。また列指向でデータをインデキシングするため、高パフォーマンスでの検索、ソート、フィルタリングを実現できます。
Finding Your Feet
ここから何節か跨いでサンプルデータを扱うことで Elasticsearch を学んでいきます。サンプルデータは従業員のデータです。HR では従業員のデータを様々な用途で検索します。
Indexing Employee Documents
ここでは Elasticsearch へのデータの登録について学びます。まずは Elasticsearch にサンプルデータを格納します。Elasticsearch にデータを格納することをインデキシングといいます。インデキシングの例は上記でサンプルのコマンドで紹介した通りです。インデックス、タイプ、ID、フィールドなどは下記をご参照ください。
豆
Elasticsearch は 3種類のインデックスという単語が登場します。
- 論理的なデータ格納先となるインデックス Elasticsearch の論理構成は RDBMS の論理構成と対比すると理解が早まります。
RDBMSの用語 | Elasticsearch |
---|---|
データベース | インデックス |
テーブル | タイプ |
カラム | フィールド |
主キー | ID |
データ登録のインデックス これは RDBMS の INSERT のようなものです。どちらかというとインデキシングと言われることが多いです。
転置インデックス 全文検索の手法の一つです。転置インデックス型全文検索と同じポジションなのが Grep 型全文検索(順次走査検索)です。
Retrieving a Document
ここでは Elasticsearch からのデータの取得について学びます。登録したデータを取得します。Elasticsearch は検索はもちろんですが、インデックス名、タイプ名、ID を指定することで一つのデータを取得することもできます。
Search Lite
ここでは Elasticsearch からのデータの検索について学びます。_search
API により検索できます。
- 何も指定しない場合、全件検索します。
- クエリストリングに
q
を検索キーワードを指定することで、簡易な条件の検索ができます。 - HTTP リクエストボディに JSON 形式の Query DSL を指定することで、複雑な検索、集計などを行うことができます。
- ほとんどはこの方法で検索します。
Search with Query DSL
ここでは Query DSL を利用したデータの検索について学びます。Talking to Elasticsearch で記載したように JSON 形式で Query DSL を記述します。例えば下記のような検索 API。
GET /megacorp/employee/_search { "query" : { "match" : { "last_name" : "Smith" } } }
インデックス「megacorp」、タイプ「employee」にあるデータからフィールド「last_name」が「Smith」のデータを検索します。
More-Complicated Searches
ここでは Query DSL についてもう少し学びます。先ほどは単純に名前の文字列を検索しました。Elasticsearch は文字列だけではありません。数値も扱うことができます。
GET /megacorp/employee/_search { "query" : { "bool": { "must": { "match" : { "last_name" : "smith" } }, "filter": { "range" : { "age" : { "gt" : 30 } } } } } }
先ほどの条件に加え、age(年齢)が 30以上のデータを取得しています。JSON が複雑になりましたが、一旦ここでは数値のフィルタリングもできるということを覚えてください。もちろん数値だけではなく、日付や時刻、珍しいところでは位置情報、IPアドレスなども扱うことができます。
Full-Text Search
ここでは転置インデックス型全文検索について学びます。RDBMS では物足りなくなり、Elasticsearch を利用する理由の一つになります。RDBMS でも全文検索できます。RDBMS ではLIKE
句を利用することで順次走査型全文検索できます。しかし、順次操作型全文検索ではLIKE
句ではインデックスを張れないため、データ量が多くなるにつれて全文検索のパフォーマンスが劣化が早いです。また含まれるか、含まれないかの Yes/No しか判断できないため、検索にヒットしたデータがどのくらい検索者の希望するものに近いのか判断することができません。転置インデックス型全文検索を利用することで全文検索のインデックス化によるパフォーマンス向上、ランキングによる検索データのスコアリングを行うことができます。詳細は別の章で説明することになるかと思いますのでここでは Elasticsearch だとこんなことができるのかと覚える程度で大丈夫です。
(RDBMS でも転置インデックス型全文検索できるものもあります)
GET /megacorp/employee/_search { "query" : { "match" : { "about" : "rock climbing" } } }
about フィールドに rock climbing というキーワードで検索します。
{ ... "hits": { "total": 2, "max_score": 0.16273327, "hits": [ { ... "_score": 0.16273327, "_source": { "first_name": "John", "last_name": "Smith", "age": 25, "about": "I love to go rock climbing", "interests": [ "sports", "music" ] } }, { ... "_score": 0.016878016, "_source": { "first_name": "Jane", "last_name": "Smith", "age": 32, "about": "I like to collect rock albums", "interests": [ "music" ] } } ] } }
Elasticsearch の match クエリはデフォルト「OR検索」のため、「rock」、「climbing」のいずれかが含むデータを返しますが、両方を含むデータの方がスコアリングにより「_score」の値が大きくなっています。
Phrase Search
ここではフレーズ検索について学びます。先ほどロッククライミングで検索したら、ロッククライミングと音楽のロックが検索ヒットしました。ただ音楽のロックは期待したことではありません。ここではノイズにしかなりません。rock climbing を連語と識別して検索方法にフレーズ検索があります。フレーズ検索は Query DSL で指定可能です。
GET /megacorp/employee/_search { "query" : { "match_phrase" : { "about" : "rock climbing" } } }
match
がmatch_phrase
になっただけですね。簡単です。
{ ... "hits": { "total": 1, "max_score": 0.23013961, "hits": [ { ... "_score": 0.23013961, "_source": { "first_name": "John", "last_name": "Smith", "age": 25, "about": "I love to go rock climbing", "interests": [ "sports", "music" ] } } ] } }
今度は音楽のロックは返ってきませんでした
Highlighting Our Searches
ここでは Elasticsearch のハイライト機能について学びます。例えば、Google 検索であるキーワードで検索した時、大体全て見きれない多くの結果が返ってきます。あなたはその多くある結果から該当するページを探す時、どう探していますか?上から順に見る方もいるかもしれません、タイトルで判断する方もいるかもしれません。タイトルの下の3,4行の説明文を見ていませんか?説明文には検索キーワードを含む文が表示されています。文脈を読むことができ、検索キーワードから期待する結果に近いのかどうか大きな判断材料となります。Elasticsearch ではハイライト機能という標準機能でそのような結果を返すことができます。また検索キーワードは特定の HTML タグを付与することで強調表示することも可能です。
GET /megacorp/employee/_search { "query" : { "match_phrase" : { "about" : "rock climbing" } }, "highlight": { "fields" : { "about" : {} } } }
先ほどのmatch_phrase
クエリにハイライトの Query DSL を付与するだけです。
{ ... "hits": { "total": 1, "max_score": 0.23013961, "hits": [ { ... "_score": 0.23013961, "_source": { "first_name": "John", "last_name": "Smith", "age": 25, "about": "I love to go rock climbing", "interests": [ "sports", "music" ] }, "highlight": { "about": [ "I love to go <em>rock</em> <em>climbing</em>" ] } } ] } }
文が短いのであまりありがたみが分からない結果となりましたが、rock と climbing にタグが付与されました。
Analytics
ここでは集計機能(Aggregation)について学びます。RDBMS の SQL では GROUP BY 句により、データ件数や数値データの合算などを集計することができます。Elasticsearch でも集計できます。Query DSL に Aggregation という機能があります。
GET /megacorp/employee/_search { "aggs": { "all_interests": { "terms": { "field": "interests.keyword" } } } }
aggs
は Aggregation 機能の宣言です。all_interests
は変数名、メソッド名みたいなものです。terms
は Terms Aggregation(Term の集計)を利用する宣言です。field
は Terms Aggregation の必須オプションで集計対象とするフィールドを指定します。今回はinterests.keyword
フィールドを指定しています。
{ ... "hits": { ... }, "aggregations": { "all_interests": { ... "buckets": [ { "key": "music", "doc_count": 2 }, { "key": "forestry", "doc_count": 1 }, { "key": "sports", "doc_count": 1 } ] } } }
フィールドinterests.keyword
からキーワード毎のデータ件数を集計します。musicを含むデータが 2件、forestry、sportsを含むデータが 1件づつあります。
検索結果を集計することもできます。
GET /megacorp/employee/_search { "query": { "match": { "last_name": "smith" } }, "aggs": { "all_interests": { "terms": { "field": "interests.keyword" } } } }
集計結果を更に集計することもできます。
GET /megacorp/employee/_search { "aggs" : { "all_interests" : { "terms" : { "field" : "interests.keyword" }, "aggs" : { "avg_age" : { "avg" : { "field" : "age" } } } } } }
これは興味があること毎の従業員の平均年齢を集計しています。
Tutorial Conclusion
ここではサンプルデータを使った説明のまとめです。ここまでで紹介したことは Elasticsearch の機能のほんの一部です。他にも様々な検索、集計ができますが、ここまでで学んだ Query DSL が変わるだけで複雑にはなりません。
Distributed Nature
ここでは Elasticsearch の分散性について学びます。チュートリアルのデータ量では意識する必要ありませんでしたが、Elasticsearch は数百(または数千)のサーバーにスケールアウトし、ペタバイトのデータを処理できます。Elasticsearch は簡単に複数ノードによるクラスタを組むことができます。