web-dev-qa-db-ja.com

SQLあいまい一致

私がこの質問を繰り返さないことを願っています。ここに投稿する前に、ここで検索してグーグルで検索しました。

フルテキストを有効にしてSQL Server 2008R2でeStoreを実行しています。

私の要件、

  1. この製品が適合する製品名、OEMコード、モデルを含む製品テーブルがあります。すべてテキストです。
  2. TextSearchという新しい列を作成しました。これには、この製品が適合する製品名、OEMコード、モデルの値が連結されています。これらの値はカンマで区切られています。
  3. 顧客がキーワードを入力すると、TextSearch列で検索を実行して製品を照合します。以下のマッチングロジックを参照してください。

ハイブリッドフルテキストを使用しており、通常のように検索を行っています。これにより、より適切な結果が得られます。一時テーブルおよびDISTINCTに対して実行されたすべてのクエリが返されました。

マッチングロジック

  1. 次のSQLを実行して、フルテキストを使用して関連製品を取得します。ただし、@ Keywordsは前処理されます。 「CLC 2200」が「CLC * AND 2200 *」に変更されるとします。

    Dbo.Product WHERE CONTAINS(TextSearch、@ Keywords)からIDを選択

  2. 別のクエリが通常のように実行されます。したがって、「CLC 2200」は「%clc%のようなTextSearch AND%2200%のようなTextSearch」に前処理されます。これは、全文検索ではキーワードの前にパターンが検索されないためです。たとえば、「pclc 2200」は返されません。

    DboからIDを選択します。製品WHERE TextSearch like '%clc%' AND TextSearch like '%2200%'

  3. 手順1と2でレコードが返されなかった場合は、次の検索が実行されます。値135は、より関連性の高いレコードを返すように微調整されました。

    Dbo.Productからp.idを選択し、p INNER JOIN FREETEXTTABLE(product、TextSearch、@ Keywords)AS r ON p.Id = r。[KEY] WHERE r.RANK> 135

上記のすべてを組み合わせると、妥当な速度で問題なく機能し、キーワードに関連する製品が返されます。

しかし、製品がまったく見つからない場合は、さらに改善したいと考えています。

お客様が「CLC 2200npk」を探していて、この製品がなかった場合、「CLC 2200」のすぐ隣に表示する必要があったとします。

これまでのところ、Soundex()関数を使用してみました。 TextSearch列の各単語のsoundex値を計算し、キーワードのsoudex値と比較して購入します。しかし、これは非常に多くのレコードを返し、あまりにも遅くなります。

たとえば、「CLC 2200npk」は「CLC 1100」などの製品を返します。ただし、これは良い結果ではありません。 CLC 2200npkに近くないため

別の良いものがあります here 。ただし、これはCLR関数を使用します。しかし、サーバーにCLR関数をインストールできません。

だから私の論理は

'CLC 2200npk'が見つからない場合は 'CLC 2200'で閉じるを表示 'CLC 2200'が見つからない場合は 'CLC 1100'で次に閉じるを表示

ご質問

  1. 提案されているように一致させることは可能ですか?
  2. スペルの修正と検索を行う必要がある場合、何が良い方法でしょうか?すべての製品リストは英語です。
  3. 私の提案のようなテキストと一致するUDFまたはSPはありますか?

ありがとう。

11
Jeyara

かなり迅速なドメイン固有のソリューションは、SOUNDEXと2つの文字列間の数値距離を使用して文字列の類似性を計算することです。これは、多くの製品コードがある場合にのみ役立ちます。

以下のような単純なUDFを使用して、文字列から数値文字を抽出できるため、「CLC 2200npk」から2200を取得し、「CLC 1100」から1100を取得できるため、各入力のSOUNDEX出力に基づいて近さを判断できます。各入力の数値コンポーネントの近さと同様。

CREATE Function [dbo].[ExtractNumeric](@input VARCHAR(1000))
RETURNS INT
AS
BEGIN
    WHILE PATINDEX('%[^0-9]%', @input) > 0
    BEGIN
        SET @input = STUFF(@input, PATINDEX('%[^0-9]%', @input), 1, '')
    END
    IF @input = '' OR @input IS NULL
        SET @input = '0'
    RETURN CAST(@input AS INT)
END
GO

汎用アルゴリズムに関する限り、データセットのサイズとパフォーマンスの要件に応じて、成功の度合いを変えるのに役立ついくつかの方法があります。 (両方のリンクでTSQL実装が利用可能です)

  • Double Metaphone -このアルゴは、soundexよりも優れたマッチングを提供しますが、速度は犠牲になりますが、スペルの修正には非常に適しています。
  • Levenshtein Distance -これは、たとえば「CLC 2200npk」から「CLC 2200」に取得するために1つの文字列を別の文字列に変換するために必要なキープレスの数を3に設定し、「CLC 2200npk」から「 CLC 1100 'は5です。

ここ は、両方のアルゴを一緒に適用する興味深い記事であり、いくつかのアイデアを提供します。

うまくいけば、それのいくつかが少し役立つでしょう。

編集: ここ は、はるかに高速な部分レーベンシュタイン距離の実装です(投稿を読んで、通常のものとまったく同じ結果は返されません)。 125000行のテストテーブルでは、6秒で実行されましたが、最初にリンクしたものは60秒でした。

18
David Ewen