在可变数量的参数上搜索表多个列

时间:2018-03-02 16:43:27

标签: php mysql mariadb

我有一个搜索输入框,用户可以在其中输入一个或多个单词,php脚本应返回所有这些单词包含在任何列中的所有行。

假设一个这样的表:

|car_id|make|model|year|plate|
+----------------------------+
|  1   |Audi|A4   |2010|AAAAA|
|  2   |Audi|A4   |2012|AAAAB|
|  3   |Audi|Q5   |2010|AAAAC|
+----------------------------+

如果用户输入“Aud”,他将获得3行。如果它进入“2010奥迪”,他会得到第1行和第3行,如果他进入“2010年第5季度”,他只会获得第3行。

我做了什么。

如果输入只有1个术语,我可以构建一个像

这样的查询
SELECT * FROM car WHERE make LIKE '%term%' OR model like '%term%' OR year like '%term%'

如果用户输入2个术语,我必须改为创建此查询(即使不考虑板列)

SELECT * FROM car WHERE 
     (make LIKE '%term%' AND model LIKE '%term2%') 
  OR (make LIKE '%term2%' AND model LIKE '%term%')
  OR (make LIKE '%term%' AND year LIKE '%term2%')
  OR (make LIKE '%term1%' AND year LIKE '%term%')
  OR (model LIKE '%term%' AND year LIKE '%term%')
  OR (model LIKE '%term2%' AND year LIKE '%term1%')

如果用户输入3个术语,则查询的指数会更加复杂。

我读到了关于MATCH关键字但有些列不是文本,就像这个例子中的年份一样。

进行此类搜索的正确方法是什么?我应该更改数据库架构吗?将所有可搜索的列concat转换为字符串并执行一些正则表达式,

谢谢。

1 个答案:

答案 0 :(得分:0)

  1. 创建一个额外的列all。它包含您需要搜索的所有列的CONCAT_WS(' ', ...)
  2. 在该列上创建FULLTEXT(all)索引。
  3. 只用一个子句构造查询:

    WHERE MATCH(all) AGAINST("+Audi +q5 +2010" IN BOOLEAN MODE)

  4. 的问题:

    • FULLTEXT的字长最短;要么改变它(唉,这是一个全球性的设置),要么以不同的方式处理短的“词”。例如,如果min字len为3,则从AGAINST字符串中的'q5'之前删除'+'。否则,InnoDB将找不到行。
    • 同样处理“停止词”。或者删除停止列表。
    • 以某种方式处理连字符等。
    • ORDER BY MATCH ... LIMIT 20可能有助于(1)对奇怪的情况给予一些偏好,以及(2)在用户指定不够时限制输出。
    • 或者你可能想公平地做ORDER BY RAND() LIMIT 20

    如果您使用的是5.7或MariaDB,则“生成”列可能会有用。