関連度スコアリング
全文検索クエリ(MATCH_ANY、MATCH_ALL、MATCH_PHRASE など)を実行する際は、関連度の高いレコードから返されるように、結果を「一致度」で並べ替えたいことがあります。Doris の関連度スコアリングでは、クエリ条件に基づいて各行に数値スコアを付けます。スコアが高いほど関連度が高いことを示します。
Doris は現在、関連度スコアリングのデフォルト実装として BM25 (Best Matching 25) アルゴリズムを使用しています。
主なユースケース:
- 検索エンジンアプリケーション:キーワードに基づき、関連度の高い文書から順に返す
- ログ分析:関連度順に並べ替え、キーワードに最もよく一致するログをすばやく見つける
- コンテンツ推薦:テキストの類似度に基づき、優先度の高いコンテンツを絞り込む
- ナレッジベース検索:質問との関連度が高い順に回答候補を返す
クイックスタート
次の例は、クエリで関連度スコアリングを有効にし、スコア順に並べ替える方法を示しています。
SELECT *,
score() AS relevance
FROM search_demo
WHERE content MATCH_ANY 'text search test'
ORDER BY relevance DESC
LIMIT 10;
実行後、Doris は BM25 アルゴリズムを使用して各行のスコアを計算し、関連度が高い上位 10 件のレコードを返します。
+------+-----------------------------------+---------+--------------+-----------+
| id | content | author | publish_date | relevance |
+------+-----------------------------------+---------+--------------+-----------+
| 1 | Full text search engine test demo | Alice | 2024-01-01 | 2.915228 |
| 7 | Text processing techniques | Grace | 2024-01-07 | 1.341931 |
| 5 | Performance test framework | Eve | 2024-01-05 | 1.341931 |
| 3 | Advanced search algorithms | Charlie | 2024-01-03 | 1.341931 |
+------+-----------------------------------+---------+--------------+-----------+
有効化の条件
スコア計算を有効にするには、クエリが以下の条件をすべて満たす必要があります。
SELECT句でscore()関数を明示的に呼び出していること。WHERE句に少なくとも一つのMATCH_*条件が含まれていること。- Top-N クエリであり、
ORDER BYがscore()の結果に基づいていること。
対応するインデックスタイプ
| インデックスタイプ | スコアリング対応 | 説明 |
|---|---|---|
| トークン化された転置インデックス | 対応 | BM25 関連度スコアを計算できる |
| トークン化されていない転置インデックス | 非対応 | 完全一致のみをサポートし、スコアは計算しない |
対応するクエリタイプ
MATCH_ANYMATCH_ALLMATCH_PHRASEMATCH_PHRASE_PREFIXSEARCH
BM25 アルゴリズム
BM25 は、確率モデルに基づくテキスト関連度アルゴリズムです。語の出現頻度 (TF)、逆文書頻度 (IDF)、レコードの長さという三つの要素を考慮し、一致した結果に重み付けをしてスコアを計算します。従来の TF-IDF モデルと比べて、BM25 はより頑健で調整しやすく、長いテキストと短いテキストのスコア差を効果的に調整できます。
基本式
score = IDF × (tf × (k1 + 1)) / (tf + k1 × (1 - b + b × |d| / avgdl))
式中の変数は次のとおりです。
| 変数 | 意味 |
|---|---|
tf | 現在の行にクエリの語が出現する回数 |
IDF | 語の希少性を表す逆文書頻度 |
|d| | 現在の行の長さ(トークン化後のトークン数) |
avgdl | テーブル内の全行の平均長 |
k1, b | アルゴリズムの調整パラメータ |
パラメータ
| パラメータ | デフォルト値 | 説明 |
|---|---|---|
k1 | 1.2 | 語の出現頻度がスコアに与える影響の大きさを制御する |
b | 0.75 | レコード長の正規化の強さを制御する |
boost | 1.0 | クエリ単位の重み係数 |
補助統計情報
IDF = log(1 + (N - n + 0.5) / (n + 0.5))
avgdl = total_terms / total_rows
ここで、各変数は次のとおりです。
N:テーブル内の総行数n:クエリの語を含む行数
クエリに複数の語が含まれる場合、最終スコアは各語のスコアの合計です。
レコード長と norms プロパティ
norms インデックスプロパティと BE 設定 inverted_index_skip_norms_for_variant は、Doris 4.1.5 以降でサポートされています。
|d| は norms から取得されます。norms は、フィールドに値がない行も含め、インデックス対象の各フィールドについて各行あたり一バイトの領域を使用します。トークン化されたインデックスは、デフォルトで norms を書き込みます("norms" = "true")。トークン化されていないインデックスは書き込みません。フィルタリングにしか使用しないインデックスでは、"norms" = "false" に設定すると領域を節約できます。
INDEX idx_content(content) USING INVERTED PROPERTIES("parser" = "english", "norms" = "false")
VARIANT のサブパスはインデックスの norms プロパティを継承し、rows × paths バイトの領域を使用します。BE 設定 inverted_index_skip_norms_for_variant(デフォルトは false、実行時に変更可能)を true に設定すると、インデックスプロパティよりもこの設定が優先され、すべての VARIANT パスインデックスで norms が無効になります。
norms を無効にしても MATCH_* によるフィルタリングには影響しませんが、score() が norms のないセグメントを読み取るとエラーになります。これらの設定が適用されるのは新たに書き込まれるセグメントです。既存のセグメントは、コンパクションによって書き換えられるまで変更されません。設定を変更する前に、すべての BE をこれらの設定に対応したバージョンにアップグレードしてください。
結果の解釈
スコアの特性を理解すると、関連度による順位付けをより適切に利用できます。
| 特性 | 説明 |
|---|---|
| スコアの範囲 | 上限が固定されていない正の数。通常は絶対値よりも相対的な大きさが重要 |
| 複数の語を含むクエリ | 複数の語が含まれる場合、総スコアは各語のスコアの合計になる |
| 長さの影響 | 一致する語が同じ場合、短いレコードのスコアがわずかに高くなる |
| 一致する語がない場合 | クエリの語がテーブル内に存在しない場合、対応するスコアは 0 になる |
よくある質問
Q1: クエリでスコアが返されないのはなぜですか?
次の項目を順に確認してください。
score()関数をSELECTで呼び出しているか。WHERE句にMATCH_*条件が含まれているか。ORDER BYがscore()に基づいているか。- インデックスがトークン化された転置インデックスか。
Q2: BM25 と TF-IDF の違いは何ですか?
BM25 は TF-IDF を基に、語の出現頻度の飽和と長さの正規化という二つの改善を加えています。これにより、長いテキストと短いテキストのスコアのバランスが改善され、頑健性が高まります。
Q3: 異なるクエリのスコアを比較できますか?
推奨しません。BM25 のスコアは、個々のクエリの語とテーブル内のデータ分布に依存します。異なるクエリ間で絶対値を比較することはできません。相対的な大きさは、同じクエリの結果セット内でのみ比較してください。