Elasticsearch + Python 基本機能の確認

#elasticsearch#Python

大量のテキストデータに対する検索を実装したかったので、全文検索について調べてみました。 ざっくりRDBMSと比べて全文検索が優れいてる点は検索速度、検索精度らしいです。 詳しい説明は他サイトを参照。

  とりあえず触ってみようが今回の目的です。

Elasticsearchインストール

登録が必要で面倒ですが、公式のビデオが参考になります。   まずJavaのバージョンを確認します。

java -version
java version "1.8.0_102"

  公式サイトからElasticsearchをダウンロードします。   解凍して、ディレクトリ内に移動してコマンドを打ちます。

bin/elasticsearch

  別のコンソールを開いてcurlでGETしてみましょう。

curl http://localhost:9200/

  するとJSONが帰ってくるのでElasticsearchの起動を確認できました。   Elasticsearchは適当なところに移動しておきましょう。   実行ファイルを起動するとローカルの9200番に開かれるということです。

IndexとTyep

Elasticsearchに実際にデータを入れていく前にIndexとTypeの違いをまとめます。 RDBになぞらえてシンプルにIndex = DB、Tyep = Tableと説明されることがあるらしいですが、正確には違うらしいです。 とりあえずはそんな感じの認識で進めます。   細かい意味は以下のページを参考にしてください。

PythonからElasticsearchを利用してみる

公式のPythonチュートリアル、APIドキュメントを参考にします。

  まずはpipでライブラリを入れます。

pip install elasticsearch

index(): ドキュメントの追加、更新

適当にPythonスニペットを書いていきます。 es = Elasticsearch()で特にオプションを記述しなければ、localhost:9200を見に行きます。   index()メソッドではドキュメントの追加、更新ができます。 引数にはindex、doc_type、bodyを必要とします。 この時点で指定したインデックス、タイプがなければ自動で作成されます。

from elasticsearch import Elasticsearch
es = Elasticsearch()
es.index(index="my-index", doc_type="test-type", body={"key": "value"})

  すると以下のような辞書が返ってきます。idは7P6CP2ABosfH4dF6PS98というのが振られたみたいです。 インクリメントでないのはRDBと違いますね。 これでmy-indexというインデックスにtest-typeというタイプで{“key”: “value”}というドキュメントが生成されました。

{'_id': '7P6CP2ABosfH4dF6PS98',
'_index': 'my-index',
'_primary_term': 1,
'_seq_no': 0,
'_shards': {'failed': 0, 'successful': 1, 'total': 2},
'_type': 'test-type',
'_version': 1,
'result': 'created'}

  ちなみに、以下のようにidを指定してドキュメントを作成することもできます。

es.index(index="my-index", doc_type="test-type", id=1, body={"key": "value1"})

get(): ドキュメントを取得する

このようにインデックス、タイプ、idを指定することで登録済みのドキュメントを取得できます。

es.get(index="my-index", doc_type="test-type",id=1

  以下のような辞書が返ってきます。

{'_id': '1',
'_index': 'my-index',
'_source': {'key': 'value1'},
'_type': 'test-type',
'_version': 1,
'found': True}

search(): ドキュメントの検索

適当にドキュメントを三つくらい追加しておきます。

es.index(index="my-index", doc_type="test-type", id=1, body={"key": "value1"})
es.index(index="my-index", doc_type="test-type", id=2, body={"key": "value2"})
es.index(index="my-index", doc_type="test-type", id=3, body={"key": "value3"})

  検索するためにはインデックスとクエリを指定します。 クエリにmatch_allとすれば全件取得できます。

es.search(index="my-index", body={"query": {"match_all": {}}})
{'_shards': {'failed': 0, 'skipped': 0, 'successful': 5, 'total': 5},
'hits': {'hits': [{'_id': '7f6GP2ABosfH4dF68C99',
'_index': 'my-index',
'_score': 1.0,
'_source': {'key': 'value'},
'_type': 'test-type'},
{'_id': '42',
'_index': 'my-index',
'_score': 1.0,
'_source': {'any': 'data'},
'_type': 'test-type'},
{'_id': '7v6HP2ABosfH4dF6qy_0',
'_index': 'my-index',
'_score': 1.0,
'_source': {'key': 'value'},
'_type': 'test-type'},
{'_id': '2',
'_index': 'my-index',
'_score': 1.0,
'_source': {'key': 'value2'},
'_type': 'test-type'},
{'_id': '7P6CP2ABosfH4dF6PS98',
'_index': 'my-index',
'_score': 1.0,
'_source': {'key': 'value'},
'_type': 'test-type'},
{'_id': '1',
'_index': 'my-index',
'_score': 1.0,
'_source': {'key': 'value1'},
'_type': 'test-type'},
{'_id': '3',
'_index': 'my-index',
'_score': 1.0,
'_source': {'key': 'value3'},
'_type': 'test-type'}],
'max_score': 1.0,
'total': 7},
'timed_out': False,
'took': 1}

*今入力した3件以外にテストで入れたドキュメントが引っかかっています。   このように条件をつければフィルターをかけることができます。

es.search(index="my-index", body={"query": {"match": {"key":"value1"}}})
{'_shards': {'failed': 0, 'skipped': 0, 'successful': 5, 'total': 5},
'hits': {'hits': [{'_id': '1',
'_index': 'my-index',
'_score': 0.6931472,
'_source': {'key': 'value1'},
'_type': 'test-type'}],
'max_score': 0.6931472,
'total': 1},
'timed_out': False,
'took': 2}

次回

と本当にざっくりまとめてみました。 求めるところはEBSにデプロイしたFlaskアプリケーション内の検索窓にオートコンプリートを実装することです。 今回はローカルで動かしてみましたが、EBSとの連携はどうするのか、オートコンプリートをどう実装するのか(Ajax?)などなど課題はつきませんが、一歩ずつ解決していきたいです。

参考