1

在问这个问题之前,重要的是要了解我实际上在做什么。

与我正在实施的功能的最佳比较是 Facebook 的搜索功能。当您开始键入时,会出现一个带有各种搜索结果的下拉列表。在顶部,您会找到名字与您的搜索匹配的朋友,然后是匹配的其他人,然后是页面、事件等。

我的情况类似,但我只想搜索两件事。用户和文档(在下面的代码中命名为涟漪)。

我有这个工作正常。在我讨论此功能的逻辑时,请多多包涵:

  1. 用户关注搜索输入。
  2. Ajax 请求检索登录的用户朋友/关注者/关注者并在客户端缓存它们(这只发生在用户第一次关注搜索输入时)
  3. 当用户键入时,高度优化的函数对用户名数组执行正则表达式,并构建一个包含头像等的自动完成列表......
  4. 同时,每次按键都会向下面的脚本触发一个 ajax 请求,该脚本执行以下操作

    • 对两个单独的索引执行两个单独的Sphinx搜索。一个收集用户 ID,另一个收集文档 ID(rippleid)
    • 用户查询的结果通过检查在 ajax 请求中发送的用户 ID 数组进行循环,以避免重复在初始高速朋友/关注者检查期间已经显示的用户。
    • 接下来我们查询实际数据库以获取剩余用户 ID 的用户数据
    • 然后重复相同的过程,但这次是针对文档(涟漪)

最后,任何返回的结果都会附加到自动完成列表中。

这是执行 sphinx 查找并从数据库中获取数据的 PHP 函数示例。

         公共功能搜索()
                {
                                $this->disableLayout();
                                $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 ));

}

您可能会问为什么我们要进行初始朋友查找,而不仅仅是对所有内容都使用 sphinx。那么通过实现上面的方法。由于客户端存储了好友数组,用户在打字时会得到即时反馈,尽管 sphinx 的速度非常快,但由于 http 请求,不可避免地会出现一些延迟。在实践中,它的效果非常好,顺便说一下,它似乎也是 facebook 使用的方法。

还有很多 javascript 代码防止不必要的查找,返回的数据被添加到缓存堆等,因此未来的搜索不需要点击 sphinx/db 等......

现在终于到了我的实际问题....

这个当前的服务器端功能让我很困扰。目前,Sphinx 执行了两次搜索,MySQL 执行了两次搜索。我怎么可能将所有这些整理成一个 sphinx 查询和一个 MySQL 查询?有什么办法吗?(请记住,文档和用户可能共享相同的 PK ID,因为它们位于 MySQL 中的两个完全不同的表上,并且(当前)分布在两个单独的索引中)。或者有什么方法可以组合两个 MySQL 查询,使它们比两个单独的选择更有效?

或者...由于查询的简单性,我最好将它们分开吗?(两者都是索引主键查询)

我想我要的是任何建议/建议。

非常欢迎任何评论。

4

2 回答 2

1

如果没有两个 MySQL 查询,您将无法真正摆脱困境。好吧,您可以使用 UNION 将它们组合成一个。或者通过创建一个新的组合“表”(视图或物化视图) - 但真的不认为它值得付出努力。两个查询非常好-正如您所说的那样,它们已编入索引。

您可以通过创建一个新的组合索引来使用一个 sphinx 索引(因此也可以使用一个搜索查询)。因为您说您的密钥不是唯一的,所以必须创建一个新的合成密钥。

例如...

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

这给了你一个假的 key 和一个属性来识别结果来自哪个表。您可以使用它来获取它来自的原始表。(有许多其他方法可以做同样的事情)

这允许您运行一个查询,可以获得组合结果。

...但不相信这是一个好主意。因为如果结果不对称,您可能会错过结果。假设一个表有 20 个匹配结果,另一个表有 10 个。假设您显示前 10 个结果,现在由于限制,第二个表的结果很可能隐藏在第一个表下方(实际上是极端示例,希望它们混合在一起)。两个单独的查询,允许您保证从每个表中获取一些结果。

......所以毕竟。坚持你得到的。没关系。

于 2012-10-12T16:23:28.613 回答
0

您可以在 Sphinx 中存储和检索有关用户和文档的所有数据,因此不需要 MySQL。

使用 Sphinx QL 而不是 API(更好更容易完成工作 -> http://sphinxsearch.com/docs/current.html#sphinxql-reference

注意:不要忘记在 sphinx.conf 源中将要从中检索数据的所有文本字段设置为 sql_field_string

于 2012-10-12T17:10:16.063 回答