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

 

参考

コメントを残す