この質問をする前に、私が実際に何をしているのかを理解することが重要です。
私が実装している機能との最良の比較は、Facebookの検索機能です。入力を開始すると、さまざまな検索結果とともにドロップダウンリストが表示されます。上部には、名前が検索に一致する友達、一致する他の人、ページ、イベントなどが表示されます。
私の状況は似ていますが、2つだけ検索したいと思います。ユーザーとドキュメント(以下のコードではリップルという名前が付けられています)。
私はこれがうまく機能しています。私の場合、この機能のロジックについて話している間、我慢してください。
- ユーザーは検索入力に焦点を合わせます。
- Ajaxリクエストは、ログインしているユーザーの友達/フォロワー/フォローを取得し、クライアント側にキャッシュします(これは、ユーザーが検索入力に初めて焦点を合わせたときにのみ発生します)
- ユーザーが入力すると、高度に最適化された関数がユーザー名の配列に対して正規表現を実行し、アバターなどを含むオートコンプリートリストを作成します...
同時に、キーを押すたびに、次のスクリプトに対して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つの別々の選択を行うよりも効率的にする方法はありますか?
または代わりに...クエリの単純さのために、私は上記のようにそれらを別々に保つのが最善ですか?(どちらもインデックス付きの主キークエリです)
私が求めているのは、推奨事項/アドバイスだと思います。
どんな解説でも大歓迎です。