0

我正在处理搜索脚本的一部分,其中解析提交的搜索字符串并将每个重要术语放入数组中。然后在 WHERE 子句中循环该数组以搜索 MYSQL 数据库中的多个列。这是一个示例 SQL 代码:

$sql = "SELECT title, question, tag1, tag2, tag3, tag4, tag5 FROM question WHERE ";

while(list($key,$val)=each($split_stemmed)){
          if($val<>" " and strlen($val) > 0){
          $sql .= 
           "(title LIKE '$val%' 
          OR question LIKE '$val%' 
          OR tag1 LIKE '$val%' 
          OR tag2 LIKE '$val%' 
          OR tag3 LIKE '$val%' 
          OR tag4 LIKE '$val%' 
          OR tag5 LIKE '$val%') OR";
          }
}
          $sql=substr($sql,0,(strLen($sql)-3));
          $sql .= "GROUP BY q_id ORDER BY 
           ((title LIKE '$val%') + 
            (question LIKE '$val%') + 
            (tag1 LIKE '$val%') + 
            (tag2 LIKE '$val') + 
            (tag3 LIKE '$val%') +
            (tag4 LIKE '$val%') +
            (tag5 LIKE '$val%')) desc, title asc";

我遇到的问题是让 ORDER BY 正常工作。ORDER BY 的目的是将查询结果从搜索字符串上的最多命中的顺序排列到最少。我的假设是我需要在 ORDER BY 子句中再次循环遍历数组,但不确定如何执行此操作,或者我什至在该假设中是否正确。有帮手吗?

我知道我可以使用 mysql 全文搜索更简单地完成此操作,但使用的表是 InnoDB,所以我认为目前还不是一个选项。

4

2 回答 2

0

需要考虑的几个问题...

1) ORDER BY 表达式中任何列 tag1、tag2、tag3... 中的 NULL 值将为整个表达式返回 NULL。考虑:

SELECT 0 + NULL + 1 + 0 

如果所有这些列都定义为 NOT NULL,那么这不是问题。但更一般地说,您希望与 NULL 值隔离...

ORDER BY ( IFNULL(title    LIKE '$val%'),0) + 
           IFNULL(question LIKE '$val%'),0) + 
           IFNULL(tag1     LIKE '$val%'),0) + 
           IFNULL(tag2     LIKE '$val' ),0) + 

- 或者替代地 -

ORDER BY ( IFNULL(title   ,'') LIKE '$val%') +
           IFNULL(question,'') LIKE '$val%') +
           IFNULL(tag1    ,'') LIKE '$val%') +
           IFNULL(tag2    ,'') LIKE '$val' ) + 
         )

(似乎您缺少%基于模式的 on tag2 ,但遗漏完全有可能是故意的

2)根本不清楚为什么您需要GROUP BY q_id在查询中使用 a 。


我建议您通过使用 ORDER BY 子句中的表达式进行测试,并将其复制到您的 SELECT 列表中,然后运行查询以查看它返回的值。

在 MySQL 中,如果将该表达式添加到 SELECT 列表并为其指定别名,则可以在 ORDER BY 上引用别名。

 SELECT expr AS match_count, ...
   FROM
  ORDER BY match_count DESC
于 2012-09-09T02:52:24.947 回答
0

您正在寻找的功能——在多个列中搜索搜索词并按相关性排序——正是全文搜索的设计目的。如果可能的话,你应该使用它,因为从长远来看它会减少你的头痛。

如果您绝对必须以这种方式实现,那么有必要将LIKE语句移动到SELECT子句中,以便您可以对它们进行求和。像这样:

SUM (CASE WHEN title LIKE '$val%' THEN 1 ELSE 0 END
    + CASE WHEN question LIKE '$val%' THEN 1 ELSE 0 END 
    + CASE WHEN tag1 LIKE '$val%' THEN 1 ELSE 0 END 
    ... etc
) AS relevance

然后只选择匹配项,您可以使用HAVING relevance > 0. 并且要订购,您只需使用ORDER BY relevance DESC(因为上面的相关性列将为您提供匹配列的数量)。

于 2012-09-09T02:58:17.817 回答