Hyper EstraierでPythonバインディングを使えるようにする(for Windows)
Webをぐるぐる回っていると、2chのDatファイルを高速検索するソフトを見つけました。
- Datファイル全文検索ソフト DatE
http://frozenlib.net/DatE/
これを読んでいると、以下の特徴があるようです。
- Hyper Estraierという全文検索エンジンを使って構築している
- ソフト自体は、.NET 3.5のWPFを使って実装しているようです
何の気なしにダウンロードして圧縮ファイルを展開すると、非常に少量のDLLで構成されているのに気付いて興味が沸きました。
一番気になったのが、estraier.dll がエンジン本体っぽくて、「あれ?結構簡単に配布できる仕組みになっているんだな?」と。
この手のソフトって、インストールの手間が非常に面倒だという固定概念が働いていたもので、面白そうだなぁと思った次第です。
○っぱい派としては、まずはPythonから使えるか調べてみた次第で、ぐぐると かなり引っかかる。
- 全文検索システム Hyper Estraier & DesktopHE を使ってみる - 傀儡師の館.Python - 楽天ブログ(Blog)
http://plaza.rakuten.co.jp/kugutsushi/diary/200702200000/ - HyperEstraierをPythonで使う - Solitaire
http://blog.redhawk.jp/2008/10/hyperestraierpython.html - Python : メモ用紙.txt
http://sinensis.plala.jp/mm/2ae6b2733aa1a8283eafe3eabb96f12df3e71f3c/#1287ba145b084bb8383a7bad7f4efc65b540b6d0 - 【IT-rescue】hyperestraier: python native bindingを作ってみた
http://memo.jj-net.jp/228
ただ、Linux派の方が多いようで、Windowsで動かしたよ〜とか書いてらっしゃる方は、ぱっと見、見当たりませんでした。むぅ。
という訳で、Windows環境でPythonバインディングを使えるようにしてみます。
ダウンロード
まずは、Windows版のエンジンをゲットしないといけないので、以下からバイナリを取得します。
- Windows版のバイナリパッケージ
http://hyperestraier.sourceforge.net/win/
次に、言語バインディングのパッケージを取得します。Pythonバインディングの場合は、SWIGバージョンを使うようです。
ビルドの前に(SWIGのセットアップ)
SWIGを入れた事の無い方は、まずはSWIGをセットアップしましょう。
といっても、展開してパスを追加するだけです。
自分がダウンロードしたのは、swigwin-1.3.36.zip で、これを展開してルートのパス位置を追加しました。
例えば、以下のように。
set PATH=C:\tool2\swig\swigwin-1.3.36;%PATH% set PYTHON_INCLUDE=C:\tool2\Python24\include set PYTHON_LIB=C:\tool2\Python24\libs\python24.lib
ビルドへ挑戦
という訳で、自分の場合、以下の2ファイルを取得しました。
- hyperestraier-1.4.10-win32.zip
- hyper_estraier_wrappers-0.0.15.tar.gz
hyperestraier-1.4.10-win32.zip には重要なDLLとEXEがあり、hyper_estraier_wrappers-0.0.15.tar.gz は、ルートに setup.py と SWIG で使われる HyperEstraier.i が転がっています。
READMEを読むと、以下のように入力せよと書いてありますが、これは Linux 向けの説明ですよね。
make python sudo make python-install
次に Makefileを読むと、以下のようにビルドするようです。う〜ん、makeを呼び出さずに直接、ここに書いてあるコマンドを打ち込みますか。
python: clean $(PYTHON) setup.py build_ext --swig-cpp $(PYTHON) setup.py build
早速、setup.pyを呼び出してみましょう。(Python 2.4で実行しています)
$ cd F:\Wacky\Test\HyperEstraier\hyper_estraier_wrappers-0.0.15 $ python setup.py build_ext --swig-cpp running build_ext building '_HyperEstraier' extension --swig-cpp is deprecated - use --swig-opts=-c++ swigging HyperEstraier.i to HyperEstraier_wrap.cpp C:\tool2\cygwin\bin\swig.exe -python -c++ -o HyperEstraier_wrap.cpp HyperEstraie r.i creating build creating build\temp.win32-2.4 creating build\temp.win32-2.4\Release C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\cl.exe /c /nologo /Ox /MD /W3 /GX /DNDEBUG -IC:\tool2\Python24\include -IC:\tool2\Python24\PC /TpHype rEstraier_wrap.cpp /Fobuild\temp.win32-2.4\Release\HyperEstraier_wrap.obj HyperEstraier_wrap.cpp f:\Wacky\Test\HyperEstraier\hyper_estraier_wrappers-0.0.15\HyperEstraierWrapper. cpp(4) : fatal error C1083: include ファイルを開けません。'estraier.h': No such file or directory error: command '"C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\cl.e xe"' failed with exit status 2
「estraier.h が無いよ!」と言ってます。estraier.h は、hyperestraier-1.4.10-win32.zip の方に転がっていますので、setup.py を少し弄ってパスを追加しましょう。
module1 = Extension( '_HyperEstraier', sources = ['HyperEstraier.i'], libraries = get_libs('estconfig --libs') + ['stdc++']) ↓ module1 = Extension( '_HyperEstraier', sources = ['HyperEstraier.i'], libraries = [], include_dirs = ['F:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\hyperestraier']) # ↑include_dirsで、estraier.hのある場所を指定している。 # ↑libraries内の estconfig は Windowsには無いツールなので、一旦空欄にしてます。
再度ビルド。
$ cd F:\Wacky\Test\HyperEstraier\hyper_estraier_wrappers-0.0.15 $ python setup.py build_ext --swig-cpp running build_ext building '_HyperEstraier' extension --swig-cpp is deprecated - use --swig-opts=-c++ swigging HyperEstraier.i to HyperEstraier_wrap.cpp C:\tool2\cygwin\bin\swig.exe -python -c++ -o HyperEstraier_wrap.cpp HyperEstraie r.i C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\cl.exe /c /nologo /Ox /MD /W3 /GX /DNDEBUG -IF:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\h yperestraier -IC:\tool2\Python24\include -IC:\tool2\Python24\PC /TpHyperEstraier _wrap.cpp /Fobuild\temp.win32-2.4\Release\HyperEstraier_wrap.obj HyperEstraier_wrap.cpp f:\Wacky\Test\HyperEstraier\hyper_estraier_wrappers-0.0.15\HyperEstraierWrapper. cpp(249) : warning C4800: 'ESTMTDB *' : ブール値を 'true' または 'false' に強制 的に設定します (警告の処理) ... C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:C:\tool2\Python24\libs /LIBPATH:C:\tool2\Python24\PCBu ild /EXPORT:init_HyperEstraier build\temp.win32-2.4\Release\HyperEstraier_wrap.o bj /OUT:build\lib.win32-2.4\_HyperEstraier.pyd /IMPLIB:build\temp.win32-2.4\Rele ase\_HyperEstraier.lib ライブラリ build\temp.win32-2.4\Release\_HyperEstraier.lib とオブジェクト bui ld\temp.win32-2.4\Release\_HyperEstraier.exp を作成中 HyperEstraier_wrap.obj : error LNK2019: 未解決の外部シンボル _est_cond_new が関 数 __wrap_new_Condition で参照されました。 ... error: command '"C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\link .exe"' failed with exit status 1120
おーまいがっ!!
LIBファイルを作ろう
先ほどのエラーメッセージ「未解決の外部シンボル _est_cond_new が関数 __wrap_new_Condition で参照されました。」の外部シンボル est_cond_new ですが、ぐぐると Hyper Estraier の定義関数である事が判ります。
つまり、「ラッパーコードから Hyper Estraier の関数を参照しているけど、リンクに失敗している」訳ですね。
で、暫く ぐぐると 以下の記事が。
- glucose : Hyper EstraierのPythonバインディングのビルド
http://glucose.jp/logs/shn/22
おそらく,HEをWindowsで使うには,必要なDLLが同梱されているバイナリパッケージを使うことになると思う.だが,これには*.libが入っていない為,Pythonバインディングをコンパイルすることが出来ない.なのでdllからlibを作るのが目標
…確かに、両方のアーカイブファイル共、LIBファイルが全く提供されてませんね。(何でだろう?)
LIBファイルが提供されていないなら、自分で作る必要があります。
一般的には、DLLファイルから dumpbin で 外部公開関数を EXPORTS し、これを DEFファイルとして LIBファイルを作るようです。
- VC++でDLLから.libファイルを作成するには?|C++ フリーでぷろぐらみんぐ
http://ameblo.jp/nana-2007-july/entry-10101317623.html
という訳で、以下のように作ります。
1.dumpbinを使って、外部公開関数を EXPORTS します。
$ cd F:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\hyperestraier $ dumpbin /exports estraier.dll > estraier.def $ dumpbin /exports regex.dll > regex.def $ dumpbin /exports qdbm.dll > qdbm.def
2.EXPORTSした出力内容を、DEFファイルの形式に修正します。例えば、以下のように。
LIBRARY estraier EXPORTS est_accept_conn est_border_str est_break_text est_break_text_chrcat ...
3.libを使って、DEFファイルからLIBファイルを生成します。
$ lib /def:estraier.def /MACHINE:x86 /out:estraier.lib Microsoft (R) Library Manager Version 7.10.6030 Copyright (C) Microsoft Corporation. All rights reserved. ライブラリ estraier.lib とオブジェクト estraier.exp を作成中 $ lib /def:regex.def /MACHINE:x86 /out:regex.lib Microsoft (R) Library Manager Version 7.10.6030 Copyright (C) Microsoft Corporation. All rights reserved. ライブラリ regex.lib とオブジェクト regex.exp を作成中 $ lib /def:qdbm.def /MACHINE:x86 /out:qdbm.lib Microsoft (R) Library Manager Version 7.10.6030 Copyright (C) Microsoft Corporation. All rights reserved. ライブラリ qdbm.lib とオブジェクト qdbm.exp を作成中
再度ビルド
作成したLIBファイルを、setup.pyの libraries に含めましょう。
module1 = Extension( '_HyperEstraier', sources = ['HyperEstraier.i'], libraries = [], include_dirs = ['F:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\hyperestraier']) ↓ module1 = Extension( '_HyperEstraier', sources = ['HyperEstraier.i'], libraries = ['estraier','regex', 'qdbm'], include_dirs = ['F:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\hyperestraier'])
それでは再度ビルド。
$ cd F:\Wacky\Test\HyperEstraier\hyper_estraier_wrappers-0.0.15 $ python setup.py build_ext --swig-cpp running build_ext building '_HyperEstraier' extension --swig-cpp is deprecated - use --swig-opts=-c++ swigging HyperEstraier.i to HyperEstraier_wrap.cpp C:\tool2\cygwin\bin\swig.exe -python -c++ -o HyperEstraier_wrap.cpp HyperEstraie r.i C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\cl.exe /c /nologo /Ox /MD /W3 /GX /DNDEBUG -IF:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\h yperestraier -IC:\tool2\Python24\include -IC:\tool2\Python24\PC /TpHyperEstraier _wrap.cpp /Fobuild\temp.win32-2.4\Release\HyperEstraier_wrap.obj HyperEstraier_wrap.cpp ... C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\bin\link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:C:\tool2\Python24\libs /LIBPATH:C:\tool2\Python24\PCBu ild estraier.lib regex.lib qdbm.lib /EXPORT:init_HyperEstraier build\temp.win32- 2.4\Release\HyperEstraier_wrap.obj /OUT:build\lib.win32-2.4\_HyperEstraier.pyd / IMPLIB:build\temp.win32-2.4\Release\_HyperEstraier.lib ライブラリ build\temp.win32-2.4\Release\_HyperEstraier.lib とオブジェクト bui ld\temp.win32-2.4\Release\_HyperEstraier.exp を作成中
お、ビルドできたようです。
では、インストール。
$ cd F:\Wacky\Test\HyperEstraier\hyper_estraier_wrappers-0.0.15 $ python setup.py build running build running build_py copying HyperEstraier.py -> build\lib.win32-2.4 running build_ext $ python setup.py install running install running build running build_py running build_ext running install_lib copying build\lib.win32-2.4\HyperEstraier.py -> C:\tool2\Python24\Lib\site-packa ges copying build\lib.win32-2.4\_HyperEstraier.pyd -> C:\tool2\Python24\Lib\site-pac kages byte-compiling C:\tool2\Python24\Lib\site-packages\HyperEstraier.py to HyperEstr aier.pyc
どうやらインストールは成功した模様です。
使ってみよう
早速使ってみましょう。
まずは、以下を参考に、インデックスを作成してみます。
- ウノウラボ Unoh Labs: Tips for HyperEstraier
http://labs.unoh.net/2008/10/tips_for_hyperestraier.html
え〜と、win版Hyper Estraierのルート(F:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\hyperestraier
)から doc フォルダに対して作業を掛けてみましょう。
$ cd F:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\hyperestraier $ estcmd create idx estcmd: INFO: status: name=idx dnum=0 wnum=0 fsiz=6899176 crnum=0 csiz=0 dknum=0 estcmd: INFO: closing: name=idx dnum=0 wnum=0 fsiz=6899280 crnum=0 csiz=0 dknum= 0 $ estcmd gather idx doc estcmd: INFO: reading list from the directory: doc estcmd: INFO: status: name=idx dnum=0 wnum=0 fsiz=6899280 crnum=0 csiz=0 dknum=0 estcmd: INFO: 1 (F:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\hyperest raier\doc\cguide-en.html): registered estcmd: INFO: 2 (F:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\hyperest raier\doc\cguide-ja.html): registered ... estcmd: INFO: closing: name=idx dnum=205 wnum=12358 fsiz=7643613 crnum=0 csiz=0 dknum=0 estcmd: INFO: finished successfully: elapsed time: 0h 0m 6s
…インデックスの生成って、結構あっけないもんですね。
気を取り直して、Pythonからインデックスデータを操作してみましょう。
$ cd F:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\hyperestraier $ python Python 2.4.2 (#67, Sep 28 2005, 12:41:11) [MSC v.1310 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import HyperEstraier >>> db = HyperEstraier.Database() >>> db.open("idx", HyperEstraier.Database.DBREADER) True >>> cond = HyperEstraier.Condition() >>> cond.set_phrase("python") >>> result = db.search(cond, 0) >>> for id in result: ... doc = db.get_doc(id, 0) ... for attr_name in doc.attr_names(): ... print "%s : %s" % (attr_name, doc.attr(attr_name)) ... @author : Mikio Hirabayashi @digest : f3f401613da4a5b6ee8333fea3bc548f @id : 3 @lang : en @size : 8034 @title : Hyper Estraier: a full-text search system for communities @type : text/html @uri : file:///F|/Wacky/Test/HyperEstraier/hyperestraier-1.4.10-win32/hyperestra ier/doc/index.html _lfile : index.html _lpath : file:///F|/Wacky/Test/HyperEstraier/hyperestraier-1.4.10-win32/hyperest raier/doc/index.html _lreal : F:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\hyperestraier\do c\index.html author : Mikio Hirabayashi content-language : en content-script-type : text/javascript content-style-type : text/css content-type : text/html; charset=UTF-8 description : homepage of Hyper Estraier keywords : Hyper Estraier, Estraier, full-text search, API @author : Mikio Hirabayashi @digest : f3f401613da4a5b6ee8333fea3bc548f @id : 3 @lang : en @size : 8034 @title : Hyper Estraier: a full-text search system for communities @type : text/html @uri : file:///F|/Wacky/Test/HyperEstraier/hyperestraier-1.4.10-win32/hyperestra ier/doc/index.html _lfile : index.html _lpath : file:///F|/Wacky/Test/HyperEstraier/hyperestraier-1.4.10-win32/hyperest raier/doc/index.html _lreal : F:\Wacky\Test\HyperEstraier\hyperestraier-1.4.10-win32\hyperestraier\do c\index.html author : Mikio Hirabayashi content-language : en content-script-type : text/javascript content-style-type : text/css content-type : text/html; charset=UTF-8 description : homepage of Hyper Estraier keywords : Hyper Estraier, Estraier, full-text search, API
…えっ?と思う程、簡単に制御できちゃうもんですねぇ。
う〜ん、これを使って何か面白い事できそうかな?