RANK を使用して検索結果を制限する

適用対象:SQL ServerAzure SQL データベースAzure SQL Managed Instance

CONTAINSTABLEFREETEXTTABLE 関数は、0から1,000までの順序数(ランク値)を含む「RANK」という列を返します。 これらの値は、選択基準にどれだけ合致するかに応じて行をランク付けします。 この順位値が示しているのは、結果セット内の各行の単なる相対順位であり、値が小さいほど関連性は低くなります。 実際の値は重要ではなく、通常はクエリを実行するたびに異なります。

CONTAINSFREETEXT の述語は、順位値を返しません。

検索条件と一致するアイテムの数が膨大になることがよくあります。 CONTAINSTABLEまたはFREETEXTTABLEクエリで一致結果が多く返されすぎるのを防ぐには、オプションのtop_n_by_rankパラメーターを使用してください。 返すのは行の一部のみです。 top_n_by_rank は整数の 値nであり、n個 の最高ランク のマッチのみが降順で返されることを示しています。 top_n_by_rank を他のパラメーターと組み合わせた場合、クエリから返される行数は、実際にすべての述語に一致する行数より少なくなります。

SQL Server データベース エンジンはマッチをランクごとに順序付けし、指定された行数までのみ返します。 例えば、通常100,000行のテーブルから100,000行を返すクエリは、上位100行のみを要求するとより速く処理されます。

RANKを使って検索結果を制限する例

例 A: 上位 3 件の一致結果のみを検索する

次の例では、CONTAINSTABLE を使用して上位 3 件の一致結果のみを返します。

USE AdventureWorks2025;
GO

SELECT K.RANK,
       AddressLine1,
       City
FROM Person.Address AS A
     INNER JOIN CONTAINSTABLE (Person.Address, AddressLine1, 'ISABOUT ("des*",
    Rue WEIGHT(0.5),
    Bouchers WEIGHT(0.9))', 3) AS K
     ON A.AddressID = K.[KEY];
GO

結果セットは次のとおりです。

RANK        Address                          City
----------- -------------------------------- ------------------------------
172         9005, rue des Bouchers           Paris
172         5, rue des Bouchers              Orleans
172         5, rue des Bouchers              Metz

例 B: 上位 5 件の一致結果を検索する

次の例では、CONTAINSTABLE を使用して Description 列内で "light" または "lightweight" という単語の近くに "aluminum" という語句を含んでいる、上位 5 種の製品の説明を返します。

USE AdventureWorks2025;
GO

SELECT FT_TBL.ProductDescriptionID,
       FT_TBL.Description,
       KEY_TBL.RANK
FROM Production.ProductDescription AS FT_TBL
     INNER JOIN CONTAINSTABLE (Production.ProductDescription,
         Description, '(light NEAR aluminum) OR (lightweight NEAR aluminum)', 5) AS KEY_TBL
         ON FT_TBL.ProductDescriptionID = KEY_TBL.[KEY];
GO

検索クエリの結果が順位付けされる方法

全文検索は、全文クエリで返されるデータの関連性を示すオプションのスコア(またはランク値)を生成することができます。 このランク値は各行で計算され、関連性でクエリの結果セットをソートする順序基準として利用できます。 順位値は、単に、結果セット内の各行の相対的な関連順位を示します。 実際の値は重要ではなく、通常はクエリが実行されるたびに変わります。 順位値は、他のクエリでは意味を持ちません。

順位付けに使用する統計

インデックスを作成すると、システムはランキングに使う統計を収集します。 全文カタログの作成は、単一の索引構造を直接作成するわけではありません。 代わりに、Full-Text エンジンはデータをインデックスする際に中間インデックスを作成します。 その後、Full-Text Engine は必要に応じてこれらのインデックスをより大きなインデックスにマージします。 このプロセスは何度も起こり得ます。 次に、Full-Text Engine は "マスター マージ" と呼ばれる処理を行います。この処理では、すべての中間インデックスが 1 つの巨大なインデックスに結合されます。

