« YAPC && Hackathon && return $HOME | メイン | Template::Plugin::FillInForm »

SEN_INDEX_DELIMITED

id:tasukuchanさんにSennaのSEN_INDEX_DELIMITEDを実装していただいたので、試す。

MySQLを用意するのが面倒なので、Senna.pmで試すことにする。
XSというかCをほとんど知らないので間違っていたら指摘してくださいです。

まずpatch

  • Senna.xsにSEN_INDEX_DELIMITEDとmysql風queryメソッド追加
  • SEN_INDEX_DELIMITEDとqueryの簡易テストのt/04-delim.tを追加
  • NGRAM onlyのcreateはエラーになるようなので修正

ファイルは以下
http://nomadscafe.jp/tmp/Senna-0.11.patch

queryのテストとして、前回と同じデータを入れて以下を作って実行
スクリプトはエレガントじゃないけど気にしない。

Senna.pmをいちいちインストールは面倒なので、このファイルをSenna.pmのdistディレクトリにいれて実行します。

#!/usr/bin/perl

use strict;
use warnings;
use FindBin;
use lib ($FindBin::Bin,"$FindBin::Bin/lib","$FindBin::Bin/blib/lib","$FindBin::Bin/blib/arch");
use Senna::Index qw(:all);
use Text::Tags::Parser;
use Encode;
use File::Spec;

my @tags = (
q/task femo/, #1
q/femo mail task/, #2
q/task femo/, #3
q/task plagger/, #4
q/task 2006-03-27 "perl monger"/, #5
q/task 終了/, #6
q/feedback femo task dev/, #7
q/task feeder dev/, #7
q/femo task dev/ #8
);

my $index_name = 'test-delimited.db';
my $path       = File::Spec->catfile($index_name);
my $index      = Senna::Index->create($path, SEN_VARCHAR_KEY, SEN_INDEX_DELIMITED);

my $i = 1;
for my $tags (@tags){
    my @unpacks;
    $tags = Encode::decode_utf8($tags);
    for my $tag (Text::Tags::Parser->new->parse_tags($tags)) {
        push @unpacks, &normalize($tag);
    }
    $index->put($i, join(' ', @unpacks));
    $i++;
}

for my $q (qw/task femo 終了/,"perl monger",{
    plus => [qw/task femo/],
    minus => [qw/終了/]
}){
    print &querize($q),",\n";
    my $cur = $index->query(&querize($q));
    while (my $r = $cur->next) {
        printf("%s\n", $r->key);
    }
}

sub querize{
    my $obj = shift;
    return "*E-1 ".&normalize($obj) unless ref $obj;
    $obj->{plus} ||= [];
    $obj->{minus} ||= [];
    my $plus = join " " , map { "+" . &normalize($_)  } @{$obj->{plus}};
    my $minus = join " " , map { "-" . &normalize($_)  } @{$obj->{minus}};
    return join " " , "*E-1", $plus, $minus;
}

sub normalize{
    my $str = shift;
    $str = Encode::decode_utf8($str) unless utf8::is_utf8 $str;
    return join 'x', map { sprintf("%02x",$_) } 
            unpack("U*", $str);
}


*E-1は完全一致検索のみを行うというプラグマ。詳しくはここ
結局unpackしているのは、"perl monger"の様に間にスペースを含むものもあるからです。

実行すると、

+74x61x73x6b +66x65x6dx6f -7d42x4e86
1
2
3
7
9

っていうのが最後にでます。
これは、「task」と「femo」を含んで「終了」を含まない、という条件で検索した結果で、前回と同じになってます。

ってことで、SEN_INDEX_DELIMITEDはイケテそうです。
問題はMySQLの移行かぁ。

トラックバック

この一覧は、次のエントリーを参照しています: SEN_INDEX_DELIMITED:

» [Perl][CDBI] has_manyなテーブルでAND検索 - Class::DBI::Sweet::Cake from 浅倉卓司@blog風味?
http://asakura.g.hatena.ne.jp/asakura-t/20060330/1143721817 ――とか出来るようになるモノを作... [詳しくはこちら]

コメント

おお、いけてましたか。。。
よかったよかった。

パッチ、取り込んでいいですか?

> daisukeさん
問題なかったら、よろしくおねがいします。

なんかquery()で直したというNGRAM関係の問題が再現できません。再現できるテストをいただけますか?

ちょっとそれ以外の問題もあったので先に0.12出しますね

queryの部分ではないです。
sennaの方がリビジョン106で
t/03-ngram.tで、
my $index = Senna::Index->create($path, SEN_VARCHAR_KEY, SEN_INDEX_NGRAM);

のままだと、

t/01-sanity....ok
t/02-morph.....ok
t/03-ngram.....dubious
Test returned status 0 (wstat 11, 0xb)
t/04-delim.....ok
Failed Test Stat Wstat Total Fail Failed List of Failed
-------------------------------------------------------------------------------
t/03-ngram.t 0 11 ?? ?? % ??
Failed 1/4 test scripts, 75.00% okay. -2/61 subtests failed, 103.28% okay.

になります。

SEN_INDEX_NORMALIZE | SEN_INDEX_NGRAM
にすると、make test通るみたいっすね。

http://search.cpan.org/src/DMAKI/Senna-0.12/t/05-delim.t
テストがそのまま採用された。しまったorz

index_create時にSEN_INDEX_NGRAMのみを指定して、
SEN_INDEX_NORMALIZE を指定しない場合にエラーが発生する不具合は
rev109で修正されましたー。

ありゃ、テストだめ?よくみてなかったけど、動いているしいいかと思って。

ちなみにquery()用のテストってあります?

テストのサンプル文がネタっぽくなっているだけです。
queryのテストはないっすね。
05-delimをちょっと弄ればいいような気がする。

コメントを投稿