概要
TxはコンパクトなTrieを構築するためのライブラリです.従来のTrieの実装(darts等)に比べ1/4〜1/10の作業領域量で辞書を保持することができ、数億〜十億キーワードなど大規模な辞書を扱うことが可能です.Trieは文字列からなるキー集合を処理するデータ構造で、キーが辞書に含まれているかのみではなく、キーのPrefixが含まれているかを高速に求めることができます.内部データ構造にはSuccinct Data StructureであるLevel-Order Unary Degree Sequence (LOUDS)を利用しています.
ダウンロード
Txはフリーソフトウェアです.BSD ライセンスに従って本ソフトウェアを使用,再配布することができます.- tx-0.13.tar.gz: HTTP
Archives
- tx-0.12.tar.gz: HTTP
- tx-0.11.tar.gz: HTTP
- tx-0.10.tar.gz: HTTP
- tx-0.09.tar.gz: HTTP
- tx-0.08.tar.gz: HTTP
- tx-0.07.tar.gz: HTTP
- tx-0.06.tar.gz: HTTP
- tx-0.05.tar.gz: HTTP
- tx-0.04.tar.gz: HTTP
- tx-0.03.tar.gz: HTTP
更新情報
- 2009-04-13: Tx 0.13
- 0.13をリリースしました
- 構築時のメモリリークを修正しました
- 2008-06-03: Tx 0.12
- 0.12をリリースしました
- configure.acを修正しました(最新のUbuntuなどをサポートしました)
- 2008-05-28: Tx 0.11
- 0.11をリリースしました
- 辞書登録件数が0件の時、構築、検索で落ちるバグを修正しました.
- 2008-04-06: Tx 0.10
- 0.10をリリースしました
- デフォルトの検索個数を0から無制限に変更しました.
- mmap時のメモリ解放のバグなどを修正しました.
- 2008-03-23: Tx 0.09
- 0.09をリリースしました
- reverseLookup()を追加しました.
- サンプルプログラムにs2sbuild s2ssearchを追加しました.
- 2008-02-27: Tx 0.08
- 0.08をリリースしました
- setArray()を追加しました.
- commonPrefixSearch(), predictiveSearch()の引数が違うバージョンを追加しました.
- サンプルプログラムにtxsearch_mmapを追加しました.
- 2008-02-13: Tx 0.07
- 0.07をリリースしました
- commonPrefixSearch(), predictiveSearch(), getKeyNum()を追加しました.
- 2008-01-23: Tx 0.06
- 0.06をリリースしました
- txbuildが一行ずつ読み込む際に、キーワードにスペース等が含まれていても正しく動作するようにしました。
- 2007-12-24: Tx 0.05
- 0.05をリリースしました
- 標準エラー出力部分をそのまま出力せずに、getResultLog(), getErrorLog()で取得できるようにしました。
- 2007-10-06: Tx 0.04
- 0.04をリリースしました
- expansionSearchの機能とインターフェースを変更。部分マッチしたものを全て返すようにした。
- 2007-05-27: Tx 0.03
- 0.03をリリースしました
- prefixSearchのインターフェースを変更。keywordの固有IDとマッチ数を返すようにした。
- 2007-05-11: 性能評価に検索速度結果を追加しました
- 2007-05-02: Tx 0.02
- 0.02をリリースしました
- prefixSearchで最長マッチが見つからない場合を修正
- マッチを見つけるexpandSearchをインターフェースに加えた。
- 2007-03-03: Tx 0.01
- リリースしました
使い方
ソースコードで配布しています。configure; make; make install して使ってください。
ライブラリのみ使いたい場合は./configure; make; sudo make installして#include
Txは各行に1つずつキーが書かれたファイルを読み込み、辞書を構築しindexに保存します。利用するときはindexから読み込み、prefixMatchまたはexpandMatch呼び出します。
ライブラリとして使う例は、txbuild.cpp txsearch.cppを参照してください.
サンプルプログラムの説明
txbuild
% ./txbuild wordlist index各行に一キーが書かれたファイルからTx用の辞書を構築しindexに保存します.
txsearch
% ./txsearch index
辞書をindexから読み込み対話的に common prefix search を行います.
txsearch_mmap
% ./txsearch_mmap index
txserachと同様ですが、読み込む際に内部でメモリは確保せずにmmapを行います.
s2sbuild
% ./s2sbuild word2wordlist index
各行にtabで区切られた二つのキーワードが書かれたファイルから1列目のキーワードから2列目のキーワードへのマッピング用の辞書を構築し,index.1 index.2 index.12に保存します.index.1 index.2がそれぞれ1列目, 2列目のキーワードに対応するtx辞書であり,index.12が1から2へのマッピングテーブルです.
s2sserach
% ./s2ssearch index
s2sbuildで構築された辞書をindexから読み込み対話的に1列目のキーワードを入力として受け取り,全ての部分文字列に対しcommon prefix searchを行い,対応する2列目のキーワードリストを表示します.
使用例
% head wikipedia_titlelist 吉祥寺 改築 三越 円 なお 高い 定休 ファン 精肉 砂 .. % ./txbuild wikipedia_titlelist index word list 682496 elements outputSize:6790788 inputSize:9957698 ratio:68.20 % ./txsearch index >東京 prefixSearch id:118049 len:6 expansionSearch 11 東 東京 東京03 東京bbs 東京jap 東京r&d 東京人 東京国 東京大 東京市 東京府 commonPrefixSearch 2 東 (id=11298) 東京 (id=118049) predictiveSearch 10 東京 (id=118049) 東京03 (id=206482) 東京bbs (id=270748) 東京jap (id=270749) 東京r&d (id=270750) 東京人 (id=270751) 東京国 (id=270752) 東京大 (id=270753) 東京市 (id=270754) 東京府 (id=270755) (最初に表示される elemNumはキーの数、nodeNumはtrie中のnodeの数です) % ./head yomi2hyoki ーーー ○ー○ー○ー○ ーーー ○ー○。 ぁ (ぁ ぁみにぃ ぁみにぃ ぁみみ ぁみみ ぁゃゃ ぁゃゃ あ 「あ」 あ 媚理 あーう゛ぇう゛ぇ a.v.v あーうーおじゃままん アーウー・オジャママン あーういんしょう アーウィン・ショウ あーえすもなこ ASモナコ あーえぬあーまいれーじくらぶ ANAマイレージクラブ あーかーげー AKG あーかーと アーカート あーかーど アーカード あーかーよんなな AK47 あーかいう゛ アーカイヴ あーかいば アーカイバ あーかいぶ アーカイブ % ./s2sbuild yomi2hyoki y2hindex % ./s2ssearch y2hindex keyNum:174496 nodeNum:1620383 keyNum:195576 nodeNum:1530718 >どらごんくえすと どらご ドラゴ どらごん ドラゴン doragon dragon どらごんくえすと ドラゴンクエスト ドラゴン・クエスト Dragon Quest ドラゴンクエスト らごん ラゴン ごん GON! く クモハ313 くえすと クエスト クエスト えす E’S 「S」 SP-NX502 es [es] es Es すと 「スト」
メソッドの説明
int tx_tool::tx::build(vector<string>& wordList, const char* fileName) const
wordListを元にTxを構築しfileNameで指定されたファイルに保存します.このメソッドは構築して保存するだけであり,すぐ使いたい場合は,続いてreadを呼び出す必要があります.
wordListには保存したいキー集合入れます.必ずしもソートされている必要はありません。重複キーは構築時取り除かれます。
fileNameには保存先のファイル名を入れます.既にそのファイルがある場合はそのファイルは破壊されます.
int tx_tool::tx::read(const char* fileName)
TxをfileNameから読み込みます.失敗した場合は-1が返ります.
tx_tool::uint tx_tool::tx::prefixSearch(const char* str, const size_t len, size_t& retLen) const;
strに対し,そのprefixで最も長く一致したキーがある場合はそのキー固有の番号,一つも見つからない場合はtx_tool::NOTFOUNDを返します.retLenに一致したprefix長を返します.
キー固有の番号は登録したキー全てに0から順に番号が割り振られてます(必ずしも登録順とは一致しない).
tx_tool::uint tx_tool::tx::expandSearch(const char* str, const size_t len, vector<string>& ret, const size_t limit= TX_LIMIT_DEFAULT) const;
strに対し,そのprefixにマッチするキー,また,そのstrをprefixとして持つキー全てをretに入れて返します.commonPrefixSearchとpredictiveSearchの和集合が返されます.返り値はretに入った要素数です。limitを指定した場合,短いキー順に最大limitの個数だけ返されます.
tx_tool::uint tx_tool::tx:commonPrefixSearch(const char* str, const size_t len, std::vector<std::string>& ret, std::vector<uint>& retID, const uint limit = TX_LIMIT_DEFAULT) const;
strに対し,そのprefixにマッチする全てのキーをretに入れて,retIDにそれらのキー固有の番号を返します.返り値はretに入った要素数です。limitを指定した場合,短いキー順に最大limitの個数だけ返されます.
tx_tool::uint tx_tool::tx:commonPrefixSearch(const char* str, const size_t len, std::vector<uint>& retLen, std::vector<uint>& retID, const uint limit = TX_LIMIT_DEFAULT) const;
strに対し,そのprefixにマッチする全てのキー長をretLenに入れて,retIDにそれらのキー固有の番号を返します.返り値はretに入った要素数です。limitを指定した場合,短いキー順に最大limitの個数だけ返されます.
tx_tool::uint tx_tool::tx:predictiveSearch(const char* str, const size_t len, std::vector<std::string>& ret, std::vector<uint>& retID, const uint limit = TX_LIMIT_DEFAULT) const;
strに対し,そのstrをprefixとして持つキー全てをretに入れて,retIDにそれらのキー固有の番号を返します.返り値はretに入った要素数です。limitを指定した場合,短いキー順に最大limitの個数だけ返されます.
tx_tool::uint tx_tool::tx:predictiveSearch(const char* str, const size_t len, std::vector<uint>& retLen, std::vector<uint>& retID, const uint limit = TX_LIMIT_DEFAULT) const;
strに対し,そのstrをprefixとして持つキー長をretLenに入れて,retIDにそれらのキー固有の番号を返します.返り値はretに入った要素数です。limitを指定した場合,短いキー順に最大limitの個数だけ返されます.
tx_tool::uint tx_tool::tx:reverseLookup(const tx_tool::uint id, std::string& ret) const;
prefixSearchなどで得られたtx固有のidからキーを復元し,retに返します.返り値はキー長です。無効なidを入力した場合はretには空文字列,長さは0が返されます.
string tx_tool::tx::getResultLog();
構築時、読み込み時の詳細情報をstringで返します.
string tx_tool::tx::getErrorLog();
構築時、読み込み時に発生したエラーの詳細情報をstringで返します.
string tx_tool::tx::getKeyNum();
登録されているキーの数を返します.
string tx_tool::tx::setArray(void* ptr, size_t readSize);
ptrを読み込み用の入力ファイルとみなし,read()と同様にインデクスを読み込みます.mmapなどを使いたい場合にはread()の代わりにこれを利用してください.利用方法については添付のtxsearch_mmap.cppを参照してください.
TX_LIMIT_DEFAULTは0xffffffff(符号無し32bit整数の最大値)です。
性能評価
インデクス構築時間とサイズ
入力データ
- Web 1T 5-gram Version 1
- 1gmsのリストから出現頻度を除いたものを入力として作成
- キーワード種類数: 13,588,391
- キーワードをつなげたサイズ: 112,349,445 bytes
- trie中の葉も含めたノード数: 34,722,820
| インデクスサイズ(入力サイズ比) | 構築時のtime結果 | |
| tx 0.02 (txbuild) | 52,626,805 (46.8%) | 30.581u 1.137s 3:50.95 13.7% |
| darts 0.31 (mkdarts) | 406,358,432 (361.7%) | 16.688u 1.785s 8:13.52 3.7% |
検索処理時間
入力データと評価方法
- Wikipedia 日本語版から抽出されたキーワード
- キーワード種類数: 682,496
- つなげた長さ10,640,194 bytes (1キーワードあたり平均長16 bytes)
- trie中の葉も含めたノード数:4,531,308
- 登録した全キーワードをランダムに一回ずつ検索した時の平均時間(exact matchingのみ)
| 一回あたりの時間(micro-second) *1 | |
| tx 0.02 | 10.8 |
| std::map<std::string,int> | 4.06 |
| darts 0.31 | 1.05 |
| std::tr1::unordered_map<std::string,int> | 0.63 |
TODO
- インターフェースをきちんと作る
- 性能評価(クエリに関する速度評価)
- ソースにコメント書く
- 解説文書の充実
- 高速化、省メモリ化
- hatena keywordなどのアプリケーション例を充実させる
その他
つくばエクスプレス(tx)の行き帰りで作ったので、その名前がついています。
謝辞
ライブラリ作成などでkzkさんに協力していただきました.またtakuさんから有益なコメントをいただきました.ありがとうございます.
参考文献, リンク
- Tx, Bepの内部で使われている技術についての解説発表です (pdf|ppt)
- Bep: 最小完全ハッシュ関数を利用した連想配列.速い
- tx-ruby: TxのSWIGを利用したRuby binding.
- Macports: Macportsによるインストール方法解説
- Darts: Trieではよく使われている実装でDouble Arrayを用いてTrieを構築します。
- G. Jacobson. Space-efficient static trees and graphs. In Proc. 30th FOCS, 549-554
- O. Delpratt, N. Rahman, R. Raman. Engineering the LOUDS Succinct Tree Representation. (pdf)
Proceedings of WEA 2006, LNCS 4007, p. 134-145.
連絡先
コメントやバグ報告などありましたらこちらまで
Daisuke Okanohara (hillbig @ is.s.u-tokyo.ac.jp) (全角@を半角@に直してください)