PythonとElasticsearchで形態素解析

Elasticsearchから取り出してsklearnでテキストデータをゴニョゴニョするときにPython側ではIgoを使って形態素解析とかしていたけど、Elasticsearchでやっている形態素解析と一致しないのもなんだし、Igoを直読みするよりパフォーマンスは落ちると思うけど、辞書管理等々考えるとElasticsearchのanalyze APIを使って形態素解析しちゃった方がシンプルかなっと思い、まとめておく。
まず、PythonでElasticsearchのAnalyze APIが呼べることを以下で確認する。ここでは、Python 2.7を利用している。elasticsearch-pyもインストール済みな想定で、Elasticsearchも起動しておく必要がある。

$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> reload(sys)
<module 'sys' (built-in)>
>>> sys.setdefaultencoding("utf-8")
>>> from elasticsearch import Elasticsearch
>>> es = Elasticsearch(hosts="localhost:9200")
>>> text=u"今日の天気は晴れです。"
>>> es.indices.analyze(index=u"sample",body=text,params={u"field":u"message"})
{u'tokens': [{u'end_offset': 2, u'token':...

Python2の問題だけど、setdefaultencodingでセットしないとエラーになる。
エンコーディングさえ問題なければ、上記ではsampleインデックスのmessageフィールドのAnalyzerでtextをトークナイズできる。
まぁ、Ubuntuとかであれば、/etc/python2.7/sitecustomize.py の先頭に

import sys
sys.setdefaultencoding("utf-8")

を追加してdefaultencodingをutf-8にしてしまっても良いのかも。(最適な対応方法はわからない…) ほかの環境であれば、/usr/lib/python*/site-packages/sitecustomize.pyあたりに記述すればよい。
ここまで、できてしまえば、sklearnとかで使いたいなら、

class Analyzer:
    """Analyzer"""
    def __init__(self, es, index, field):
        self.es = es
        self.index = index
        self.field = field
    def __call__(self, text):
        if not text:
            return []
        data = self.es.indices.analyze(index=self.index,
                                       body=text, params={"field":self.field})
        tokens = []
        for token in data.get("tokens"):
            tokens.append(token.get("token"))
        return tokens

というような感じで、Analyzerクラスを作っておいて

es = Elasticsearch(hosts="localhost:9200")
analyzer = Analyzer(es, "sample", "message")
vectorizer = TfidfVectorizer(analyzer=analyzer)

みたいな感じで呼べば、いろいろなVectorizerで利用できると思います。

PythonでURLエンコード

urlibのquote/unquoteを利用する。

$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import urllib
>>> text=u"今日の天気は晴れです。"
>>> print text
今日の天気は晴れです。
>>> print urllib.quote(text.encode('utf-8'))
%E4%BB%8A%E6%97%A5%E3%81%AE%E5%A4%A9%E6%B0%97%E3%81%AF%E6%99%B4%E3%82%8C%E3%81%A7%E3%81%99%E3%80%82
>>> print urllib.quote(text.encode('euc-jp'))
%BA%A3%C6%FC%A4%CE%C5%B7%B5%A4%A4%CF%C0%B2%A4%EC%A4%C7%A4%B9%A1%A3
>>> print urllib.quote(text.encode('shift_jis'))
%8D%A1%93%FA%82%CC%93V%8BC%82%CD%90%B0%82%EA%82%C5%82%B7%81B
>>> print urllib.unquote('%E4%BB%8A%E6%97%A5%E3%81%AE%E5%A4%A9%E6%B0%97%E3%81%AF%E6%99%B4%E3%82%8C%E3%81%A7%E3%81%99%E3%80%82')
今日の天気は晴れです。

elasticsearch-pyを試す

ElasticsearchのPython用クライアントであるelasticsearch-pyを試してみる。
pipが利用できる環境であれば、

$ sudo pip install elasticsearch

とすれば利用できるようになる。
あとは、以下のような感じでes.pyとか適当に作って、

# -*- coding: utf-8 -*-
from datetime import datetime
from elasticsearch import Elasticsearch
es = Elasticsearch("localhost:9200")
# データの登録
res1 = es.index(index="sample", doc_type="data",
                  body={"msg":"Hello", "timestamp": datetime.now()}, id="1")
print(res1)
# 検索
res2 = es.search(index="sample", doc_type="data",
                 body={"query":{"match_all":{}}})
print(res2)
# インデックスの削除
res3 = es.indices.delete(index="sample")
print(res3)

これを実行すれば、アクセスすることができます。
結構、簡単に使えますね。

PythonでIgoを使う

形態素解析器IgoをPythonで利用する方法をまとめます。Mecabとかもありますが、クロスプラットフォームとかで環境準備しようとすると、面倒な部分もあるので…。
今回は、Ubuntu 14.04にインストールします。pipコマンドでインストールしようと思いますが、インストールしていなければ、インストールしておきます。

$ sudo apt-get install python-pip

そして、IgoをPythonで利用するためにigo-pythonをインストールします。

$ sudo pip install igo-python

インストールしたら、辞書を準備します。MecabのIPA辞書を以下のコマンドでIgo用の辞書に変換します。

$ wget -O igo-0.4.5.jar "http://sourceforge.jp/frs/redir.php?m=iij&f=%2Figo%2F55029%2Figo-0.4.5.jar"
$ wget -O mecab-ipadic-2.7.0-20070801.tar.gz "http://sourceforge.jp/frs/g_redir.php?m=jaist&f=%2Fmecab%2Fmecab-ipadic%2F2.7.0-20070801%2Fmecab-ipadic-2.7.0-20070801.tar.gz"
$ tar zxvf mecab-ipadic-2.7.0-20070801.tar.gz
$ java -cp igo-0.4.5.jar net.reduls.igo.bin.BuildDic ipadic mecab-ipadic-2.7.0-20070801 EUC_JP

igoのjarファイルとIPA辞書を取得して、igoのjarファイルを用いて、IPA辞書をipadicディレクトリに出力しています。
ここまでできたら、あとは動作確認します。たとえば、以下のようなtest.pyを作成して実行します。

# -*- coding: utf-8 -*-
from igo.tagger import Tagger
if __name__ == '__main__':
    tagger = Tagger('ipadic')
    words = tagger.parse(u'明日東京へ行く。')
    for word in words:
        print word.surface, word.feature, word.start

実行結果は以下のようになります。

明日 名詞,副詞可能,*,*,*,*,明日,アシタ,アシタ 0
東京 名詞,固有名詞,地域,一般,*,*,東京,トウキョウ,トーキョー 2
へ 助詞,格助詞,一般,*,*,*,へ,ヘ,エ 4
行く 動詞,自立,*,*,五段・カ行促音便,基本形,行く,イク,イク 5
。 記号,句点,*,*,*,*,。,。,。 7

以上のような感じで、Pythonで手軽に形態素解析を利用することができます。