2010年11月28日日曜日

Igo-pythonの導入メモ

igo-pythonを導入する一連の手順を書いてなかったので、ここに纏めておきます。

インストール

$ easy_install igo-python
もしくはhttp://pypi.python.org/pypi/igo-python/からソース配布物をダウンロード&展開して
python setup.py install

辞書のコンパイル

辞書作成はJava版のIgoで行うのでJavaが必要です。
ローカル版
Igoのサイトの手順そのままです。
準備
  • igo-0.4.2.jarの入手
  • 辞書のダウンロードと展開
$ java -cp igo-0.4.2.jar net.reduls.igo.bin.BuildDic コンパイル済み辞書出力先 ダウンロードした辞書を展開したところ 辞書の文字セット
$ java -cp igo-0.4.2.jar net.reduls.igo.bin.BuildDic ipadic mecab-ipadic-2.7.0-20070801 EUC-JP
GAE版
igo-gaeの手順です。 ローカル版との違いは使用するjarがigo-0.4.2-gae.jarなだけ。igo-0.4.2-gae.jarはigo-gaeのgithubから入手できます。

動作確認

ローカル版
$ python
Python 2.6.6 (r266:84292, Oct  9 2010, 11:40:09) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from igo.Tagger import Tagger
>>> for m in Tagger('ipadic').parse(u'すもももももももものうち'):
...   print m.surface, m.feature, m.start
... 
すもも 名詞,一般,*,*,*,*,すもも,スモモ,スモモ 0
も 助詞,係助詞,*,*,*,*,も,モ,モ 3
もも 名詞,一般,*,*,*,*,もも,モモ,モモ 4
も 助詞,係助詞,*,*,*,*,も,モ,モ 6
もも 名詞,一般,*,*,*,*,もも,モモ,モモ 7
の 助詞,連体化,*,*,*,*,の,ノ,ノ 9
うち 名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ 10
>>>
GAE版辞書をローカルで
>>> for m in Tagger('ipadic_gae', gae=True).parse(u'すもももももももものうち'):
...   print m.surface, m.feature, m.start... 
すもも 名詞,一般,*,*,*,*,すもも,スモモ,スモモ 0
も 助詞,係助詞,*,*,*,*,も,モ,モ 3
もも 名詞,一般,*,*,*,*,もも,モモ,モモ 4
も 助詞,係助詞,*,*,*,*,も,モ,モ 6
もも 名詞,一般,*,*,*,*,もも,モモ,モモ 7
の 助詞,連体化,*,*,*,*,の,ノ,ノ 9
うち 名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ 10
GAEで
@norioさんが置かれた gist: 716998 - igo-python gae test- GitHub https://gist.github.com/716998 で試すのが良いと思います。

Google App Engineでメモリを節約する

igo-pythonがGAEでもやっと動くようになったと思ったら、メモリの使いすぎで毎回インスタンスが終了されてしまう状態でした。メモリ使用量を削減したものをリリースしました(最初に出したのはバグってた。やっぱり文字と文字コードの扱いだった。@norioさんありがとうございます)

辞書の読み込みが問題(*)であることは見当がついていたので、幾つか思い当たる点をあたってみた。
  1. 文字列の連結で全部ロードしてからjoinするのをやめた
    • 少し減ったがほとんど効果なし
  2. バイト列で読んでからunicode化するのをStreamReaderで直にunicodeで読むようにした
    • 思ったより減らない
  3. Unicode文字列を使うのやめてarrayを使うようにした
    • 効果大
GAEのPythonはUCS4モードになっているので、大きいunicode文字列を持つとメモリの使用量が思った以上に増えてしまうことが分かった。それを連結したりしていたため最終的な文字列が出来ときに許容量をオーバーしていたと考えられる。
また、同じくメモリ節約のためarray.fromstringではなく、array.fromfileで読みたいため、いったんmmapは使わないようにした。pythonのmmapはコピーを作ってしまうので全部シーケンシャルに読んでしまうような使い方ではあまり効果がなさそうと判断した。

(*) 読み込みが終わっている状態では70MB程度で何度もインスタンスを作ったり、parseしても特に増えていく様子はなかった。

2010年11月27日土曜日

Igo for Pythonを使ってGoogle App Engineで形態素解析が出来た

