Sphinx vs. MySql - 搜索朋友列表(效率/速度)

时间:2012-08-01 15:07:20

标签: mysql search indexing sphinx

我正在将我的应用程序从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 vs mysql找到alex的朋友会更有效率吗?或者这会是一种矫枉过正的事情吗?如果sphinx的速度更快,因为这个列表会让成千上万的人感到满意, 索引查询会是什么样的?我如何删除与sphinx不再存在的友谊,在这种情况下我可以有一个详细的例子吗?我应该更改此查询以使用Sphinx吗?

4 个答案:

答案 0 :(得分:7)

好的,这就是我看到它的工作方式。

我和MongoDB有完全相同的问题。 MongoDB“提供”搜索功能,但就像MySQL一样,你不应该使用它们,除非你想被IO,CPU和内存问题所困扰,并被迫使用更多的服务器来处理你的索引。

如果使用Sphinx(或其他搜索技术),整个想法是通过拥有一个高性能的索引搜索器来降低每台服务器的成本。

但Sphinx不是存储引擎。查询表之间的确切关系并不是那么简单,他们已经使用SphinxQL重新进行了一些修复,但由于全文索引的性质,它仍然没有像在MySQL中那样进行整体连接。

相反,我会在MySQL中存储关系,但在Sphinx中有一个“用户”索引。

在我的网站上,我个人有2个索引:

  • main(包含用户,视频,频道和播放列表)
  • 帮助(帮助系统搜索)

这些是每分钟更新一次的delta。由于实时索引有时仍然是有点实验性的,而且我个人已经看到了高插入/删除率的问题,我保持delta更新。所以我会使用delta索引来更新我站点的主要可搜索对象,因为这比实时索引(来自我自己的测试)的资源消耗更少,性能更高。

请注意,为了处理删除以及您的Sphinx集合不是通过delta,您需要一个killlist和delta索引的某些过滤器。这是我的索引中的一个例子:

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
}

这会每分钟处理一次删除和添加,这对于真正的网络应用来说非常实时。

现在我们知道如何存储我们的索引。我需要谈谈这些关系。 Sphinx(尽管它有SphinxQL)不会对数据进行整体连接,所以我个人建议在Sphinx之外做一个关系,不仅如此,但正如我所说的这种关系表将获得高负载所以这可能会影响到狮身人面像指数。

我会查询所有ID并使用该组ID使用sphinx API上的“filter”方法将主索引过滤到特定文档ID。完成后,您可以正常搜索Sphinx。这是迄今为止我发现的最有效的方法。

在任何时候都要记住的关键是Sphinx是一种搜索技术,而MySQL是一种存储技术。记住这一点,你应该没事。

修改

正如@ N.B所说(在我的回答中我忽略了)Sphinx确实有SphinxSE。虽然它是开发性的并且仍然处于其开发的测试阶段(与实时索引相同),但它确实为Sphinx提供了一个实际的MyISAM / InnoDB类型存储。这太棒了。但是有一些警告(与任何事情一样):

  • 语言是主要的
  • 连接是主要的

然而,它可以/可以完成您正在寻找的工作,所以一定要查看它。

答案 1 :(得分:6)

所以我要继续前进并总结一下-I-感觉狮身人面像的最佳使用案例,你可以决定它是否或多或少符合你的目标。

如果您要做的只是字符串搜索一个字段;然后使用MySQL,你可以毫无困难地进行外卡搜索,并且可以使用索引,除非你期望数百万行你会没事。

现在拿facebook,这不仅是索引名称,还有页面等,甚至是任何高级搜索字段。 Sphinx可以从MySQL,PostGRES,MongoDB中获取x列(在此处插入您想要的数据库)并在所有这些列中创建可搜索的全文索引。

示例:

您有5个字段(门牌号码,街道,城市,州,邮政编码),您希望对所有这些字段进行全文搜索。现在使用MySQL,您可以对每一个进行搜索,但是使用sphinx,您可以将它们全部拼接在一起,然后sphinx根据您传入的字符串以及由此产生的匹配来做一些令人敬畏的统计结果。

此链接:PHP Sphinx Searching可以很好地指导您了解它的外观以及如何协同工作。

所以你并没有真正取代数据库;你只需要添加一个特殊的守护进程(sphinx),它允许你创建专门的索引并对它运行全文搜索。

答案 2 :(得分:5)

没有索引可以帮助您解决此问题,因为您正在寻找字符串作为中缀,而不是前缀(您正在寻找'%friendname%',而不是'friendname%'

此外,LIKE解决方案会让您陷入困境:假设您正在寻找一位名为 Ann 的朋友。 LIKE表达式也会匹配 Marianne Danny 等。LIKE表达式中没有“完整单词”概念。

真正的解决方案是使用文本索引。 FULLTEXT索引仅适用于MyISAM,而MySQL 5.6 (此时不是GA)会在FULLTEXT上引入InnoDB

否则,您确实可以使用 Sphinx 来搜索文本。

只有数百或数千,你可能看不到很大的区别,除非你真的要每秒进行多次搜索。数字越大,您最终会发现全表扫描不如Sphinx搜索。

我正在使用Sphinx,数十种,有时甚至是数亿种大型文本,并且可以证明它有点像魅力。

Sphinx的问题当然是它是一个外部工具。使用Sphinx,您必须告诉它从数据库中读取数据。你可以每隔 5 分钟,每小时等,使用crontab等。所以如果行是DELETE d,那么它们只会在下一次从sphinx中移除它从表中读取数据的时间。如果你能忍受 - 那是最简单的解决方案。

如果不能,sphinx中有实时索引,因此您可以直接指示它删除某些行。我无法解释这个端口中的所有内容,所以这里有几个链接:

Index updates

Real time indexes

作为最终结论,您有三种选择:

  1. 冒险并使用全表扫描,假设您没有高负荷。
  2. 等待MySQL 5.6 并将FULLTEXT与InnoDB一起使用。
  3. 使用sphinx
  4. 此时,我肯定会使用选项#3:使用sphinx。

答案 3 :(得分:1)

看看我在这里建议的解决方案: https://stackoverflow.com/a/22531268/543814

您的朋友姓名可能很短,您的查询看起来很简单。您可以负担得起存储所有后缀,可能在一个单独的表中,指向原始表以获取全名。

这会以更多的存储空间为代价为您提供快速中缀搜索。

此外,为了避免在搜索'Ann'时找到'Marianne',请考虑:

  • 使用区分大小写的搜索。 (脆弱;如果您的用户输入的名称或搜索查询的大写不正确,可能会中断。)
  • 查询后,进一步过滤搜索结果,要求搜索字词周围有字边界(例如正则表达式\bAnn\b)。