16

アプリケーション検索を MySQL から Sphinx に移植していますが、これを理解するのに苦労しています。または、移植する必要があるかどうかさえわかりません (この特定のケースで効率のために sphinx を使用する価値があるかどうかを本当に知りたいです)。 /速度):

users
uid uname
  1    alex
  2    barry
  3    david

friends
uid | fid
  1     2
  2     1
  1     3
  3     1

詳細は次のとおりです。
- InnoDB
-ユーザー: uid のインデックス、uname のインデックス
-フレンド: uid、fid の複合インデックス

通常、mysql を使用して alex のすべての友人を検索するには、次のようにします。

$uid = 1
$searchstr = "%$friendSearch%";
$query = "SELECT f.fid, u.uname FROM friends f 
          JOIN users u ON f.fid=u.uid
          WHERE f.uid=:uid AND u.uname LIKE :friendSearch";
$friends = $dbh->prepare($query);
$friends->bindParam(':uid', $uid, PDO::PARAM_INT);
$friends->bindParam(':friendSearch', $searchstr, PDO::PARAM_STR);
$friends->execute();

sphinx と mysql を使用してアレックスの友達を見つける方が効率的ですか、それともやり過ぎでしょうか?
リストが何千人もの人々にヒットするので、スフィンクスがこれに対してより高速になるとしたら、インデックス作成クエリはどのようになりますか? スフィンクスにも存在しない友情を削除するにはどうすればよいですか? この場合の詳細な例を教えてください。Sphinx を使用するようにこのクエリを変更する必要がありますか?

4

4 に答える 4

8

わかりました、これが私がこれがどのように機能するかです。

MongoDB でもまったく同じ問題があります。MongoDB は検索機能を「提供」しますが、MySQL と同様に、IO、CPU、およびメモリの問題で窒息し、通常よりも多くのサーバーを使用してインデックスに対処する必要がある場合を除き、決して使用しないでください。

Sphinx (または別の検索技術) を使用する場合の全体的なアイデアは、パフォーマンスの高いインデックス サーチャーを使用してサーバーあたりのコストを削減することです。

ただし、Sphinx はストレージ エンジンではありません。テーブル間の正確な関係をクエリするのは簡単ではありません。SphinxQL を使用してこれを少し改善しましたが、全文インデックスの性質上、MySQL で得られるような統合結合はまだ実行されません。

代わりに、MySQL 内にリレーションシップを保存しますが、Sphinx 内に「ユーザー」のインデックスを作成します。

私のウェブサイトには、個人的に 2 つのインデックスがあります。

  • メイン (ユーザー、動画、チャンネル、プレイリストを収容)
  • help (ヘルプ システム検索)

これらは 1 分ごとに更新されるデルタです。リアルタイム インデックスはまだ少し実験的であり、個人的には挿入/削除率が高いという問題が見られたので、デルタ アップデートを維持しています。そのため、デルタ インデックスを使用して、サイトの主要な検索可能オブジェクトを更新します。これは、(私自身のテストによると) リアルタイム インデックスよりもリソースの消費が少なく、パフォーマンスが高いためです。

削除を処理し、デルタを介して Sphinx コレクション以外のものを処理するには、キルリストとデルタ インデックス用の特定のフィルターが必要になることに注意してください。これが私のインデックスの例です:

source main_delta : main
{
    sql_query_pre = SET NAMES utf8
    sql_query_pre =
    sql_query = \
        SELECT id, deleted,  _id, uid, listing, title, description, category, tags, author_name, duration, rating, views, type, adult, videos, UNIX_TIMESTAMP(date_uploaded) AS date_uploaded \
        FROM documents \
        WHERE id>( SELECT max_doc_id FROM sph_counter WHERE counter_id=1 ) OR update_time >( SELECT last_index_time FROM sph_counter WHERE counter_id=1 )

    sql_query_killlist = SELECT id FROM documents WHERE update_time>=( SELECT last_index_time FROM sph_counter WHERE counter_id=1 ) OR deleted = 1
}

これにより、削除と追加が 1 分ごとに 1 回処理されます。これは、実際の Web アプリではほぼリアルタイムです。

これで、インデックスを保存する方法がわかりました。私は関係について話す必要があります。Sphinx は (SphinxQL を持っていても) データ全体の統合的な結合を行わないので、個人的には Sphinx の外部で関係を行うことをお勧めします。それだけでなく、前述したように、この関係テーブルは高負荷になるため、これはスフィンクス インデックス。

すべての ID を選択するクエリを実行し、その ID セットを使用して、Sphinx API の「フィルター」メソッドを使用して、メイン インデックスを特定のドキュメント ID にフィルターします。これが完了すると、通常どおり Sphinx で検索できます。これは、これを処理するためにこれまでに見つけた中で最もパフォーマンスの高い方法です。

常に覚えておくべき重要なことは、MySQL がストレージ技術であるのに対し、Sphinx は検索技術であるということです。それを心に留めておけば、大丈夫です。