統計は各中間インデックス レベルで収集されます。 インデックスがマージされると、統計もマージされます。 一部の統計値は、マスターのマージ処理の過程でしか生成できません。

データベース エンジンはクエリ結果セットをランク付けしますが、最大の中間インデックスからの統計値を使用します。 この用法は中間インデックスが統合されるかどうかに依存します。 したがって、中間インデックスがマージされていない場合、順位付けの統計の精度にばらつきが生じることがあります。 この精度の違いが、同じクエリでも、全文インデックスデータの追加・修正・削除や、小さなインデックスの統合によって異なるランク結果を返す理由を説明しています。

インデックスのサイズを最小化し、計算を容易にするために、統計はしばしば丸められます。

共通に使用される用語と順位の計算に必要な統計値を次の表に示します。

用語/値 説明
プロパティ 行の中でフルテキスト インデックスが付けられた列です。
Document クエリで返されるエンティティです。 データベース エンジンではこれは行に対応します。 1 つの行にフルテキスト インデックスが付いた列が複数含まれるのと同様に、1 つのドキュメントには複数のプロパティが含まれる場合があります。
インデックス 1 つまたは複数のドキュメントの単一の逆インデックスです。 これは、完全にメモリ内またはディスク上に存在する可能性があります。 クエリ統計の多くは、一致した個々のインデックスと関連しています。
フルテキスト カタログ クエリで 1 つのエンティティとして扱われる中間インデックスのコレクションです。 カタログは管理者が組織の単位と見なすものです。
Word、トークン、またはアイテム フルテキスト エンジンの一致単位です。 文書からのテキストストリームは、言語固有のワードブレーカーによって単語やトークンにトークン化されます。
個数 単語区切り処理によって決定される文書プロパティ内の単語オフセット。 最初のワードはオカレンス 1、次のワードはオカレンス 2 というように、それ以降順番に番号が付けられます。 フレーズクエリや近接クエリで誤検知を避けるため、文末と段落末は出現間隔を大きくします。
TermFrequency キー値が連続して出現する回数です。
IndexedRowCount インデックスが付けられた合計行数です。 この値は中間インデックスで保持されたカウントに基づいて計算されます。 この数の精度にはばらつきがあります。
KeyRowCount 指定されたキーを格納するフルテキスト カタログの合計行数です。
MaxOccurrence 行内の指定されたプロパティについて、フルテキスト カタログに保存される最大出現回数です。
MaxQueryRank 最大階級 1000は Full-Text エンジンによって返されました。

順位計算に関する問題点

ランクの計算過程には多くの要因が影響します。 ワード ブレーカーの言語が異なると、テキストをトークン化する方法も異なります。 例えば、ある単語ブレイカーは「dog-house」の文字列を「dog」と「house」に分けますが、別のワードブレイカーは「dog-house」として扱います。 マッチングやランク付けは、指定された言語によって異なり、単語だけでなく文書の長さも異なるためです。 ドキュメント長の違いは、クエリすべての順位付けに影響します。

IndexRowCount などの統計は大きく異なる場合があります。 例えば、カタログのマスターインデックスに20億行がある場合、1つの新しいドキュメントがインメモリ中間インデックスにインデックスされ、そのドキュメントのランキングは、メモリインデックス内のドキュメント数に基づくランクがマスターインデックスのドキュメントのランクと比べて歪む可能性があります。 このため、多数の行がインデックス化または再インデックスされる母集団の後は、 ALTER FULLTEXT CATALOG ... REORGANIZE Transact-SQL文を使ってこれらのインデックスをマスターインデックスに統合します。 また、中間インデックスの数やサイズなどのパラメーターを基に、Full-Text Engine によるインデックスのマージも自動的に実行されます。

MaxOccurrence の値は 1 ~ 32 の範囲のいずれかに正規化されます。 この正規化とは、例えば50語の文書が100語の文書と同じ扱いを受けることを意味します。 以下の表は正規化を示しています。 これらのドキュメント長は以下の表の 32 と 128 の間にあるため、実際には同じドキュメント長 (32 <docLength<= 128) として扱われます。

