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?)などなど課題はつきませんが、一歩ずつ解決していきたいです。