darts 0.32 + chasen 2.3.3 のインストールでエラーになる件

mecab 使えよって言われそうですけど、サーバ切替で手数を少なくするため、アプリにはなるべく手を入れたくないであります。

といいつつも、必要最低限の部分には手を入れているわけですが、一部の古いアプリで chasen 2.3.3 を使ったヤツがありまして、仕方なく chasen のインストールをしました。ほとんどのアプリが mecab ベースで作ってあるので、当然のように darts は最新の 0.32 をインストールしてあります。

chasen 2.3.3 は darts 0.2 をベースとして作られているので darts が 0.3 系にあがったときの一部の仕様変更について行けてません。

結果としてコンパイルエラーが発生します。

dartsdic.cpp: In function 'darts_t* da_open(char*, char*, char*)':
dartsdic.cpp:71: error: 'class Darts::DoubleArrayImpl >' has no member named 'setArray'
dartsdic.cpp: In function 'int da_build_dump(da_build_t*, char*, FILE*)':
dartsdic.cpp:186: warning: deprecated conversion from string constant to 'char*'
dartsdic.cpp:193: error: invalid conversion from 'char**' to 'const char**'
dartsdic.cpp:193: error: initializing argument 2 of 'int Darts::DoubleArrayImpl::build(size_t, const node_type_**, const size_t*, const array_type_*, int (*)(size_t, size_t)) [with node_type_ = char, node_u_type_ = unsigned char, array_type_ = long int, array_u_type_ = long unsigned int, length_func_ = Darts::Length]'
make[2]: *** [dartsdic.lo] エラー 1
make[2]: ディレクトリ `/usr/local/src/chasen/chasen-2.3.3/lib' から出ます
make[1]: *** [all-recursive] エラー 1
make[1]: ディレクトリ `/usr/local/src/chasen/chasen-2.3.3' から出ます

ここではその対処方法についてのメモを公開します。

- スポンサーリンク -

いや patch としては、とっても単純なんですけどね。自分で見つけるとなると意外とメンドウなわけでして・・・。

まずは x86_64 な環境の場合は、lib/dartsdic.cpp の 180 行目付近を以下のように変更します。
※赤文字の部分のように訂正します。

    while (i != entries->end()) {
        const std::string& key = i->first;
        last = entries->upper_bound(key);
        lex_indices.clear();
        for (; i != last; i++) {
            lex_indices.push_back(i->second);
        }
        lens[size] = key.size();
        //(const char*)keys[size] = key.data();
        keys[size] = (char*)key.data();

        vals[size] = redump_lex(lens[size], lex_indices, tmpfile, lexfile);
        if (vals[size] < 0) {
            std::cerr << "Unexpected error at " << key << std::endl;
            cha_exit_perror("build darts file");
        }
        size++;
    }

つぎに darts 0.32 対応。同じく、lib/dartsdic.cpp の 71 行目付近を以下のように変更します。
※赤文字の部分のように訂正します。

da_open(char *daname, char *lexname, char *datname)
{
    darts_t *da;
    DoubleArrayL *darts = new DoubleArrayL;

    da = (darts_t*)cha_malloc(sizeof(darts_t));
    da->da_mmap = cha_mmap_file(daname);
    //darts->setArray(cha_mmap_map(da->da_mmap));
    darts->set_array(cha_mmap_map(da->da_mmap));
    da->da = darts;
    da->lex_mmap = cha_mmap_file(lexname);
    da->dat_mmap = cha_mmap_file(datname);

    return da;
}

さらに 192 行目付近を以下のように変更します。※赤文字の部分のように訂正します。

    }
    std::cerr << size << " keys" << std::endl;

    DoubleArrayL da;
    da.build(size, (const char **)keys, lens, vals);
    da.save(builder->path->c_str(), "wb");

    return builder->entries->size();
}

以上で全てのエラーがとれて正常にコンパイルができるようになるかと思います。まぁ〜結局はアプリ側を改修して chasen 完全非依存な環境になったわけですけど、chasen である必要がある場合にお役に立てればと。

ちなみに mecab でなくって chasen を使いたい用途としては、TF-IDF 理論に基づいてコストを算出する際に、TF-IDF 専用のコーパスを用意しなくても、chasen の標準辞書内に含まれている生起コストを利用したい場合などです。

Kazuho@Cybozu Labs: キーワード抽出モジュールを作ってみた

このへんに詳細が書かれていますが、mecab の場合は 0.9 系の場合、辞書内の共起コストは IDF として用いることは間違いとのやりとりがなされています。

mecab 0.90 から CRF という方法を使っていて、単語正規コスト=~ idf と近時できるわけではありません。
mecab 0.81 や chasen が採用しているコストはそうやっても実用上は問題ないと思います。

さらにちなむと、手軽にTF/IDFを計算するモジュール - ダウンロードたけし(寅年)の日記 らへんに、それを解決した TF-IDF 計算手法についてのエントリがあったりします。w

- スポンサーリンク -