LudiaでPostgreSQLに全文検索を

NTT Data が開発した(というか、SennaPostgreSQL バインディングを作った) Ludia を使ってみた。
# 以前、pg_senna を試したこともあり、期待大。

インストールは ドキュメント通りに問題なく完了。

環境は

こんなので。(MacOS X, PostgreSQL-8.1.4でもちゃんと動いたよ)

手元の、Plagger で取ってきたフィードを保存しているテーブルに INDEX を作って検索してみた。

 # SELECT count(*) FROM entry;
  count
 -------
  64445

 # SELECT sum(octet_length(body)) FROM entry;
    sum
 ----------
  69037755

 # CREATE INDEX entry_ftidx ON entry USING fulltext(body);
 CREATE INDEX
 Time: 65367.833 ms

6万4千件、70MBほどのサイズ。index 作成は 1ms/row 程度と高速。

 # SELECT substring(title,1,30), pgs2getscore(entry.ctid, 'entry_ftidx')
   FROM entry WHERE body @@ 'Plagger';
                           substring                           | pgs2getscore
 --------------------------------------------------------------+--------------
  akaihoの日記                                                 |          235
  Plaggerで出前が寿司に対応しました                            |          185
  Catalyst::Plugin::Plagger を使って                           |          110
  Googleで「はらへった」と検索するとピザが届くようにする       |          100
 (略)
 (469 rows)
 Time: 3.682 ms

さすがに速い。普通に LIKE や正規表現で部分一致検索をすると、1200 ms 程度。
# まあ、70MBを1.2秒でベタなめできる、という最近の機械も十分凄いとは思うが

検索には senna の検索式書式が使える。http://qwik.jp/senna/query.html

さらに、(当然というか) 他のカラムで条件を付けて絞ったりもできる。

 # SELECT * FROM entry WHERE body @@ 'Plagger +LDR' AND link !~ '\.internal';

これは素晴らしい。DB上のデータに対する全文検索への敷居が、ぐっと下がった感じ。

それはそうと、ludia の README にある例。「あの壺はよいものだ」……って、マ・クベですか。

  SELECT * FROM table1 WHERE col1 @@ 'もも';
             col1           |        col2
  --------------------------+--------------------
   すもももももももものうち | あの壺はよいものだ
   ももから生まれた桃太郎   | あの壷はよいものだ
  (2 rows)