7

現在、FirstName、LastName、MiddleName、および AKA の 4 つのフィールドを検索するテーブルがあります。現在、行のCONTAINSTABLE検索があり、機能しています。うまくいきませんが、うまくいきます。ここで、First Name の重みを高くし、Middle Name の重みを低くしたいと考えています。

コマンドISABOUTを見つけましたが、列ではなく単語で実行する必要がある場合、それはかなり価値がないようです(うまくいけば、これが間違っていることを理解していました)。ユーザーが入力する単語数がわからないため、単語単位の場合、これはオプションではありません。

この同じ解決策について話しているスレッドを見つけましたが、受け入れられた解決策を機能させることができませんでし。たぶん私は何か間違ったことをしたのですが、それを機能させることができず、そのロジックは本当に...奇妙に思えます。もっと簡単な方法があるはずです。

4

5 に答える 5

8

ランキングを操作するための鍵は、ユニオンを使用することです。列ごとに、個別のselectステートメントを使用します。そのステートメントに、各行がどの列からプルされたかを示す識別子を追加します。結果をテーブル変数に挿入すると、識別子で並べ替えたり、識別子に基づいてランクに値を掛けたりして、ランキングを操作できます。

重要なのは、SQLサーバーのランキングを実際に変更するのではなく、ランキングを変更しているように見せることです。

テーブル変数を使用した例:

DECLARE @Results TABLE (PersonId Int, Rank Int, Source Int)

各列がフルテキストカタログに追加されたテーブルPeoplewithColumnsPersonId Int PK Identity, FirstName VarChar(100), MiddleName VarChar(100), LastName VarChar(100), AlsoKnown VarChar(100)の場合、次のクエリを使用できます。

INSERT INTO @Results (PersonId, Rank, Source)

SELECT PersonId, Rank, 1
FROM ContainsTable(People, FirstName, @SearchValue) CT INNER JOIN People P ON CT.Key = P.PersonId

UNION
SELECT PersonId, Rank, 2
FROM ContainsTable(People, MiddleName, @SearchValue) CT INNER JOIN People P ON CT.Key = P.PersonId

UNION
SELECT PersonId, Rank, 3
FROM ContainsTable(People, LastName, @SearchValue) CT INNER JOIN People P ON CT.Key = P.PersonId

UNION
SELECT PersonId, Rank, 4
FROM ContainsTable(People, AlsoKnown, @SearchValue) CT INNER JOIN People P ON CT.Key = P.PersonId

/*
Now that the results from above are in the @Results table, you can manipulate the
rankings in one of several ways, the simplest is to pull the results ordered first by Source then by Rank.  Of course you would probably join to the People table to pull the name fields.
*/

SELECT PersonId
FROM @Results
ORDER BY Source, Rank DESC

/*
A more complex manipulation would use a statement to multiply the ranking by a value above 1 (to increase rank) or less than 1 (to lower rank), then return results based on the new rank.  This provides more fine tuning, since I could make first name 10% higher and middle name 15% lower and leave last name and also known the original value.
*/

SELECT PersonId, CASE Source WHEN 1 THEN Rank * 1.1 WHEN 2 THEN Rank * .9 ELSE Rank END AS NewRank FROM @Results
ORDER BY NewRank DESC

1つの欠点は、私が使用しなかったことに気付くでしょう。UNION ALLそのため、単語が複数の列に表示された場合、ランクはそれを反映しません。UNION ALLそれが問題である場合は、重複するレコードのランクのすべてまたは一部を同じ個人IDを持つ別のレコードのランクに追加することにより、重複する個人IDを使用して削除できます。

于 2008-11-26T21:15:30.837 に答える
3

ランクはインデックス全体では役に立ちません。それらをマージして、結果が何の意味も持たないことを期待することはできません。各指数のランク数はリンゴ/オレンジ/グレープ/スイカ/ペア比較であり、他の指数のWRT内容に相対的な意味はありません。

確かに、インデックス間のリンク/重み/順序ランクを試して意味のある結果をごまかすことができますが、結局のところ、その結果はまだ意味不明ですが、状況の詳細に応じて実行可能なソリューションを提供するのに十分な可能性があります。

私の見解では、検索可能にする予定のすべてのデータを単一の FTS インデックス/列に配置し、その列のランクを使用して出力を並べ替えることが最善の解決策です。結果を達成するためにフィールドの内容を複製する必要がある場合でも。

于 2008-11-30T05:32:36.793 に答える
2

ほんの数週間前、私は非常によく似た問題を解決していましたが、解決策は驚くほど簡単です (醜くてスペースを消費しますが)。FirstName + FirstName + LastName + MiddleNameこの順序で結合された値を含む別の列を作成します。重複する FirstName 列はタイプミスではありません。FT が検索中に FirstName の値をより高く重み付けするように強制するトリックです。

于 2010-11-08T14:59:29.697 に答える
1

この方法はどうですか:

    SELECT p.* from Person p
left join ContainsTable(Person, FirstName, @SearchValue) firstnamefilter on firstnamefiler.key = p.id
left join ContainsTable(Person, MiddleName, @SearchValue) middlenamefilter on middlenamefilter.key = p.id
where (firstnamefilter.rank is not null or middlenamefilter.rank is not null)
order by firstnamefilter.rank desc, middlenamefilter.rank desc

これにより、ファースト ネームまたはミドル ネーム (またはその両方) が検索語で一致する各Personレコードのレコードが生成され、ファースト ネームに対するすべての一致が最初に (降順で) 並べ替えられ、その後にミドル ネームに対するすべての一致が続きます。 (これも降順)

于 2014-06-05T08:45:43.213 に答える
0

返されたデータは、スキーマ内の他のテーブルに結合されていると思いますか? 関連データからフルテキスト インデックスまでの列に基づいて、独自の RANK を作成します。これにより、RANK 値の精度も保証されます。

于 2008-12-04T09:52:09.093 に答える