KWICを試す

はじめに

形態素解析辞書の登録単語の単位や品詞/活用などを考える時は、対象コーパスでその単語がどのような文脈で用いられているか調べたいことが多い。
単純にgrepコマンドやエディタの検索とかで調べればよいけど、検索速度や見やすさの問題があったりする。
KWICという用語索引の共通フォーマットがあり、見やすいのでこれを試しに作ってみる。

KWICとは

  • KeyWord In Contextの略語
  • 普通、辞書の後ろにある索引のような「単語」と「ページ番号」だけのでなく、「単語の前後の文章」を含むような索引のこと
    • KWIC indexは、単語についてソート&アラインメントされた索引リストのことを指す
    • permuted indexとも呼ばれるらしい
  • 1960年にLuhnによってconcordancerが作られたときにできた造語

アプローチ

やりたいのは、任意のコーパスについて、
http://chasen.org/~taku/software/ajax/kwic/index.html
のようなこと。


http://chalow.net/2005-02-28-5.html
にCとsaryでやってると書かれた。


ここでは、文字単位で前方文字列と後方文字列を作って、mysqlにいれて検索する方法で試してみる。
(mysqlの前方一致検索で。)

コード

#!/usr/bin/perl
# Usage: $ perl make.pl < TEXT_FILE > TEXT_FILE.mysql
use strict;
use warnings;
use Encode;
use utf8;
use Data::Dumper;
use List::Util qw(max min);

binmode STDIN, ":utf8";
binmode STDERR, ":utf8";
binmode STDOUT, ":utf8";

#前方向の文字数
my $FORWARD_TEXT_MAX_N = 5;
#後ろ方向(索引含む)の文字数
my $BACKWARD_TEXT_MAX_N = 5;

#行番号
my $line_num = 1;

#mysqlのため
print "create database KWIC default character set utf8;\n";
print "use KWIC;\n";
print "create table suffix_array (\n";
print "  id int primary key auto_increment,\n";
print "  backward text,\n";
print "  forward text,\n";
print "  line int\n";
print ") engine = MyISAM default charset = utf8;\n";
print "\n";


while(<>){
    chomp;

    my $line = $_;
    #$line =~ s/\t/ /g; #タブ文字は区切り文字で使うのでスペースに変更しておく

    my @sp = split(//, $line);
    my $n = scalar(@sp);

    for(my $i=0; $i<$n; $i++){
        my $forward_text = "";
        my $backward_text = "";

        #前方文脈
        for(my $j=max(0,$i-$FORWARD_TEXT_MAX_N); $j<$i; $j++){
            $forward_text .= $sp[$j];
        }
        #後方文脈
        for(my $k=$i; $k<min($n, $i+$BACKWARD_TEXT_MAX_N); $k++){
            $backward_text .= $sp[$k];
        }


        $forward_text =~ s/\"/\\\"/g;
        $backward_text =~ s/\"/\\\"/g;

        #出力
        #print $backward_text, "\t", $forward_text, "\t", $line_num, "\n";
        print "insert into suffix_array ";
        print "(forward, backward, line) values ";
        print "(\"" . $forward_text . "\",\"" . $backward_text . "\"," . $line_num . ");\n";
    }

    $line_num++;
}

実行結果

#テストテキスト
$ cat test.txt
今日は晴れでした。
明日は晴れるかな?
"今日は明日"

#mysql用ファイルの作成
$ perl make.pl < test.txt > text.txt.mysql

#mysqlへ登録
$ mysql < text.txt.mysql

#mysqlで前方一致検索(コマンドライン)
$ cat search.mysql
use KWIC;
select * from suffix_array where backward like "晴れ%";

$ mysql < search.mysql
id	backward	forward	line
4	晴れでした	今日は	1
13	晴れるかな	明日は	2

あとは、phpとかでbackwardをクエリとそれ以外に分解して、ソートしたり整形して表示すればよさそう。

参考