有没有更好的方法从Sphinx / MySQL一次从两个表中获取数据?

时间:2012-10-12 11:19:39

标签: php mysql sphinx

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

与我正在实施的功能的最佳比较将是Facebook的搜索功能。当您开始输入时,会出现包含各种搜索结果的下拉列表。在顶部,您会找到名字与您的搜索匹配的朋友,然后是其他匹配的人,然后是页面,活动等....

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

我的工作正常。在我谈论这个功能的逻辑时,请耐心等待我:

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

    • 在两个单独的索引上执行两个单独的 Sphinx 搜索。一个用于收集用户ID,另一个用于收集文档ID(涟漪)
    • 通过检查在ajax请求中发送的用户ID数组来循环用户查询的结果,以避免重复在初始高速朋友/关注者检查期间已经显示的用户。
    • 接下来,我们查询实际数据库以获取剩余用户ID
    • 的用户数据
    • 然后重复相同的过程,但这次是文件(涟漪)
  5. 最后,任何返回的结果都会附加到自动完成列表中。

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

             public function 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 ));

    }

    您可能会问我们为什么要进行初始的朋友查询,而不仅仅是使用sphinx进行所有操作。那么通过实施上述方法。由于朋友阵列存储在客户端,用户在打字时会得到即时反馈,尽管sphinx的速度非常快,但由于http请求不可避免地存在一些延迟。在实践中,它非常有效,顺便说一句,它似乎也是facebook使用的方法。

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

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

    这个当前的服务器端功能困扰了我很多。目前,Sphinx正在进行两次搜索,MySQL正在进行两次搜索。我怎么可能将所有这些整理成一个sphinx查询和一个MySQL查询?有什么办法吗? (请记住,文档和用户可能在MySQL中的两个完全不同的表上共享相同的PK ID,并且(通过两个单独的索引)传播(当前)。或者有没有办法将两个MySQL查询结合起来,使它们比两个单独的选择更有效?

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

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

    非常欢迎任何评论。

2 个答案:

答案 0 :(得分:1)

你真的无法逃脱没有两个MySQL查询。好吧,你可以通过jsut将它们合并为一个,与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

这为您提供了一个假密钥,以及一个用于标识结果来自哪个表的属性。您可以使用它来获取它来自的原始表。 (还有很多其他方法可以做同样的事情)

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

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

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

答案 1 :(得分:0)

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

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

注意:别忘了在sphinx.conf源代码中将所有想要检索数据的文本字段设置为sql_field_string