webdevqa.jp.net

ファジー検索アルゴリズム(近似文字列照合アルゴリズム)

ファジー検索アルゴリズムを作成したいです。しかし、何時間もの研究の結果、私は本当に苦労しています。

学校名のリストでファジー検索を実行するアルゴリズムを作成したい。

これは私がこれまで見てきたことです:

私の研究のほとんどは、GoogleやStackoverflowで次のような「string metrics」を指しています。

  • レーベンシュタイン距離
  • ダメラウ-レーベンシュタイン距離
  • Needleman–Wunschアルゴリズム

ただし、これは単にsimilar 2文字列のスコアを示します。 検索アルゴリズムとして実装することを考えることができる唯一の方法は、線形検索を実行し、各文字列に対して文字列メトリックアルゴリズムを実行し、特定のしきい値を超えるスコアを持つ文字列を返すことです。 (もともとはトライツリーに文字列を保存していましたが、これは明らかにここでは役に立ちません!)

これは小さなリストにとってそれほど悪い考えではありませんが、たとえば100,000個の名前を持つリストでは問題になり、ユーザーは多くのクエリを実行しました。

私が見た別のアルゴリズムは、Spell-checker methodで、すべての潜在的なスペルミスを検索するだけです。ただし、長さが7でエラーカウントが2の場合、75,000ワード以上が必要になるため、これも非常に非効率的です。

必要なもの

誰かが私に良い効率的なファジー検索アルゴリズムを提案してもらえますか?で:

  • アルゴリズムの名前
  • 仕組みまたは仕組みへのリンク
  • 賛否両論とそれが最適な場合(オプション)

すべてのアルゴリズムには長所と短所があり、bestアルゴリズムはないことを理解しています。

44
Yahya Uddin

あなたが学校名のリストでファジー検索を行おうとしていることを考えると、レーベンシュタイン距離のような伝統的な文字列の類似性に行きたくないと思います。私の想定では、ユーザーの入力(キーボード入力または電話での会話)を使用しており、一致する学校をすばやく見つけたいと考えています。

距離メトリックは、類似した2つの文字列が置換、削除、および挿入に基づいていることを示します。しかし、これらのアルゴリズムは、文字列がが人間の言語の単語にどれだけ似ているかについては何も教えてくれません。

たとえば、「smith」、「smythe」、「smote」などの単語を考えてみましょう。 2つのステップで「smythe」から「smith」に移動できます。

smythe -> smithe -> smith

そして、2つのステップで「スモート」から「スミス」へ:

smote -> smite -> smith

したがって、この2つの距離は strings と同じ距離ですが、 words としては大きく異なります。誰かがあなたに(話し言葉で)「Symthe College」を探していると言ったら、ほぼ間違いなく「ああ、スミスのことだと思う」と言うでしょう。しかし、誰かが「Smote College」と言った場合、あなたは彼が何について話しているのか全く分かりません。

必要なのは 音声アルゴリズムSoundex または Metaphone のようなものです。基本的に、これらのアルゴリズムはWordを音素に分解し、話し言葉でWordがどのように発音されるかを表現します。次に、結果を既知の単語リストと比較して、一致するものを見つけることができます。

このようなシステムは、距離メトリックを使用するよりも much 速くなります。距離メトリックでは、ユーザーの入力をリスト内のすべての単語と比較して距離を取得する必要があることを考慮してください。これは計算コストが高く、「スミス」と「スモート」で示したように、結果は笑いが悪くなる可能性があります。

音声アルゴリズムを使用して、既知の各単語の音素表現を作成し、辞書(ハッシュマップまたは場合によってはトライ)に配置します。これは、1回限りの起動コストです。次に、ユーザーが検索語を入力するたびに、入力の音素表現を作成し、辞書で調べます。それははるかに速く、はるかに良い結果を生み出します。

また、人々が固有名詞のつづりを間違えると、ほとんどの場合最初の文字が正しくなり、つづりを間違えた音のような/実際の単語を発音しないことも考慮してください。その場合、音声アルゴリズムは間違いなく進むべき方法です。

33
Jim Mischel

