まず、フルテキストインデックスのRDBMSサポートは、構造化データへの効率的なアクセスを可能にするように設計されたテクノロジに非構造化テキストを処理させるためのハックであることを理解する必要があります。 (はい、それはただの 意見。必要に応じて、両方のテクノロジーを非常によく理解しているので、それを守ることができます。;)
では、検索パフォーマンスを向上させるために何ができるでしょうか?
オプション1-「タスクに最適なツール」
ドキュメントのコーパス内で全文検索を処理する最良の方法は、 SOLR (Lucene)ApacheまたはSphinx から エラーから、スフィンクス。
以下で明らかになる理由から、このアプローチを強くお勧めします。
オプション2-結果をプリロードする
テキストベースの検索ソリューションを構築する場合、通常のアプローチは、すべてのドキュメントを単一の検索可能なインデックスにインデックス付けすることです。これが最も便利かもしれませんが、それが唯一のアプローチではありません。
検索対象を一連の既知のルールに簡単に定量化できると仮定すると、単に修飾されていないフルテキストよりも「ガイド付き」スタイルの検索を提供できます。つまり、アプリケーションがユーザーを結果に誘導することでメリットが得られる場合は、既知のルールセットに基づいてさまざまな結果セットを独自のテーブルにプリロードできるため、検索するデータの量を減らすことができます。
ユーザーの大多数が既知の順序で既知の検索用語のセットから恩恵を受けると予想される場合は、それらの用語を優先するように検索UIを構築できます。
したがって、大多数のユーザーがさまざまな自動車を探していると仮定すると、モデル、年式、状態などに基づいて事前定義された検索を提供できます。検索UIは、ユーザーを特定の結果に「ガイド」する一連のドロップダウンメニューとして作成されます。
または、検索の大部分が特定のメイントピック(「自動車」など)に対するものである場合は、以前に自動車に関連していると特定したレコードのみのテーブルを事前に定義できます。
これらのアプローチはどちらも、検索するレコードの数を減らすため、応答時間が長くなります。
オプション3-「自分でロール」
外部検索テクノロジーをプロジェクトに統合できず、プリロードがオプションではない場合でも、検索クエリの応答時間を大幅に改善する方法はありますが、達成する必要のあることや、検索の実行方法によって異なります。 。
ユーザーが単一のキーワードまたはフレーズとそれらの間のブール関係を使用して検索することを期待する場合は、独自の'転置インデックス 'あなたのコーパスの。 (これはMySQLのブール全文検索がすでに行っていることですが、自分で実行すると、検索の速度と精度の両方をより細かく制御できます。)
既存のデータから転置インデックスを作成するには:
ステップ1.3つのテーブルを作成する
// dict - a dictionary containing one row per unique word in corpus create table dict ( id int primary key, word varchar ) // invert - an inverted_index to map words to records in corpus create table invert ( id int primary key, rec_id int, word_id int ) // stopwords - to contain words to ignore when indexing (like a, an, the, etc) create table stopwords ( id int primary key, word varchar )
注:これは単なるスケッチです。これらのテーブルを実際に作成するときに、インデックスや制約などを追加する必要があります。
ストップワードテーブルは、インデックスのサイズを、ユーザーの予想されるクエリに関係する単語のみに縮小するために使用されます。たとえば、「a」、「an」、「the」などの英語の冠詞は、キーワード検索に有用な意味を与えないため、索引付けすることはめったに役に立ちません。
通常、特別に作成されたストップワードリストが必要になります。 アプリケーションのニーズに合わせて。ユーザーがクエリに「赤」、「白」、「青」という用語を含めることを期待しない場合、またはこれらの用語がすべてに表示される場合 検索可能なレコード。ストップワードリストに追加することをお勧めします。
MySQLで独自のストップワードリストを使用する手順については、このメッセージの最後にあるメモを参照してください。
参照:
ステップ2.転置インデックスを作成する
既存のレコードから転置インデックスを作成するには、次のことを行う必要があります(擬似コード):
foreach( word(w) in record(r) ) { if(w is not in stopwords) { if( w does not exist in dictionary) { insert w to dictionary at w.id } insert (r.id, w.id) into inverted_index } }ストップワードの詳細:
特定のストップワードリストを使用する代わりに、「if(w is not in stopwords)」テストは、受け入れられない単語のリストの代わりに、またはそのリストの補助として、他の決定を行うことができます。
アプリケーションでは、長さが4文字未満のすべての単語を除外するか、含めるのみを希望する場合があります。 事前定義されたセットからの単語。
独自の転置インデックスを作成することにより、検索をはるかに細かく制御できます。
ステップ3.SQLを使用して転置インデックスをクエリする
この手順は、クエリがインデックスに送信されることをどのように期待するかによって異なります。
クエリを「ハードコーディング」する場合は、selectステートメントを自分で作成するか、ユーザーが入力したクエリをサポートする必要がある場合は、選択したクエリ言語をSQLステートメントに変換する必要があります(通常は、単純なパーサー)。
論理クエリ'(word1 AND word2)OR word3'に一致するすべてのドキュメントを取得する場合、考えられるアプローチは次のとおりです。
CREATE TEMPORARY TABLE temp_results ( rec_id int, count int ) AS
( SELECT rec_id, COUNT(rec_id) AS count
FROM invert AS I, dict AS D
WHERE I.word_id=D.id AND (D.word='word1' OR D.word='word2')
GROUP BY I.rec_id
HAVING count=2
)
UNION (
SELECT rec_id, 1 AS count
FROM invert AS I, dict AS D
WHERE I.word_id=D.id AND D.word='word3'
);
SELECT DISTINCT rec_id FROM temp_results;
DROP TABLE temp_results;
注:これは私の頭のてっぺんからの最初のパスです。ブールクエリ式を効率的なSQLステートメントに変換するより効率的な方法があると確信しており、改善のためのあらゆる提案を歓迎します。
フレーズを検索するには、転置インデックスにフィールドを追加して、単語がレコード内に出現した位置を表し、それをSELECTに含める必要があります。
そして最後に、新しいレコードを追加したり、古いレコードを削除したりするときに、転置インデックスを更新する必要があります。
最後の言葉
「全文検索」は、「情報検索」またはIRとして知られる非常に広い研究分野に分類され、このテーマに関する多くの本があります。
-
情報検索:検索エンジンの実装と評価 StefanBüttcher、Charles L. A. Clarke、Gordon V. Cormack(2010年7月23日)
-
検索エンジン:実際の情報検索 ブルース・クロフト、ドナルド・メッツラー、トレバー・ストローマン(2009年2月16日)
-
検索アプリケーションの構築:Lucene、LingPipe、Gate Manu Konchady(2008年6月)
詳細についてはAmazonを確認してください。
メモ
MySQLでストップワードの独自のリストを使用する方法
MySQLで独自のストップワードリストを使用するには:
- ストップワードの独自のリストを1行に1ワード作成し、サーバー上の既知の場所(/usr/local/lib/IR/stopwords.txtなど)に保存します。
- my.cnfを編集して、次の行を追加または更新します。
[mysqld] ft_min_word_len=1 ft_max_word_len=40 ft_stopword_file=/usr/local/lib/IR/stopwords.txt
これにより、有効な単語の最小長と最大長がそれぞれ1と40に設定され、ストップワードのカスタムリストの場所がmysqldに通知されます。
(注:デフォルトのft_max_word_lenは84です。これはかなり過剰であり、実際の単語ではない文字列の実行にインデックスが付けられる可能性があると思います。)
- mysqldを再起動します
- フルテキスト関連のインデックスをすべて削除して再作成します