[解決済み] Javascriptのファジー検索が意味をなす
質問
私は配列をフィルタリングするためのあいまい検索のJavaScriptライブラリを探しています。私は使用してみました fuzzyset.js と fuse.js を試してみましたが、結果はひどいものでした(リンク先のページで試すことができるデモがあります)。
レーベンシュタイン距離についていくつか読んでみたところ、ユーザーが入力するときに探しているものの近似値としては不十分であることがわかりました。ご存じない方のために説明すると、このシステムは、文字列を入力するときに、どれだけ多くの 挿入 , 削除 そして 置換 は2つの文字列を一致させるために必要です。
Levenshtein-Demerauモデルで修正された明らかな欠点として、両方の文字列が一致するために blub と ブーブー は、同じように 球根 (それぞれ2つの置換を必要とする)と同等とみなされます。しかし、明らかなのは 電球 とはより似ています。 ブブ よりも ブーブー があり、先ほどのモデルは、それを認識した上で 転置 .
これをテキスト補完の文脈で使いたいので、もし、配列
['international', 'splint', 'tinder']
という配列があり、私のクエリが
int
であり、私は
国際
よりも上位にランクされるべきだと思います。
スプリント
は、前者のスコア(より高い=悪い)が10であるのに対して、後者のスコアは3であるにもかかわらず、よりも上位にランクされるはずです。
ですから、私が探しているもの (そして、存在しない場合は作成します) は、次のようなことを行うライブラリです。
- 異なるテキスト操作の重み付け
- 各操作が単語内のどこに現れるかによって異なる重み付けをする(初期の操作は後期の操作よりもコストが高い)
- 関連性でソートされた結果リストを返す
誰かこのようなものに出会ったことがありますか?私は、StackOverflow がソフトウェアの推奨事項を尋ねる場所ではないことを理解していますが、上記の暗黙の了解 (もうありません!) は、私がこれを正しい方法で考えているかどうかということです。
編集
を見つけたので 良い論文(pdf) を見つけました。いくつかのメモと抜粋です。
<ブロッククオートアフィン編集距離関数は、挿入または削除のシーケンスに比較的低いコストを割り当てます。
Monger-Elkan距離関数 (Monge & Elkan 1996) は、Smith-Waterman距離関数 (Durban et al. 1998) を特定のコストパラメータでアフィン変換したものです。
については スミス-ウォーターマン距離 (ウィキペディア) スミス-ウォーターマン アルゴリズムは、配列全体を見るのではなく、すべての可能な長さのセグメントを比較し、類似度測定を最適化するものです。
<ブロッククオート編集距離モデルに基づかない、よく似た指標として Jaro メトリック (Jaro 1995; 1989; Winkler 1999). レコード リンクの文献では、2 つの文字列間の共通文字の数と順序に基づくこの方法の変種を使用して、良い結果が得られています。
Winkler (1999)によるこの変形はまた、最も長い共通の接頭辞の長さPを使用します。
<ブロッククオート(主に短い文字列のために用意されたようです)
テキスト補完の目的では、Monger-Elkan と Jaro-Winkler のアプローチが最も理にかなっていると思われます。Jaro メトリックへの Winkler の追加は、効果的に単語の先頭をより重く評価します。また、Monger-Elkanのアフィン的側面は、単語を補完する必要性(これは単に一連の追加である)が、あまり大きく不利にならないことを意味します。
結論
TFIDF ランキングはいくつかのトークンベースの距離メトリックの中で最も良い結果を示した。 また、MongeとElkanによって提案された調整されたアフィンギャップ編集距離メトリックは、いくつかの文字列編集距離メトリックの中で最も良い結果を示した。 文字列編集距離メトリクスの中で最もよい結果を示した。意外にも優れた距離 Jaroによって提案され,後にWinklerによって拡張された高速な発見的スキームである. この方式はMonge-Elkan方式とほぼ同様に機能するが は1桁以上速い。 TFIDF法とJaro-Winkler法を組み合わせる簡単な方法は Jaro-Winklerを組み合わせる簡単な方法の1つは、TFIDFで使われる厳密なトークン照合を TFIDFで用いるトークン照合をJaro-Winkler方式に基づく近似的なトークン照合に置き換えることである。 ウィンクラー方式に基づく近似的なトークン・マッチに置き換えることである。この組み合わせは、平均してJaro-WinklerとTFIDFのどちらよりもわずかに性能が良く、時にははるかに性能が良くなることもある。また、この論文で検討したいくつかの最良のメトリクスの学習された組み合わせに近い性能を持つ。 この論文で検討した
どのように解決するのですか?
いい質問ですね。しかし、私の考えでは、Levenshtein-Demerau を修正しようとするよりも、別のアルゴリズムを試すか、2 つのアルゴリズムからの結果を組み合わせたり、重み付けしたりするほうがよいかもしれません。
Levenshtein-Demerau は、"starting prefix" への完全一致または近似一致を特に重視しませんが、あなたの明らかなユーザーの期待には重みを与えるだろうと思います。
私は "better than Levenshtein" で検索し、とりわけこれを見つけました。
http://www.joyofdata.de/blog/comparison-of-string-distance-algorithms/
これは、多くの文字列の距離について言及しています。あなたの要件に特に関連するように見えた 3 つは、次のとおりです。
-
Longest Common Substringの距離。 結果として得られる部分文字列が同一になるまで、両方の文字列から削除されなければならない記号の最小数。
-
q-gram距離。 両文字列のN-gramベクトル間の差の絶対値の和。
-
Jaccard距離です。 共有N-gramと全観測N-gramの商を1minで表す。
多分、Levenshteinで、これらのメトリックの重み付けされた組み合わせ(または最小値)を使用することができます -- 共通の部分文字列、共通のN-gramまたはJaccardはすべて強く好まれます。 類似 文字列を強く好みます -- あるいは Jaccard だけを使ってみるのもいいかもしれません。
リスト/データベースのサイズによりますが、これらのアルゴリズムは中程度に高価になることがあります。私が実装したファジー検索では、設定可能な数の N-gram を DB からの検索キーとして使用し、それらを優先順位でソートするために、高価な文字列距離測定を実行しました。
SQL でのファジー文字列検索について、いくつかのメモを書きました。参照してください。
関連
-
[解決済み】JavaScriptの配列でforEachが関数でない不具合
-
フロントエンド非同期(アシンク)ソリューション(全ソリューション)
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptでメールアドレスを検証するのに最適な方法は何ですか?
-
[解決済み] 単語を含まない行にマッチする正規表現
-
[解決済み】JavaScriptの比較では、どちらの等号演算子(== vs ===)を使うべきですか?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
-
[解決済み】オブジェクトからプロパティを削除する(JavaScript)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
JavaScriptの関数この指摘の問題を説明
-
Vueの要素ツリーコントロールに破線を追加する説明
-
JavaScriptのクロージャの説明
-
Vueのイベント処理とイベントモディファイアの解説
-
[解決済み】SyntaxError: JSONの位置1に予期しないトークンoがある。
-
[解決済み】JavaScriptの配列でforEachが関数でない不具合
-
[解決済み】GETできない / Nodejsエラー
-
[解決済み】ERROR エラーです。スイッチのname属性が指定されていないフォームコントロールの値アクセッサがない
-
[解決済み】 Uncaught TypeError : undefined のプロパティ 'replace' を読み取れない In Grid
-
[解決済み】ReactJSでエラー発生 Uncaught TypeError: Super expression は null か関数でなければならず、undefined ではありません。