= Doar (ver 0.0.8) = '''概要''' Doarは、DoubleArrayの構築・検索を行うためのC++ライブラリです。 [[BR]] 現在(2009/11/1)で実装されている機能は以下の通りです。 ・DoubleArrayの構築・保存 ・ソート済みのキーセットから、DoubleArrayを構築 ※ 構築時の使用メモリ容量が少ない ・任意の順番のキーセットから、DoubleArrayを構築 ・構築したDoubleArrayをファイルに保存 ・一度保存したデータを読み込んで、更新(要素追加)、再保存 ・上で作成したDoubleArrayデータから、キーを検索する ・各キーを、0から始まるユニークなIDにマッピング (IDは挿入順で割り振られる) ・Rubyバインディング ※ 現在は、データ読込・検索のみ ---- '''環境''' ・現在(2009/11/1)は、sizeof(int)==4、となる環境を前提としています ---- '''使い方''' ・ルートディレクトリでmakeを実行することで、サンプルコマンドがbin以下に作成されます ・mkdoar: DoubleArray構築コマンド ・doar: 簡易検索コマンド ・ckdoar: 構築したDoubleArrayのテスト & ベンチマークコマンド ・具体的な使い方は、src/comman/以下の各ファイルを参照して下さい ---- '''簡易API C++''' '''※ まだ開発途中なので、APIは変更される可能性があります。''' {{{ code cpp namespace Doar { //=== ファイル: src/doar/builder.h === class Builder { // 引数のファイル(ソート済み)から、DoubleArrayを構築する // [返り値] // 成功: 0 // 失敗(ファイルオープン): -1 // 失敗(未ソートファイル): -2 ※ キーがユニークでは無い場合もこのエラーを返す int build(const char* filepath); // 引数の文字列配列(ソート済み)から、DoubleArrayを構築する // [返り値] // 成功: 0 // 失敗(未ソート文字列配列): -2 ※ キーがユニークでは無い場合もこのエラーを返す void build(const char** strs, unsigned str_count); // 引数のファイルにDoubleArrayを保存する bool save(const char* filepath); // DoubleArrayに格納されているキー数を取得する unsigned size() const; }; //=== ファイル: src/doar/node.h === struct Node { // IDを取得する unsigned id() const; // ノードが有効化どうか(検索に成功したかどうか)を返す operator bool() const; // ノードが葉(終端)かどうかを返す bool is_leaf() const; } //=== ファイル: src/doar/searcher.h === class Searcher { // DoubleArrayを引数のファイルから読み込む Searcher(cosnt char* filepath); // (コンストラクタで)無事に読み込めた場合はtrueを返す operator bool() const; // コンストラクタ呼び出し後のSearcherの状態 // 0 : 検索可能 // -1: ファイルオープンに失敗 // -2: ファイルフォーマットが不正 // -3: ファイルが壊れている const int status; // DoubleArrayに格納されているキー数を取得する unsigned size() const; // ルートノードを取得する Node root_node() const; // キーに対応するノードを探す // 検索に失敗した場合は、Node.valid()==falseとなる Node search(const char* key) const; // 初期ノード(root_node)を指定して、検索を行う // root_nodeには、最後に使われた親ノードが格納される ※ 終端ノードで一致した場合は、node.is_leaf()==trueとなる Node search(const char* key, Node &root_node) const; // common-prefix検索(走査)を行う // fnは、void fn(const char* key, unsigned key_offset, unsigned id)形式のファンクタ // fnは、keyに一致するノードが見つかった場合に、その都度呼び出される // ※ 現在、fnはconst指定されているので、fnが関数オブジェクトで、かつ可変メンバを使いたい場合は、そのメンバにmutableを指定して下さい template<typename Callback> void common_prefix_search(const char* key, const Callback& fn) const; // common-prefix検索(走査)を行う // root_nodeを指定することで検索を開始するノードが指定できる // fnは、void fn(const char* key, unsigned key_offset, unsigned id, Node node)形式のファンクタ // fnの引数のnodeは、一致したノードの親ノード ※ 終端ノードで一致した場合は、node.is_leaf()==trueとなる // fnは、keyに一致するノードが見つかった場合に、その都度呼び出される template<typename Callback> void common_prefix_search(const char* key, Node root_node, const Callback& fn) const; // parentの子ノード(のindex)を、走査する // fnは、 void fn(char arc_char, Node child_node, const char* tail)形式のファンクタ // child_node.is_leaf()の場合は、tailには遷移文字に続く文字列へのポインタが渡される (それ以外はNULL) template<typename Callback> void children(Node parent, const Callback& fn) const; }; //=== ファイル: src/doar/double_array.h === class DoubleArray { DoubleArray(); // keyをDoubleArrayに追加する // ※ keyはNULL終端で、途中に値が0xFFの文字を含むことはできない // 既にキーが挿入されている場合は、falseを返す bool insert(const char* key); // Searcherクラスの同メソッドと同様に働く // ただし、検索系のメソッドは、Searcherクラスのそれの方が最適化されている可能性がある unsigned size() const; Node root_node() const; Node search(const char* key) const; Node search(const char* key, Node &root_node) const; template <typename Callback> void common_prefix_search(const char* key, Callback& fn) const; template <typename Callback> void common_prefix_search(const char* key, Node root_node, Callback& fn) const; template <typename Callback> void children(Node parent, const Callback& fn) const; // pathに構築したtrieデータを保存する bool save(const char* path); // データを初期化する void clear(); // pathからtrieデータを読み込む // 読み込んだ後は、そのデータに対して、さらにinsertを行うことが可能 // ※ ただし、挿入効率は、ゼロから構築したtrieに比べて劣る // // [返り値] // 0 : 成功 // -1: ファイルオープンに失敗 // -2: ファイルフォーマットが不正 // -3: ファイルが壊れている int load(const char* path); } } }}} ---- '''インストール + 使用方法: Ruby''' '''※ まだ開発途中なので、メソッド等は変更される可能性があります。''' {{{ code ruby ## インストール方法 # cd $DOAR_ROOT/ruby # ruby extconf.rb # make # sudo make install require "doar" trie = Doar::Searcher.new("doar.dat") trie.size --> 1000000 # キー数 trie.key?("形態素") --> true trie["形態素"] --> 10 # ID trie["morpheme"] --> nil # trie.key?("...")==falseの場合 trie.common_prefix_search("形態素") --> [[3, 368117], [6, 368161], [9, 368162]] # [一致した文字列の位置,ID]の配列 trie.each_common_prefix("形態素"){|pos,id| puts "#{id}: #{'形態素'[0,pos]}" } 368117: 形 368161: 形態 368162: 形態素 --> nil trie.each{|key,id| # 格納されている全てのキーをiterate # ... } trie.each("日本"){|key,id| # "日本"で始める全てのキーをiterate # keyは、先頭に"日本"という文字列を必ず含む # 第二引数にfalseを渡した場合、共通(第一引数)部分が除去された文字列が渡される } }}} ---- '''TODO''' ・(このページを含めて)ドキュメント作成