【问题标题】:WHERE x LIKE'%$find%' - What if $find = 2 seperate values?WHERE x LIKE'%$find%' - 如果 $find = 2 个单独的值怎么办?
【发布时间】:2011-10-23 02:27:27
【问题描述】:

我正在为产品目录创建搜索功能。

这是目前为止的输入代码:

<form name="search" method="post" action="'.$PHP_SELF.'">
    <div>
    Search for: <input type="text" name="find" />
    <input type="hidden" name="searching" value="yes" />
    <input type="submit" name="search" value="Search" />
    </div>
</form>

这是查询 Mysql 数据库以进行匹配的查询:

SELECT * FROM `products` WHERE upper(`desc`) LIKE'%$find%'

当用户搜索一个单词字符串时,这一切都很好。

这里的问题是,当用户搜索两个单词的字符串时,找不到匹配项,因为有时这些字符串与单独的特征相关。

例如,产品目录包含有关各种巧克力的信息:

你会得到巧克力棒、巧克力盒、巧克力包等......

现在虽然desc 字段中的一些描述包含单词巧克力和棒,但有些包含变体,例如“公司棒 120 克巧克力”。

这会导致上述代码出现问题,因为如果用户搜索“巧克力吧”,除非desc 字段中的描述明确包含该变体,否则不会返回任何匹配项。

我希望发生的是,当用户搜索“巧克力吧”时,将返回包含变体“巧克力”和“酒吧”的任何匹配项。

有人对我将如何完成这项任务有任何意见吗?

可以把$find 变成一个数组,然后用“”作为分隔符吗?

【问题讨论】:

  • 这就是类别/标签的用途。
  • @Tomalak 再次嗨!我对此很陌生,但我会研究这些类别和标签,感谢您的输入!
  • 我的意思是你会创建它们、索引它们并搜索它们,而不是强迫自己搜索人类可读的“描述”。

标签: php mysql forms search


【解决方案1】:

您需要将字符串拆分为多个部分,然后将它们全部分别添加到where 子句中。即:

.... WHERE `desc` LIKE '%bar%' OR `desc` LIKE '%chocolate%'

但请注意,这可能是一个有点慢的查询!无论如何,SQL 中的通配符搜索速度很慢,而且多个通配符会使问题更加复杂。

您可以使用FULLTEXT 获得更快的结果。这需要额外的数据库设置工作,但更重要的是,它在您给出的示例中可能没有用,因为FULLTEXT 通常会从索引中删除短词。它是可配置的,所以你也许可以让它工作,但FULLTEXT 的重点是为大块文本建立一个搜索索引;它并不是真正用于较短的字符串。

此类问题的更常见解决方案是使用标记,并搜索标记而不是字符串。这将涉及基本上有一个单独的表,其中包含来自每条记录的所有相关关键字,单独存储。这使您可以非常快速地搜索,因为您可以完全摆脱通配符。您甚至可以添加其他可能不在实际文本中的同义词关键字,这有助于使搜索更易于使用。

如果您的用户确实无法通过标记解决方案找到他们想要的内容,您仍然可以为他们提供“高级”搜索,这可以追溯到通配符解决方案。只要确保他们知道这会很慢。

【讨论】:

  • 这并不能进行全词搜索。我更喜欢从输入标记构建一个聪明的 FULLTEXT 搜索。
  • desc为保留字,请用反引号表示。
  • 这就是我的想法。但确实你提出了一个观点。对更快的方法有什么建议吗?
  • @cularis - 当然。固定的。为了我好,我打字太快了:-)
  • @BlackberryFan - 添加了一些关于其他解决方案的注释。
【解决方案2】:

也许你可以这样做:

$keywords_array = explode(' ', $find);

$qry = "SELECT * FROM `products` WHERE `desc` LIKE '%" 
       . implode("%' OR `desc` LIKE '%", $keywords_array) 
       . "%'";

$find = 'this' 的输出:

SELECT * FROM products WHERE desc LIKE '%this%'

$find = 'this and that' 的输出:

SELECT * FROM products WHERE desc LIKE '%this%' OR desc LIKE '%and%' OR desc LIKE '%that%'

这确实是一个非常基本的功能,但你明白了。

【讨论】:

    【解决方案3】:

    第一个问题是将搜索拆分为单个单词。这可以在 PHP 本身中轻松完成,但根据您的搜索,您可能还启用了短语,例如"this is a phrase" 如果没有,很容易将搜索文本用空格分隔。

    对于您的第二个问题,两种可能的解决方案都已发布,您可以使用... LIKE 'chocolate% OR LIKE 'bar%(注意:我只在单词后添加了 % - 我会避免在两边都使用它,除非您想查找单词部分同样,例如 hocol 仍然必须匹配 chocolade。这非常慢,因为无法使用索引!

    如前所述,更好的解决方案是fulltext search,使用MATCH()... AGAINST(),因为该解决方案利用全文索引并大大加快了搜索速度!

    【讨论】:

      【解决方案4】:

      转向正则表达式怎么样?

      您可以用$find 中的| 替换空格(或您喜欢的任何输入语法)来模拟“OK”:

      "chocolate bar" => "chocolate|bar" (如果你需要单词边界,甚至是 "\b(chocolate|bar)\b") p>

      或者你可以转换成跟随来模拟“AND”

      “巧克力吧”=>“巧克力。*吧”

      然后执行:

      WHERE desc REGEXP '$find'

      仔细检查性能是否适合您。

      【讨论】:

        【解决方案5】:

        您应该查看 FULLTEXT INDEX Documentation

        desc LIKE '%word%' 会越来越重。 用户还可以提供 2 个词甚至更多。只需将查询分解为更多单词并构建一个覆盖所有可能性的 where 子句:

        WHERE desc LIKE '%word1%' or desc LIKE '%word2%' OR  ....
        

        同样,这不是非常有效或快速,FULLTEXT + MATCH AGAINST 效果更好。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-10-19
          • 1970-01-01
          • 1970-01-01
          • 2023-03-22
          • 1970-01-01
          • 1970-01-01
          • 2019-10-16
          • 2010-10-16
          相关资源
          最近更新 更多