晩秋のPECLまつり

溜まっていたものをまとめてリリース。PHP 6.0/5.3向けにビルドできなくなったのを修正したり、PHP6のUnicode文字列への対応を改善したりが主な変更点です。

  6.0 5.3 5.2 5.1 4.4 備考
php_continuation-0.1.1 × バグ修正。TODO: PHP6に対応する。
php_iovm-0.4.0 × × IoでのPHPサポートを強化。詳細はまた後日。
php_opendogs-0.6.1 バグ修正。TODO: 64ビット環境で扱える平衡三進法の桁数を増やす。
php_senna-0.1.2 × × QL APIのサンプルをr610で動作するように修正。
php_tokyocabinet-0.1.0 × × 最初のリリース。詳細は別エントリで
php_unichar-0.2.0 UTF-8の文字列をN-gramに分割する関数 unistr_ngram($str, $n) を追加。
php_yaml-0.2.0 TODO: LibYAML-0.1.1のAPIでエミッタを実装する。


unicharエクステンションに追加したunistr_ngram関数はちょっと良いですよ。UTF-8のバイナリ文字列もしくはPHP6のUnicode文字列しか扱えませんが、Pure PHPでやるよりずっと速くマルチバイト文字列から文字単位の (バイト単位でない) N-gramを作成できます。

<?php
dl('unichar.so');
print_r(unistr_ngram('UTF-8の文字列をN-gramに分割する。', 3));
?>
Array
(
    [0] => UTF
    [1] => TF-
    [2] => F-8
    [3] => -8の
    [4] => 8の文
    [5] => の文字
    [6] => 文字列
    [7] => 字列を
    [8] => 列をN
    [9] => をN-
    [10] => N-g
    [11] => -gr
    [12] => gra
    [13] => ram
    [14] => amに
    [15] => mに分
    [16] => に分割
    [17] => 分割す
    [18] => 割する
    [19] => する。
)
<?php
function my_ngram($str, $n)
{
    $ngram = array();
    $end = mb_strlen($str) - ($n - 1);
    for ($i = 0; $i < $end; $i++) {
        $ngram[] = mb_substr($str, $i, $n);
    }
    return $ngram;
}

// 青空文庫より芥川 竜之介「あばばばば」のテキストデータでテスト
// @link http://www.aozora.gr.jp/cards/000879/card14.html
$data = file_get_contents('ababababa.txt');
$data = mb_convert_encoding($data, 'UTF-8', 'SJIS-win');

$t0 = microtime(true);
$a = unistr_ngram($data, 3);
$t1 = microtime(true);
$b = my_ngram($data, 3);
$t2 = microtime(true);

var_dump($a == $b, $t1 - $t0, $t2 - $t1);
?>
bool(true)
float(0.0059678554534912)
float(0.37802219390869)

これをTokyo Cabinetと組み合わせて、内容のN-gramをキー、文書IDを値とするB+木データベースを作成すれば基本的な転置インデックスが実現できますね。配列の添字は位置情報とみなすことができるので、文書IDとペアで格納するのも良さそうです。