首先我们首先要了解几个概念
- MySQL自带英文的全文搜索功能,需要知道fulltext索引和myisam引擎。
- 英文全文搜索是靠单词之间的空格实现的。
- 英文全文搜索的三个模式以及权重分析。
什么是索引
这边我先做一个说一下索引有什么用?众所周知,你要执行查询,如果没有索引的话,他的搜索方式是检表,即从前到后依次对表进行遍历,最简单的例子
SELECT * FROM users WHERE age=18
这条语句会检查所有表中的数据,直到表没数据了为止,可想而知,如果是数据量较少,速度几乎是不能察觉出来的,但数据量一旦十万百万等,会有明显的延迟。而如果我们给age建立了索引,那么这这个索引的数据将会是这样的。
index | age |
---|---|
18 | 18 |
19 | 19 |
20 | 20 |
18 | 18 |
此处index为索引标识符,里面存储的是标识符和数据地址,当我们用上面的SQL语句搜索时,步骤是,搜索索引标识符,通过索引标识符,得到所有age=18
的数据地址,然后依次取出来。
这样,便省去了检表的操作。
这样,是不是省去了不少时间。
Fulltext的效果就是这样的。
英文全文搜索的三个模式
- 自然搜索模式
MySQL会把搜索字符串解析成一系列的单词,然后搜索出保函这些单词的所在行。
SELECT * FROM index_article WHERE MATCH(content) AGAINST('中国 北京')
这条语句意思为:搜索索引表中字段为content中包含关键词'中国'、'北京'的文章。
- 布尔搜索模式
在搜索的字符串中可以存在修饰符
SELECT * FROM index_article WHERE MATCH(content) AGAINST('+北京 -朝阳' IN BOOLEAN MODE)
这条语句的意思为搜索索引表中包含'北京'不包含'朝阳'的文章。
- 扩展搜索模式
两次搜索,第一次搜索是自然搜索,第二次搜索会吧第一次搜索中内容中所有次再次进行匹配,从而达到扩大饭的效果。
SELECT * FROM index_article WHERE MATCH(content) AGAINST('中国 北京' WITH QUERY EXPANSION)
这句的效果是,当第一次搜索时候,搜索到了一句北京朝阳男性市民
,第二次扩展搜索时,会将男性
和市民
加入搜索行列,即所有出现这些关键词的时候,都会被搜索到。
权重,怎么计算?
一条语句搞定,但是中文特殊一点,在源码中我有使用到。
SELECT id, MATCH(content) AGAINST('中国 北京') AS weight FROM index_article
之前写的条件变成了权重显示的字段。这条语句的效果为,所有匹配到这两个关键词的内容,会根据次数,密度,比例等指标计算权重。示例如下:
id | weight |
---|---|
1 | 1.2323232123 |
2 | 1.3423423423 |
3 | 2.3421231231 |
4 | 0.2213123123 |
好,基本知识普及完成,接下来讲下中文全文搜索的思路以及源码
思路解析
项目:做一个博客,可以进行文章上传、展示、站内全文关键词搜索、搜索关键字提示、搜索权重分析。
项目思路:对文章和标题进行分词操作,分词写入数据库的索引表,原数据写入原表;关键词高亮显示,可以使用字符串替换;权重计算关键词出现的次数。
数据表截图
多插入几条数据才能实现
展示页面+搜索
个人博客
个人网站
get_keyword($keywords);
unset($keywords);// 释放变量
// 准备sql语句
$sql = "SELECT fid FROM index_article WHERE MATCH(title,content) AGAINST('".$key."')";
$rtn = $model->get_all($sql);
unset($sql);// 释放变量
$keys = explode(' ', $key);// 将关键字分割成数组
$res = [];// 建立空数组存储数据
for($i=0;$iget_one($sql);
unset($sql);// 销毁变量
//这边做一个相似度评级
$res[$i]['title_num'] = 0;
$res[$i]['content_num'] = 0;
for($j=0;$j$v){
$weight[$k] = $v['weight'];
}
@array_multisort($weight,SORT_NUMERIC,SORT_DESC,$res);
// 销毁变量
unset($rtn);
unset($weight);
}else{
$sql = "SELECT * FROM article";
$res = $model->get_all($sql);
unset($sql);
}
$str = '';
for($i=0;$i'.$res[$i]['title'].'';
$str .= ''.$res[$i]['content'].'
';
$str .= '';
$str .= '';
$str .= ' ';
}
// // $s = '';
// 替换多个关键字
for($i=0;$i".$keys[$i]."",$str);
}
echo $str;
// 释放变量
unset($keys);
unset($str);
?>