1

この質問をする前に、私が実際に何をしているのかを理解することが重要です。

私が実装している機能との最良の比較は、Facebookの検索機能です。入力を開始すると、さまざまな検索結果とともにドロップダウンリストが表示されます。上部には、名前が検索に一致する友達、一致する他の人、ページ、イベントなどが表示されます。

私の状況は似ていますが、2つだけ検索したいと思います。ユーザーとドキュメント(以下のコードではリップルという名前が付けられています)。

私はこれがうまく機能しています。私の場合、この機能のロジックについて話している間、我慢してください。

  1. ユーザーは検索入力に焦点を合わせます。
  2. Ajaxリクエストは、ログインしているユーザーの友達/フォロワー/フォローを取得し、クライアント側にキャッシュします(これは、ユーザーが検索入力に初めて焦点を合わせたときにのみ発生します)
  3. ユーザーが入力すると、高度に最適化された関数がユーザー名の配列に対して正規表現を実行し、アバターなどを含むオートコンプリートリストを作成します...
  4. 同時に、キーを押すたびに、次のスクリプトに対してajaxリクエストが実行されます

    • 2つの別々のインデックスで2つの別々のSphinx検索を実行します。1つはユーザーIDを収集し、もう1つはドキュメントID(rippleid)を収集します
    • ユーザークエリの結果は、ajaxリクエストで送信されたユーザーIDの配列とのチェックを通じてループされ、最初の高速フレンド/フォロワーチェック中にすでに表示されたユーザーの重複を回避します。
    • 次に、実際のデータベースにクエリを実行して、残りのユーザーIDのユーザーデータを取得します。
    • その後、同じプロセスが繰り返されますが、今回はドキュメント(リップル)に対して

そして最後に、返された結果がオートコンプリートリストに追加されます。

これは、スフィンクスルックアップを実行してデータベースからデータを取得するPHP関数の例です。

         パブリック関数search()
                {{
                                $ this-> disableLayout();
                                $ request = new Request();
                                $ params = $ request-> getParams(GET);

//Perform sphinx textsearch include('/usr/local/lib/php/sphinxapi.php'); $sphinx = new \SphinxClient(); $sphinx->setMatchMode(SPH_MATCH_ANY); $sphinx->SetLimits(0, 4); $mysqlconn = mysql_connect("127.0.0.1:9306") or die ("Couldn't connect to MySQL."); $users = $sphinx->Query($params['data']['q'], "users"); $ripples = $sphinx->Query($params['data']['q'], "ripples"); /* *USERS */ //Loop through users and only collect ID's that are not already present if (!empty($users["matches"])) { $ids = ""; foreach($users['matches'] as $id => $data) { if($ids > ""){ $ids .= ","; } if(!isset($params['data']['e'][$id])){ $ids .= $id; } } //If there any any remaining ID's collect the data from the database and return as JSON if(!empty($ids)){ $userdataquery = "select users.userid, users.firstname, users.lastname from tellycards_user_data users where userid IN($ids) "; $query = new Query($userdataquery); $usersoutput = $query->fetchAll(); } } /* *RIPPLES */ //Loop through ripples and collect ID's if (!empty($ripples["matches"])) { $rippleids = ""; foreach($ripples['matches'] as $id => $data) { if($rippleids > ""){ $rippleids .= ","; } $rippleids .= $id; } //If there any any remaining ID's collect the data from the database and return as JSON if(!empty($rippleids)){ $rippledataquery = "select ripples.id, ripples.name, ripples.screenshot from tellycards_ripples ripples where id IN($rippleids) "; $query = new Query($rippledataquery); $ripplesoutput = $query->fetchAll(); } } header('Content-type: text/json'); echo json_encode(array( 'users' => (!empty($usersoutput)) ? $usersoutput : null, 'ripples' => (!empty($ripplesoutput)) ? $ripplesoutput : null ));

}

すべてにスフィンクスを使用するだけでなく、なぜ最初の友達検索を行うのかと疑問に思われるかもしれません。さて、上記の方法を実装することによって。友人の配列がクライアント側に保存されているため、ユーザーは入力中に即座にフィードバックを受け取りますが、スフィンクスの素晴らしい速度にもかかわらず、httpリクエストのために必然的に多少の遅れが生じます。実際には、それは素晴らしく、偶然にも機能し、Facebookも使用している方法のようです。

また、不要なルックアップを防ぐ多くのjavascriptコードがあり、返されたデータはキャッシュパイルなどに追加されるため、将来の検索ではsphinx/dbなどを押す必要がありません...

最後に、私の実際の質問に移ります。

この現在のサーバー側の機能は私をとても悩ませます。現在、Sphinxによって実行されている2つの検索と、MySQLによって実行されている2つの検索があります。これらすべてを1つのスフィンクスクエリと1つのMySQLクエリに照合するにはどうすればよいですか?何か方法はありますか?(ドキュメントとユーザーは、MySQLの2つの完全に異なるテーブルにあり、(現在)2つの別々のインデックスに分散しているため、同じPK IDを共有する場合があることに注意してください)。または、2つのMySQLクエリを組み合わせて、2つの別々の選択を行うよりも効率的にする方法はありますか?

または代わりに...クエリの単純さのために、私は上記のようにそれらを別々に保つのが最善ですか?(どちらもインデックス付きの主キークエリです)

私が求めているのは、推奨事項/アドバイスだと思います。

どんな解説でも大歓迎です。

4

2 に答える 2

1

2つのMySQLクエリがないことで本当に逃げることはできません。どちらかを組み合わせて、UNIONを使用することもできます。または、新しい結合された「テーブル」(ビューまたはマテリアライズドビューのいずれか)を作成することによって-しかし、実際には努力する価値があるとは思わないでください。2つのクエリは完全に問題ありません-あなたが言うように、それらは索引付けされています。

新しい結合インデックスを作成することで、1つのスフィンクスインデックス(したがって1つの検索クエリ)を使用できます。キーは一意ではないと言うので、新しい合成キーを作成する必要があります。

例えば...

sql_query = SELECT userid*2 AS id, 1 AS table_id, firstname AS one, lastname as two FROM tellycards_user_data \
              UNION \
            SELECT (id*2)+1 as id, 2 AS table_id, name AS one, screenshot AS two FROM tellycards_ripples
sql_attr_unit = table_id

これにより、偽のキーと、結果がどのテーブルからのものであるかを識別する属性が提供されます。これを使用して、元のテーブルを取得できます。(同じことをする方法は他にもたくさんあります)

これにより、1つのクエリを実行し、組み合わせた結果を得ることができます。

...しかし、その良い考えを確信していません。結果が非対称である場合、結果を見逃す可能性があるためです。1つのテーブルから20の一致する結果があり、別のテーブルから10の一致する結果があるとします。上位10件の結果を表示するとします。これは、制限があるため、2番目のテーブルの結果が最初のテーブルの下に隠れている可能性があります(極端な例では、実際には、それらが混在していることを願っています)。2つの個別のクエリにより、各テーブルからいくつかの結果を取得することが保証されます。

...結局のところ。あなたが得たものに固執する。大丈夫だよ。

于 2012-10-12T16:23:28.613 に答える
0

ユーザーとドキュメントに関するすべてのデータをSphinxに保存および取得できるため、MySQLは必要ありません。

APIではなくSphinxQLを使用します(作業をより簡単に行うことができます-> http://sphinxsearch.com/docs/current.html#sphinxql-reference

注意:データを取得するすべてのテキストフィールドを、sphinx.confソースのsql_field_stringとして設定することを忘れないでください。

于 2012-10-12T17:10:16.063 に答える