Pythonで使える形態素解析モジュールEsanpy

Pythonで日本語形態素解析をするならMecabやJanomeなどがありますが、日本語に限らずテキスト解析をするPythonモジュール[Esanpy](https://github.com/codelibs/esanpy)を紹介します。
Esanpyは内部的にはElasticsearchのテキスト解析機能を利用しているので、設定することで様々なトークナイズができます。Elasticsearch/Luceneでできることであれば、Esanpyでも可能です。あとは、Esanpyだけをインストールすれば利用可能なので、手軽に使えるところも魅力の一つです。

## インストール

pip installするだけです。

    $ pip install esanpy

Python 2.7か3.4〜で利用することができます。内部的にElasticsearchがJavaで動くので、Java 8が必要になります。javaコマンドをパスに通しておく必要があります。現時点ではWindowsでの動作を対応してません。

インストールすると、Pythonモジュールとして利用可能になり、esanpyコマンドも利用できるようになります。

## Pythonモジュール

以下のような感じでimportしておきます。

```
import esanpy
```

### テキスト解析サーバの起動

Esanpyは内部的にElasticsearchにアクセスして、形態素解析などのテキスト解析を行うので、以下の呼び出しでテキスト解析サーバを起動します。処理したいプログラムの開始時に一度呼び出して起動するなどが良いと思います。

```
esanpy.start_server()
```

初回起動時にはElasticsearchや必要なプラグインをダウンロードおよび設定するので少々時間がかかります（Esanpyが自動でセットアップするので、Elasticsearchを別途構築したりする必要はありません）。ダウンロードしたものは`~/.esanpy`ディレクトリに保存されます。問題などがあれば、そのディレクトリ以下のesanpy.logに出力されます。内部的に利用するElasticsearchはデフォルトで9299ポートで立ち上がります。`curl localhost:9299`のようにアクセスすると、正しく起動していれば応答があります。

### テキスト解析

Esanpyは`analyzer`と`custom_analyzer`を提供します。
`analyzer`はAnalyzer名を指定して呼び出し、`custom_analyzer`は`tokenizer`、`token_filter`および`char_filter`を組み合わせて呼び出すときに利用します。Analyzer、Tokenzier、Char Filter、Token Filterについて、詳しく知りたい場合はLuceneやElasticsearchのドキュメントを参照してください。簡単に説明すると、入力テキスト→Char Filter→Tokenizer→Token Filter→トークナイズされたテキスト群 の流れで処理されます。AnalyzerはChar Filter→Tokenizer→Token Filterをまとめたものになります。

まず、`analyzer`はテキストを渡すと分割されたテキストリストとして返ってきます。デフォルトのAnalyzerはstandardが適用されます。

```
tokens = esanpy.analyzer("This is a pen.")
# tokens = ["this", "is", "a", "pen"]
```

日本語形態素解析をしたい場合はkuromojiが利用可能なので、`analyzer="kuromoji"`を指定します。

```
tokens = esanpy.analyzer("今日の天気は晴れです。", analyzer="kuromoji")
```

`custom_analyzer`は`tokenizer`、`token_filter`および`char_filter`を組み合わせて呼び出します。以下の場合、`tokenizer="keyword"`はスペースで分割しないので、"this is a test"が返ります。

```
tokens = esanpy.custom_analyzer('This is a <b>test</b>',
                                tokenizer="keyword",
                                token_filter=["lowercase"],
                                char_filter=["html_strip"])
```

ElasticsearchのAnalyze APIについては、[Analyze](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-analyze.html)を参照してください。

### テキスト解析サーバの起動

テキスト解析サーバの停止は`stop_server()`を呼び出します。

```
esanpy.stop_server()
```

プログラムの終了時など、テキスト解析の処理をする必要がなくなったら呼ぶと良いです。

## esanpyコマンド

Esanpyは`esanpy`コマンドを提供しています。渡したテキストを改行区切りで分割して出力します。

```
$ esanpy --text "This is a pen."
this
is
a
pen
```

`esanpy`コマンドはテキスト解析サーバを起動していなければ自動で立ち上げます。そのため、初回起動時には時間がかかります。テキスト解析サーバが起動していればすぐに応答します。

Analyzerを指定する場合は`--analyzer`オプションを利用します。

```
$ esanpy --text 今日の天気は晴れです。 --analyzer kuromoji
今日
天気
晴れ
```

`--stop`オプションはテキスト解析サーバをコマンド終了時に停止します。ですので、`--stop`オプションを利用して、コマンドによるテキスト解析サーバの停止ができます。

```
$ esanpy --text "This is a pen." --stop
```

## その他

### Analyzerの登録

複雑なテキスト解析を行いたい場合は`create_analysis`を利用して、独自のAnalyzerを組み立てることができます。たとえば、`kuromoji_analyzer`というAnalyzerを作りたい場合は、`namespace`に`my_analyzers`を指定して作成できます。一つのnamespaceに複数のAnalyzerを登録することができます。

```
esanpy.create_analysis('my_analyzers',
                       char_filter={
                           "mapping_ja_filter": {
                               "type": "mapping",
                               "mappings_path": mapping_file
                               }
                       },
                       tokenizer={
                           "kuromoji_user_dict": {
                               "type": "kuromoji_tokenizer",
                               "mode": "normal",
                               "user_dictionary": userdict_file,
                               "discard_punctuation": False
                               }
                       },
                       token_filter={
                           "ja_stopword": {
                               "type": "ja_stop",
                               "stopwords": [
                                   "行く"
                                   ]
                               }
                       },
                       analyzer={
                           "kuromoji_analyzer": {
                               "type": "custom",
                               "char_filter": ["mapping_ja_filter"],
                               "tokenizer": "kuromoji_user_dict",
                               "filter": ["ja_stopword"]
                               }
                       }
                       )
```

`kuromoji_analyzer`を利用する場合は以下のように`analyzer`と`namespace`を指定して呼び出します。

```
tokens = esanpy.analyzer('①東京スカイツリーに行く',
                         analyzer="kuromoji_analyzer",
                         namespace='my_analyzers')
# tokens = ['1', '東京スカイツリー', 'に']
```

`namespace`を削除するには`delete_analysis`を呼び出します。

```
esanpy.delete_analysis('my_analyzers')
```

### Esanpyのアンインストール

Esanpyをアンインストールするには

```
$ ps aux | grep esanpy
$ kill [above PIDs]
```

のようにプロセスを確認して終了してから、`~/.esanpy`を削除してください。

```
$ rm -rf ~/.esanpy
```

そして、最後に

```
$ pip uninstall esanpy
```

すればアンインストールできます。