{ 16, 32, 128, 256, 512, 725, 1024, 1450, 2048, 2896, 4096, 5792, 8192, 11585,
16384, 23170, 28000, 32768, 39554, 46340, 55938, 65536, 92681, 131072, 185363,
262144, 370727, 524288, 741455, 1048576, 2097152, 4194304 };

CONTAINSTABLE の順位付け

CONTAINSTABLE の順位付けでは次のアルゴリズムを使用します。

StatisticalWeight = Log2( ( 2 + IndexedRowCount ) / KeyRowCount )
Rank = min( MaxQueryRank, HitCount * 16 * StatisticalWeight / MaxOccurrence )

フレーズマッチは個々のキーと同様にランク付けされますが、 KeyRowCount (フレーズを含む行数)は推定値であり、実際の数値よりも不正確で高くなることがあります。

NEARの順位

CONTAINSTABLE では、NEAR オプションを使用することで、相互に近接する 2 つ以上の検索語句に対するクエリをサポートしています。 返される各行の順位値は、いくつかのパラメーターに基づいています。 順位付けの主な要因の 1 つは、ドキュメントの長さに関連した一致の合計数 ( ヒット) です。 したがって、たとえば、100 語のドキュメントと 900 語のドキュメントに同一の一致が含まれている場合は、100 語のドキュメントの方が順位が高くなります。

行における各ヒットの合計の長さも、そのヒットの最初と最後の検索語句の間の距離に基づいて、その行の順位に影響を与えます。 距離が小さいほど、ヒットは行の順位値に大きく影響します 全文クエリで最大距離として整数が指定されていない場合、論理的項が100個を超える距離のヒットのみを含む文書はランク0となります。

ISABOUT の順位付け

CONTAINSTABLE は、ISABOUT オプションを指定した重み付け語句のクエリをサポートします。 ISABOUT は、従来の情報検索用語で言うところのベクトル空間クエリです。 既定の順位付けアルゴリズムには、Jaccard という一般的に知られている公式が使用されます。 クエリ内の用語ごとに順位付けが計算され、次のアルゴリズムで示す方法で各順位付けが結合されます。

ContainsRank = same formula used for CONTAINSTABLE ranking of a single term (above).
Weight = the weight specified in the query for each term. Default weight is 1.
WeightedSum = Σ[key=1 to n] ContainsRankKey * WeightKey
Rank =  ( MaxQueryRank * WeightedSum ) / ( ( Σ[key=1 to n] ContainsRankKey^2 )
      + ( Σ[key=1 to n] WeightKey^2 ) - ( WeightedSum ) )

FREETEXTTABLE の順位付け

FREETEXTTABLE の順位付けは、OKAPI BM25 という公式を使用して計算されます。 FREETEXTTABLE クエリは屈折生成(元のクエリ語の屈折形)によってクエリに単語を追加します。 これらの単語は別々の単語として扱われ、生み出された単語と特別な関係はありません。 シソーラス機能によって生成されたシノニムは、同等に重み付けされた別々の用語として扱われます。 クエリ内の各単語が順位の要素となります。

Rank = Σ[Terms in Query] w ( ( ( k1 + 1 ) tf ) / ( K + tf ) ) * ( ( k3 + 1 ) qtf / ( k3 + qtf ) ) )
Where:
w is the Robertson-Sparck Jones weight.
In simplified form, w is defined as:
w = log10 ( ( ( r + 0.5 ) * ( N - R + r + 0.5 ) ) / ( ( R - r + 0.5 ) * ( n - r + 0.5 ) )
N is the number of indexed rows for the property being queried.
n is the number of rows containing the word.
K is ( k1 * ( ( 1 - b ) + ( b * dl / avdl ) ) ).
dl is the property length, in word occurrences.
avdl is the average length of the property being queried, in word occurrences.
k1, b, and k3 are the constants 1.2, 0.75, and 8.0, respectively.
tf is the frequency of the word in the queried property in a specific row.
qtf is the frequency of the term in the query.