【问题标题】:Mysql, PHP, searching for multiple wordsMysql,PHP,搜索多个单词
【发布时间】:2013-10-11 20:55:37
【问题描述】:

我正在尝试在表格中搜索特定字词。

假设我有一个单词列表:打印机、网络、无线、紧急

我只想返回包含所有这些单词的行。

SELECT * FROM tickets WHERE concat(subject,body) REGEXP "printer|network|wireless|urgent" 

将返回包含这些单词中的任何一个的任何行。我怎样才能使它只返回所有这些单词都在其中的行。

谢谢,

【问题讨论】:

  • 必须出现的字数是固定的还是可变的?
  • 最好是一个变量。
  • 你可以做LIKE '%word1%' AND LIKE '%word2%' AND ...,虽然性能不会很好。如果您通常实现关键字搜索,您可能希望研究基于文本索引的系统,例如 Zend Lucene(基于 PHP,如果您不介意使用其他语言,还有其他系统)。

标签: php mysql search


【解决方案1】:

有两种方法可以做到这一点。第一种是相当明显的方法。假设您有所有需要出现在名为 $necessaryWords 的数组中的单词:

$sql = 'SELECT ... FROM ...'; // and so on
$sql .= ' WHERE 1';

foreach ($necessaryWords as $word)
    $sql .= ' AND concat(subject,body) LIKE "%' . $word . '%"'; //Quotes around string

但是,使用%foo% 相当慢,因为不能使用索引,因此此查询可能会导致大型表和/或大量必要单词的性能问题。

另一种方法是在subjectbody 上建立FULLTEXT 索引。您可以像这样使用全文MATCH IN BOOLEAN MODE

$sql = 'SELECT ... FROM ...'; // and so on
$sql .= ' WHERE MATCH(subject,body) AGAINST("';

foreach ($necessaryWords as $word)
    $sql .= ' +' . $word;
$sql .= '")';

请注意,您的表必须使用MyISAM 才能使用FULLTEXT 索引。 更新:As of MySQL 5.6InnoDB 也支持FULLTEXT 索引。我想这可能是更好的选择性能。更多关于布尔模式全文的文档可以在manual中找到。

【讨论】:

  • @DobotJr:出于好奇和此页面未来可能的访问者:您选择了哪个版本,为什么?
【解决方案2】:

不是最好的方法,但是:

SELECT * FROM tickets WHERE
concat(subject,body) REGEXP "printer" AND
concat(subject,body) REGEXP "network" AND
concat(subject,body) REGEXP "wireless" AND
concat(subject,body) REGEXP "urgent"

【讨论】:

    【解决方案3】:
    SELECT * FROM tickets WHERE
       concat(subject,body) LIKE "%printer%" AND
       concat(subject,body) LIKE "%network%" AND
       concat(subject,body) LIKE "%wireless%" AND
       concat(subject,body) LIKE "%urgent%"
    

    【讨论】:

      【解决方案4】:

      不确定这是否适用于 MySQL 正则表达式引擎,但下面的正则表达式(使用外观)可以实现您正在寻找的内容。将找到感兴趣的单词,无论它们出现的顺序如何:

      ^(?=.*printer)(?=.*network)(?=.*wireless)(?=.*urgent).*$
      

      演示:http://www.rubular.com/r/XcVz5xMZcb

      这里有一些正则表达式环视示例:http://www.rexegg.com/regex-lookarounds.html

      【讨论】:

        【解决方案5】:

        替代答案,只是因为我在看你的问题时想到了它。我不知道它是否会比其他答案更快(很可能不是):

        (SELECT * FROM tickets WHERE subject LIKE "%printer%" OR body LIKE "%printer%")
        UNION
        (SELECT * FROM tickets WHERE subject LIKE "%network%" OR body LIKE "%network%")
        UNION
        (SELECT * FROM tickets WHERE subject LIKE "%wireless%" OR body LIKE "%wireless%")
        UNION
        (SELECT * FROM tickets WHERE subject LIKE "%urgent%" OR body LIKE "%urgent%")
        

        更新: 这是错误的

        【讨论】:

        • 这将返回包含任一单词的所有行。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-18
        • 1970-01-01
        • 2011-10-06
        • 1970-01-01
        • 1970-01-01
        • 2015-07-13
        相关资源
        最近更新 更多