FTS5(SQLite)
SQLiteの全文検索用仮想テーブルモジュールの最新版。FTS3/FTS4の後継として設計が刷新されており、SQL構文にも違いがある。
#sqlite #database #full-text-search
BM25によるランキング
FTS5はrankという隠しカラムを公開しており、ORDER BY rankとするだけでBM25スコア(値が小さいほど関連度が高い)による関連度順ソートができる。BM25の計算に使う定数k1・bはそれぞれ1.2・0.75に固定されている。この関連度ランキングはFTS3/FTS4にはなかった機能。
external content / contentless テーブル
contentオプションで、元のテキストを別テーブルに持たせる「external contentテーブル」(content='posts'のように指定、本文の二重保存を避けられる)や、本文を一切保持しない「contentlessテーブル」(content=''、検索はできるが元テキストの取得はできず、rowidだけを返す)を構成できる。
トークナイザ
組み込みトークナイザとしてunicode61(デフォルト)、ascii、porter、trigramがある。デフォルトのunicode61は空白区切りを前提とするため英語向けで、単語の区切りが明示されない日本語には不向き。trigramトークナイザを使うと3文字の連続部分文字列単位でのマッチングができ、完全な単語でなくても任意の文字列にマッチできるようになる(ただし3文字未満の文字列はどの行にもマッチしないという制約がある)。日本語(CJK)検索では、ラテン文字部分はunicode61、CJK部分はtrigramを使い分けるハイブリッド戦略が実用的とされる。
日本語対応の選択肢: N-gramと形態素解析
日本語のように単語の区切りが明示されない言語では、unicode61のような空白区切り前提のトークナイザはそのままでは使えない。主なアプローチは2つ。
- N-gram(trigramトークナイザなど): 意味のある単語に分割せず、機械的にN文字ずつの部分文字列に区切ってトークン化する。単語の切れ目を解析する必要がないのが利点だが、意味のない部分文字列にもヒットするノイズ(false positive)が発生しやすく、インデックスサイズも単語ベースより大きくなりがち。
- 形態素解析(MeCabなど): 事前にMeCabのような形態素解析エンジンでテキストを単語単位に分割してからFTSに投入する。精度は高いが、外部の解析エンジンへの依存が増える。
日本語(CJK)検索では、ラテン文字部分はunicode61、CJK部分はtrigramを使い分けるハイブリッド戦略も実用的とされる。
FTS3/FTS4との違い
FTS3のノートで触れた通り、FTS3/FTS4は単語単位の前方一致・完全一致にしか対応せず関連度ランキングも持たないのに対し、FTS5はモジュール設計が刷新され、SQL構文もやや異なる(例: プレフィックス検索はMATCH演算子内でterm*のように書く)。
出典
- SQLite FTS5 Extension(公式ドキュメント)
- SQLite Full-Text Search: FTS5 Virtual Tables and MATCH
- Full-text CJK Search with SQLite FTS5: Trigram Tokenizer and Hybrid Strategy
- SQLite FTS5 Tokenizers: unicode61 and ascii
- SQLiteを使ってAndroid端末内でお手軽に日本語全文検索する - Qiita
- SQLite FTS : trigram tokenizerでunigram&bigram検索までサポート
- 【Python】SQLite で日本語を全文検索するコード例【N-Gram, FTS4/FTS5】 | シラベルノート