ふにゃるんv2

もとは、http://d.hatena.ne.jp/Wacky/

Hyper EstraierでPythonバインディングを使えるようにする(for Windows)

Webをぐるぐる回っていると、2chのDatファイルを高速検索するソフトを見つけました。

これを読んでいると、以下の特徴があるようです。

何の気なしにダウンロードして圧縮ファイルを展開すると、非常に少量のDLLで構成されているのに気付いて興味が沸きました。
一番気になったのが、estraier.dll がエンジン本体っぽくて、「あれ?結構簡単に配布できる仕組みになっているんだな?」と。
この手のソフトって、インストールの手間が非常に面倒だという固定概念が働いていたもので、面白そうだなぁと思った次第です。


○っぱい派としては、まずはPythonから使えるか調べてみた次第で、ぐぐると かなり引っかかる。


ただ、Linux派の方が多いようで、Windowsで動かしたよ〜とか書いてらっしゃる方は、ぱっと見、見当たりませんでした。むぅ。
という訳で、Windows環境でPythonバインディングを使えるようにしてみます

ダウンロード

まずは、Windows版のエンジンをゲットしないといけないので、以下からバイナリを取得します。

次に、言語バインディングのパッケージを取得します。Pythonバインディングの場合は、SWIGバージョンを使うようです。

更に、SWIGが必要なので、swigwinをゲットしましょう。(CygwinswigでもOKぽいです)

ビルドの前に(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 の関数を参照しているけど、リンクに失敗している」訳ですね。


で、暫く ぐぐると 以下の記事が。

おそらく,HEをWindowsで使うには,必要なDLLが同梱されているバイナリパッケージを使うことになると思う.だが,これには*.libが入っていない為,Pythonバインディングコンパイルすることが出来ない.なのでdllからlibを作るのが目標

…確かに、両方のアーカイブファイル共、LIBファイルが全く提供されてませんね。(何でだろう?)


LIBファイルが提供されていないなら、自分で作る必要があります。
一般的には、DLLファイルから dumpbin で 外部公開関数を EXPORTS し、これを DEFファイルとして LIBファイルを作るようです。


という訳で、以下のように作ります。
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

どうやらインストールは成功した模様です。

使ってみよう

早速使ってみましょう。
まずは、以下を参考に、インデックスを作成してみます。


え〜と、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

…えっ?と思う程、簡単に制御できちゃうもんですねぇ。
う〜ん、これを使って何か面白い事できそうかな?

まとめ


余談ですが、

の組み合わせでコンパイラが必要になるハズです。
VS2008は無償版があるので、Python 2.6の組み合わせが一番やりやすいかも知れません。