【问题标题】:How to quickly search book titles?如何快速搜索书名?
【发布时间】:2011-08-21 04:05:54
【问题描述】:

我有一个包含大约 20 万本书的数据库。我希望为我的用户提供一种按书名快速搜索书籍的方法。现在,有些书名可能有 A、THE 等前缀,并且书名中也可以有数字,所以搜索 12 应该匹配书名中带有“12”、“12”和“dozen”的书。这将通过 AJAX 工作,因此我需要确保数据库查询非常快。

我假设大多数用户会尝试使用标题的某些单词进行搜索,因此我正在考虑将所有标题拆分为单词并创建一个单独的数据库表,将单词映射到标题。但是,我担心这可能不会给出最好的结果。例如,书名可能是 2 或 3 个常用词,我可能会得到一个包含所有 2-3 个词的较长标题的书籍列表,而我正在寻找的那本书就像大海捞针一样丢失了。此外,搜索标题中包含许多单词的书可能会因为 OR 子句过多而减慢查询速度。

基本上,我正在寻找一种方法:

  • 快速查找结果
  • 按相关性对它们进行排序。

我认为这不是第一次有人需要这样的东西,我不想重新发明轮子。

附:我目前正在使用 MySQL,但如果需要,我可以切换到其他任何东西。

【问题讨论】:

  • 如果我错了,请纠正我,但是您正在寻找信息检索/搜索引擎系统,对于书籍,不是吗?在这种情况下,请查看 Apache Lucene。
  • @amit,“看看 Apache Lucene”就像是在说“google it”。源代码很大,我有一个非常具体的问题。您能否指出我需要在 Lucene 中查看哪些内容?

标签: algorithm search


【解决方案1】:

使用 SOUNDEX 是我认为的最佳方式。

SELECT
  id,
  title
FROM products AS p
WHERE p.title SOUNDS LIKE 'Shaw'

// This will match 'Saw' etc.

为了获得最佳数据库性能,您可以最好地计算标题的 SOUNDEX 值并将其放入新列中。您可以使用 SOUNDEX('Hello') 计算 soundex。

示例用法:

UPDATE `books` SET `soundex_title` = SOUNDEX(title);

【讨论】:

    【解决方案2】:

    您可能想看看Apache Lucene。这是一个高性能的基于java的信息检索系统。
    您可能想要创建一个 IndexWriter,并为您的所有标题编制索引,并且您可以添加链接到实际书籍的参数(查看类)。
    搜索时,您需要一个 IndexReader 和一个 IndexSearcher,并在它们上使用 search() 操作。
    查看示例:src/demo 和:http://lucene.apache.org/java/2_4_0/demo2.html
    使用信息检索技术会使索引花费更长的时间,但每次搜索都不需要遍历大部分标题,总体而言,您可以期待更好的搜索性能。
    另外,选择好的分析器可以让你忽略诸如“the”、“a”之类的词...

    【讨论】:

      【解决方案3】:

      一种可以轻松满足您的数据量和速度要求的解决方案是使用Redis 键值对存储。 在我看来,您可以继续使用将标题映射到关键字并将它们存储在表单下的解决方案:

      关键字:一组书名

      Redis 已经有一个可以使用的内置 set 数据类型。

      接下来,要获取包含搜索关键字的书名,您可以使用sinter 命令,该命令将为您执行设置交集。

      一切都在内存中完成;因此响应时间非常快。 此外,如果您想保存索引,redis 有许多不同的持久性/缓存机制。

      【讨论】:

        【解决方案4】:

        Apache LuceneSolr 绝对是解决您问题的一个很好的选择

        您可以直接链接 Solr/Lucene 来直接索引您的 MySQL 数据库。这是一个关于如何将 MySQL 数据库与 Lucene/Solr 链接的简单教程:http://www.cabotsolutions.com/2009/05/using-solr-lucene-for-full-text-search-with-mysql-db/

        以下是使用 Lucene-Solr 代替 MySQL 全文搜索的优点和痛点:http://jayant7k.blogspot.com/2006/05/mysql-fulltext-search-versus-lucene.html

        【讨论】:

          【解决方案5】:

          保持简单。在标题字段上创建索引并使用通配符模式匹配。你不可能让它更快,因为你的瓶颈不是字符串匹配,而是你想与标题匹配的字符串数量。

          只是想出了一个不同的想法。你说有些词可以有不同的解释。像 12、12、12 打。与其创建具有不同解释的查询,不如将标题的不同解释存储在单独的表中,并与书籍一对多。然后,您可以 GROUP BY book_id 来获得唯一的书名。

          说“一角钱”这本书。在书籍表中它将是:

          book_id=356
          book_title='A dime in a dozen'
          

          将存储在titles表中:

          titles_id=123
          titles_book_id=356
          titles_title='A dime in a dozen'
          --
          titles_id=124
          titles_book_id=356
          titles_title='A dime in a 12'
          --
          titles_id=125
          titles_book_id=356
          titles_title='A dime in a twelve'
          

          对此的查询: 选择 b.book_id,b.book_title FROM books b 在 b.book_id=t.titles_book_id 上加入标题 t WHERE t.titles_title='%twelve%' GROUP BY b.book_id

          现在,插入成为一项更大的任务,但创建变体可以在数据库之外完成并一举插入。

          【讨论】:

          • 有趣的想法,仍然使用 %twelwe% 需要读取所有记录,因为索引无法使用,甚至没有比开始时更多的记录,所以它会更慢。
          • 老实说,我认为将关键字分配给书籍并保留标题对您的帮助更大。然后,您可以简单地向最终用户提供标题搜索和关键字搜索。标题搜索不会 LIKE foo% 匹配 'as you type',MySQL 应该 将其优化为索引搜索并在提交时 LIKE '%foo%'。关键字仅匹配完整关键字与关键字表中的 a 行匹配的标题。不应允许在关键字搜索中输入“the”的人使用互联网,但您当然可以在搜索页面上礼貌地表述。
          猜你喜欢
          • 2014-10-14
          • 2012-05-25
          • 1970-01-01
          • 1970-01-01
          • 2018-10-10
          • 1970-01-01
          • 2015-03-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多