16

我正在将我的应用程序搜索从 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

4 回答 4

8

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

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

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

然而,Sphinx 不是存储引擎。查询跨表的确切关系并不那么简单,他们已经用 SphinxQL 稍微修正了这一点,但由于全文索引的性质,它仍然不像你在 MySQL 中那样进行整体连接。

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

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

  • 主要(房屋用户、视频、频道和播放列表)
  • help(帮助系统搜索)

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

请注意,为了通过 delta 处理删除以及您的 Sphinx 集合,您将需要一个 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
}

这每分钟处理一次删除和添加,这对于真正的 Web 应用程序来说几乎是实时的。

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

我会做一个查询来挑选所有的 id 并使用那组 id 使用 sphinx API 上的“过滤器”方法将主索引过滤到特定的文档 id。完成此操作后,您可以像往常一样在 Sphinx 中搜索。这是迄今为止我发现的处理此问题的最有效的方法。

始终要记住的关键是,Sphinx 是一种搜索技术,而 MySQL 是一种存储技术。记住这一点,你应该没问题。

编辑

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

  • 语言是原始的
  • 连接是原始的

但是,它可以/可以完成您正在寻找的工作,因此请务必对其进行调查。

于 2012-08-21T07:55:06.463 回答
6

所以我将继续概述一下 - 我认为 sphinx 的最佳用例是什么,你可以决定它是否或多或少符合你想要做的事情。

如果您要做的只是一个字符串搜索一个字段;然后使用 MySQL,您可以毫不费力地进行通配符搜索,并且诚实地在其上使用索引,除非您期望数百万行您会没事的。

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

例子:

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

此链接:PHP Sphinx 搜索在引导您了解它的外观以及事物如何协同工作方面做得很好。

因此,您并没有真正替换数据库;您只是向它添加了一个特殊的守护程序(sphinx),它允许您创建专门的索引并针对它运行您的全文搜索。

于 2012-08-17T19:46:19.777 回答
5

没有索引可以帮助您进行此查询,因为您正在寻找作为中缀而不是前缀的字符串(您正在寻找'%friendname%',而不是'friendname%'.

此外,该LIKE解决方案会让您陷入困境:假设您正在寻找一个叫Ann的朋友。该LIKE表达式还将匹配MarianneDanny等。表达式中没有“完整单词”的概念LIKE

一个真正的解决方案是使用文本索引。FULLTEXT索引仅在 上可用,MyISAMMySQL 5.6(此时不是 GA)将FULLTEXT在 上引入InnoDB

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

只有数百或数千,您可能不会看到很大的差异,除非您真的要每秒进行多次搜索。有了更大的数字,您最终会意识到全表扫描不如 Sphinx 搜索。

我经常使用 Sphinx,在数十甚至数亿大文本上,并且可以证明它就像一个魅力。

当然,Sphinx 的问题在于它是一个外部工具。使用 Sphinx,您必须告诉它从数据库中读取数据。您可以每5分钟、每小时等执行一次(crontab例如使用) 。因此,如果行是d,则它们只会在下次从表中读取数据时从 sphinx 中删除。如果你能忍受 - 这是最简单的解决方案。DELETE

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

索引更新

实时索引

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

  1. 假设您不会有高负载,请冒险并使用全表扫描。
  2. 等待 MySQL 5.6FULLTEXT与 InnoDB 一起使用。
  3. 使用狮身人面像

在这个时间点,我肯定会使用选项 #3:使用 sphinx。

于 2012-08-19T15:05:09.537 回答
1

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

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

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

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

  • 使用区分大小写的搜索。(易碎;如果您的用户输入的姓名或搜索查询的大小写不正确,则可能会损坏。)
  • 查询后,进一步过滤您的搜索结果,要求搜索词周围的单词边界(例如 regex \bAnn\b)。
于 2015-01-30T09:48:52.840 回答