編集

@NBが言ったように(私の回答では見落としていました)、SphinxにはSphinxSEがあります。原始的で、まだ開発のテスト段階にありますが (リアルタイム インデックスと同じ)、実際の MyISAM/InnoDB タイプのストレージを Sphinx に提供します。これは素晴らしいです。ただし、注意点があります (他の場合と同様):

  • 言語は原始的です
  • 結合はプリミティブです

しかし、それはあなたが探している仕事をすることができます/できるので、必ず調べてください.

于 2012-08-21T07:55:06.463 に答える
6

ですから、先に進んで、Sphinx の最適な使用例が何であるかについて概要を説明します。それが、あなたがやりたいことと多かれ少なかれ一致するかどうかを判断してください。

探しているのが文字列検索だけの場合は、1 つのフィールドを検索します。その後、MySQL を使用すると、問題なく何百万行もあると予想される場合を除き、ワイルド カード検索を問題なく行うことができ、正直にインデックスを使用できます。

Facebook を例にとると、名前だけでなく、ページや高度な検索フィールドのインデックスも作成されます。Sphinx は、MySQL、PostGRES、MongoDB (必要なデータベースをここに挿入) から x 列を取り込み、それらすべてにわたって検索可能な全文インデックスを作成できます。

例:

5 つのフィールド (番地、通り、都市、州、郵便番号) があり、それらすべてに対して全文検索を実行したいとします。MySQL を使用すると、すべての文字列を検索できますが、sphinx を使用すると、それらをすべてまとめてグロブ化でき、sphinx は、渡された文字列とその結果の一致に基づいて、いくつかの素晴らしい統計結果を表示します。

このリンク: PHP Sphinx Searchingは、それがどのように見えるか、どのように連携するかを説明するのに非常に役立ちます。

したがって、実際にはデータベースを置き換えているわけではありません。特殊なインデックスを作成し、それに対して全文検索を実行できる特別なデーモン (sphinx) を追加するだけです。

于 2012-08-17T19:46:19.777 に答える
5

このクエリでは、文字列をプレフィックスではなくインフィックスとして探しているため、インデックスは役に立ちません'%friendname%'( 'friendname%'.

さらに、LIKE解決策は窮地に立たされます: Annという名前の友人を探しているとします。この式は、 MarianneDannyLIKEなどにも一致します。式には「完全な単語」という概念はありません。LIKE

本当の解決策は、テキスト インデックスを使用することです。FULLTEXTインデックスは でのみ使用でき、MyISAMMySQL 5.6 (現時点では GA ではありません) は で導入さFULLTEXTInnoDBます。

それ以外の場合は、実際にSphinxを使用してテキストを検索できます。

ほんの数百または数千の場合、1 秒間に多くの検索を実際に実行しない限り、おそらく大きな違いは見られないでしょう。数値が大きいほど、完全なテーブル スキャンが Sphinx 検索よりも劣ることが最終的にわかります。

私は何十、時には何億もの大きなテキストで Sphinx をよく使っており、それが魅力的に機能することを証明できます。

もちろん、Sphinx の問題は、それが外部ツールであることです。Sphinx では、データベースからデータを読み取るように指示する必要があります。これを (crontabたとえば) 5分ごと、1 時間ごとなどに行うことができます。したがって、行がDELETEd の場合、次にテーブルからデータを読み取るときにのみ sphinx から削除されます。それを受け入れることができるなら、それが最も簡単な解決策です。

できない場合は、sphinx にリアルタイム インデックスがあるため、特定の行を削除するように直接指示することができます。このポートのすべてを説明することはできないため、ここにいくつかのリンクを示します。

インデックスの更新

リアルタイムインデックス

最終的な結論として、次の 3 つのオプションがあります。

  1. 負荷が高くないと仮定して、リスクを冒してフルテーブルスキャンを使用してください。
  2. MySQL 5.6FULLTEXTを待ち、 InnoDBで使用します。
  3. スフィンクスを使う

この時点で、私は間違いなくオプション 3 を使用します: Sphinx を使用します。

于 2012-08-19T15:05:09.537 に答える
1

ここで提案するソリューションをご覧ください: https://stackoverflow.com/a/22531268/543814

友達の名前はおそらく短く、クエリは単純に見えます。完全な名前を取得するために元のテーブルを指すように、おそらく別のテーブルにすべてのサフィックスを保存する余裕があります。

これにより、ストレージ容量が少し増えますが、高速な中置検索が可能になります。

さらに、「Ann」を検索するときに「Marianne」が見つからないようにするには、次のことを考慮してください。

  • 大文字と小文字を区別する検索の使用。(脆弱です。ユーザーが大文字と小文字を正しく使用せずに名前や検索クエリを入力すると壊れる可能性があります。)
  • クエリの後、検索結果をさらにフィルタリングし、検索語の周囲に単語境界を必要とします (例: regex \bAnn\b)。
于 2015-01-30T09:48:52.840 に答える