百度二面,MySQL 怎么做权重搜索?

考虑这样一个搜索需求,有一个 MySQL 表,表中很多个列存放着不同的内容,希望用户通过关键词进行搜索的时候,能够模糊匹配多个列,比如有 t1 列、t2 列、t3 列,同时还希望 t1 列的匹配权重最高,t3 列的匹配权重最低。简单说就是如果有一个关键词同时出现在记录 A 的 t1 列 和里记录 B 的 t2 列,那么记录 A 应该优先展示,排序是在前面的。

注意这里是 MySQL,不是 ES,搜索引擎做这种搜索需求当然得天独厚,但是这种在 MySQL 中进行权重搜索的需求也不是没有,业务初期数据量还不大的时候大概率不会考虑上 ES,这时候在 MySQL 中先简单跑通逻辑才是最重要的。

思考下该如何做?

模糊匹配

首先模糊匹配大家最常用的就是 like

复制代码
SELECT * FROM test 
WHERE t1 LIKE '%标题%' 
 or t2 LIKE '%内容%' 
 or t3 LIKE '%注释%''

当只需要简单的模式匹配时 like 确实往往是更好的选择。而在需要进行复杂匹配,如同一字段中包含多个模式,进行分组匹配等,REGEXP 则表现更为突出,Mysql 支持对列的正则表达式方式查询,使用方式如下:

复制代码
SELECT  * FROM test 
WHERE t1 regexp '标题'
 or t2 regexp '内容' 
 or t3 regexp '注释'

权重搜索

权重搜索涉及到几个 Mysql 函数。

  • LOCATE('标题', test.t1) : 查询 "标题" 在 test.t1 列出现的位置,0 表示未找到。否则返回 坐标位置,坐标位置从 1 开始。

  • IF( 表达式, 1, 0):判断表达式结果,TRUE 则返回 1,FALSE 则返回 0

下面我们来看如何基于这两个函数来实现文章开头的需求:

复制代码
SELECT  *, ( 
    IF(LOCATE('标题',test.t1), 1, 0) 
     + IF(LOCATE('内容',test.t2) , 1, 0) 
     + IF(LOCATE('注释',test.t3) , 1, 0) 
 ) AS weight 
FROM test 
WHERE test.t1 regexp '标题'
 or test.t2 regexp '内容' 
 or test.t3 regexp '注释' 
order by weight desc 

上面的查询中,每个关键词的权重都是 1,所以,在这 t1\t2\t3 三列中,关键词出现次数最多的记录将出现在搜索结果的第一位。

如果权重增加,那么权重高的关键词将会影响排序规则。如下例子,将 t1 列的搜索权重改为 7:

复制代码
SELECT  *, ( 
    IF(LOCATE('标题',test.t1), 7, 0) 
     + IF(LOCATE('内容',test.t2) , 2, 0) 
     + IF(LOCATE('注释',test.t3) , 1, 0) 
 ) AS weight 
FROM test 
WHERE test.t1 regexp '标题'
 or test.t2 regexp '内容' 
 or test.t3 regexp '注释' 
order by weight desc 
相关推荐
阿里小阿希4 小时前
Vue3 + Element Plus 项目中日期时间处理的最佳实践与数据库设计规范
数据库·设计规范
且行志悠4 小时前
Mysql的使用
mysql
白鹭4 小时前
MySQL源码部署(rhel7)
数据库·mysql
666和7775 小时前
Struts2 工作总结
java·数据库
还听珊瑚海吗5 小时前
SpringMVC(一)
数据库
星期天要睡觉6 小时前
MySQL 综合练习
数据库·mysql
Y4090016 小时前
数据库基础知识——聚合函数、分组查询
android·数据库
JosieBook7 小时前
【数据库】MySQL 数据库创建存储过程及使用场景详解
数据库·mysql