全文検索エンジンSennaの2indバグを回避する方法


Senna (Tritonn) とは、未来検索ブラジルが開発した全文検索エンジンで、2indという機能があります。

(http://d.hatena.ne.jp/keyword/Senna)

2ind(2インデックス同時使用)というのは

MySQLなどでクエリを実行する際、1つのテーブルに対して、全文検索用のFULLTEXTインデックスと、他のインデックスを組み合わせて利用(インデックスマージ)できる機能です。

http://qwik.jp/tritonn/userguide.html#0cb0baa8b27d86e9233f601a9cc9cc4f

この機能を使わず全文検索を実行した場合、関連度合いでソートされた結果が返されます。ですが、大体の用途において、更新日時などでソートしたいことが多いと思います。

例えば、このようなテーブル構造

Field Type Null Key Default Extra
id int(10) unsigned NO PRI 0
title varchar(100) NO FULLTEXT
time int(10) unsigned NO MUL 0

- id => データID(インデックス:Primary)
- title => 本文(インデックス:FULLTEXT)
- time => データが更新されたUNIXタイム(インデックス:INDEX)

このテーブルにおいて、titleの全文検索をtime順に並べてidを取得するクエリは

SELECT `id`
FROM `tbl_name`
FORCE INDEX ( `time` )
WHERE MATCH (
`title`
)
AGAINST (
'検索したいテキスト'
)
ORDER BY `time`
LIMIT 0 , 10

となります。
シンプルなクエリで特に問題ないように見えますが、LIMIT句が効かなくなるバグがあります。

この問題が確認された環境ですが、
Tritonn 1.0.12(MySQL5.0.87、linux-x86_64)
現在の最終バージョンです。

解決するには

さて解決する方法は、重複を省略するDISTINCT句を加えるだけです。

SELECT DISTINCT `id`
FROM `tbl_name`
FORCE INDEX ( `time` )
WHERE MATCH (
`title`
)
AGAINST (
'検索したいテキスト'
)
ORDER BY `time`
LIMIT 0 , 10

これだけで、LIMIT句がきちんと動くようになります。
MySQLでDISTINCT句を使うと「インデックスが使われなくなるんじゃないの?」という懸念はあるのですが、EXPLAINで確認したところ「Using Where」が返ってきていたので、大丈夫みたいです。

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE tbl_name index NULL time 3 NULL 128481 Using where

※この記事は引っ越し元のブログから保存用にもってきたものです。この頃(2015年)はsennaはあまり使っていないのですが、覚書として。

0 件のコメント :

コメントを投稿