ファジー検索アルゴリズムと実装を混同している:Wordのファジー検索は、たとえば2のレーベンシュタイン距離を持つすべての単語の400の結果を返す場合がありますが、ユーザーには上位5-10のみを表示する必要があります。

実装に関しては、辞書のすべての単語を前処理し、結果をDBに保存します。人気のある単語(およびそのあいまいなもの)はキャッシュ層に保存されるため、リクエストごとにDBにアクセスする必要はありません。

最も一般的なスペルミスを追加し、DBに追加するAIレイヤーを追加できます。や。。など。

5
alfasin

ファジー検索の実装方法に関する記事を書きました。

https://medium.com/@Srekel/implementing-a-fuzzy-search-algorithm-for-the-debuginator-cacc349e6c55

実装はGithubにあり、パブリックドメインにあるため、お気軽にご覧ください。

https://github.com/Srekel/the-debuginator/blob/master/the_debuginator.h#L1856

その基本は次のとおりです。検索するすべての文字列を部分に分割します。したがって、パスがある場合、「C:\ documents\lol.txt」は「C」、「documents」、「lol」、「txt」になります。

大文字と小文字を区別しないように、これらの文字列を小文字にしてください。 (検索文字列がすべて小文字の場合にのみ行う可能性があります)。

次に、これに対して検索文字列を一致させます。私の場合、順序に関係なく一致させたいため、「loldoc」の後に「lol」が来ても、「loldoc」は上記のパスに一致します。

マッチングには良いスコアが必要です。私が考える最も重要な部分は、連続一致です。したがって、一致する文字が次々と連続するほど良いです。したがって、「doc」は「dcm」よりも優れています。

次に、パートのstartにあるマッチに追加のスコアを与えたいと思うでしょう。したがって、「doc」のポイントは「ocu」よりも多くなります。

私の場合、部品のendを一致させるためのポイントも追加します。

最後に、lastの部分と一致するための追加ポイントを与えることを検討する必要があります。これにより、ファイル名/終了スコアの一致が、それまでのフォルダーよりも高くなります。

3
Srekel

「一種のファジー検索」のための簡単なアルゴリズム

正直に言うと、場合によっては、ファジー検索はほとんど役に立たないので、ファジー検索を実行しているという感覚を提供しながら、より単純なアルゴリズムで検索結果を改善できると思います。

私のユースケースは次のとおりです。「ファジー検索」を使用して国のリストをフィルタリングします。

私が働いていたリストには、Zで始まる2つの国がありました。ザンビアとジンバブエです。

Fusejs を使用していました。

この場合、針「zam」を入力すると、結果セットには19個の一致があり、リストの一番下にある人間(ザンビア)に最も関連性の高いものが一致していました。また、結果の他のほとんどの国では、名前に文字zさえありませんでした。

これは、リストから国を選択できるモバイルアプリ用でした。電話の連絡先から連絡先を選択する必要がある場合に似ているはずです。検索ボックスに用語を入力して、連絡先リストをフィルタリングできます。

私見、検索するこの種の制限されたコンテンツは、人々が「一体何だ!??」と尋ねるような方法で扱われるべきではありません。

最も関連性の高いマッチでソートすることをお勧めします。しかし、この場合、ユーザーは縮小リストで「関心のあるアイテム」を常に視覚的に見つける必要があるため、これは問題外です。これは、「Googleのような」検索エンジンではなく、フィルタリングツールであることに注意してください。したがって、結果は予測可能な方法でソートする必要があります。また、フィルタリング前は、ソートはアルファベット順でした。したがって、フィルタリングされたリストは、元のリストのアルファベット順にソートされたサブセットである必要があります。

だから私は次のアルゴリズムを思いついた...

  1. 針をつかむ...この場合:zam
  2. 針の最初と最後に.*パターンを挿入します
  3. 針の各文字の間に.*パターンを挿入します
  4. 現在の.*z.*a.*m.*である新しい針を使用して、haystackで正規表現検索を実行します

この場合、ユーザーは文字z、a、mがこの順序で表示されているすべてのものを見つけることで、非常に期待される結果を得ることができます。針の中のすべての文字は、同じ順序でマッチに存在します。

これは、Mozambique ...のような国名とも一致します。これは完璧です。

時々、バズーカでハエを殺そうとしない方がいいと思います。

2
asiby