@norioさんからコメントでGAEではos.fstatが存在していないことを教えていただきました。os.fstatが存在すればos.fstatを、そうでなければos.statを使うようにしたものをリリースしました。

これで、GAEにデプロイするアプリでもigo-pythonを使って形態素解析が出来るようになりました!ただ、メモリとCPUを使いすぎてしまうようなので、もう少し改善できないかみてみたいと思います。

2010年11月26日金曜日

PyPIに登録

Igo for PythonをPyPIに登録した。
これでeazy_install igo-pyでインストールできるようになりました。


登録方法は、Python Hack-a-thon 4 ハンズオン 中級コースPyPIデビューを参考にした。必要な情報は一通り書いてあるので困らなかった。

はまったのは、ReSTでかけるはずのlong_descriptionがどうしてもただのテキスト扱いになってしまうこと。litteral blockの最初の空行がなかったのが原因だったのだが、rst2htmlでの確認では気づかなかった。

2010年11月24日水曜日

Pythonはまりメモなど

移植時にはまったデフォルト引数の挙動。

>>> def f(a=[]):
...     print a
...     a.append('a')
... 
>>> f()
[]
>>> f()
['a']
>>> f()
['a', 'a']
>>> 
関数定義時に固定されるからと言うのが理由。すっかり忘れてた。


モジュール名を差し替えるやりかた。Python Hack-a-thonでPyQt4のHands Onに出たときから何とか出来ないかなーと思っていたもの(LinuxではPyQt4, WindowsでPySideをつかっているので)
まあこれでも長いけど…

sys.modules['モジュール名'] = モジュールオブジェクトでできる。

import sys
try:
    import PyQt
except:
    import PySide
    sys.modules['PyQt'] = PySide
from PyQt import QtCore
from PyQt import QtGui

形態素解析器IgoのPython版を作るときにはまったこと

IgoPythonへの移植がとりあえずのところまで来たので、メモをかねて記録。

何で移植しようかと思ったかと言えば

  1. Wooshを知って、WooshがせっかくPurePythonなら形態素解析器もPurePythonでと思った
  2. IgoはJavaで書かれているので、MeCabを移植するよりは移植が簡単だと思った
  3. PurePythonでそれなりの形態素解析器があれば、いろいろ遊んでくれる人も多いだろうと考えた

取りかかる前は、バイナリ辞書の扱いが一番面倒だと思ったけど、意外と問題なくすんだ。文字列もUTF-16でそのまま読むだけで動いている。
それよりは、javaではcharは整数なのに対して、pythonの文字は整数ではないのでordで整数値にしないといけないところがあり面倒だった気がする。

GAE版辞書対応はとりあえず出来てから取りかかったけど、思った以上に簡単にできた。

普段あまり使わない、struct, arrayと初めて使ったmmapもドキュメントがあるのでそれほど迷わず使えた。一番間抜けなのは、デフォルト引数の挙動で悩んでしまったこと。昔はまったことは解決したときに思い出した。

2010年11月21日日曜日

形態素解析器IgoのPython版作った

Java(とCL)で書かれた形態素解析器であるIgoをPythonにほぼそのまま移植しました。
Java版で作った辞書がそのまま使えるようにしたので、辞書を作る部分は(まだ)移植してません。
mmapしてるのでGAEでは動きません。すぐ取りかかる予定です。
またGAE版の辞書はBigEndianなのでそこらへんも対応する予定です。

https://code.launchpad.net/~hideaki-t/+junk/igo-pyに置きました。
簡単なテストしかしてません。問題があったら教えてください!

簡単なサンプル
# coding: utf-8
import igo.Tagger

t = igo.Tagger.Tagger('/mnt/dev/ipadic')
l = t.parse(u'こんにちは世界')
for m in l:
 print m.surface, m.feature, m.start

結果
~/works/igo-py $ python test.py
こんにちは 感動詞,*,*,*,*,*,こんにちは,コンニチハ,コンニチワ 0
世界 名詞,一般,*,*,*,*,世界,セカイ,セカイ 5


追記
  • mmapが使えなければFile IOで処理するようにしました
  • GAE版辞書モード追加しました
  • 複数回parse/wakatiすると結果がつながる問題を直しました
  • PyPIに登録しました
  • Python 2.5 on Linux, Python 2.6 on Windows/Linuxで動作を確認しました