为什么需要 SearchEngine
为什么关系型数据库无法全文检索?
慢
关系型数据库通常以 B+ 树作为底层索引。一般我们在 MySQL 中模糊搜索这样用:
1 | select * from my_table where title like '%term%'; |
首先这个查询一定会触发全表扫描,即使 title 字段上建立了索引,like 语句中的 % 也会导致索引生效。
全表扫描有多慢?
全表扫描本质上就是要把整张表的数据从磁盘中顺序读取出来,读取速度取决于存储介质的 I/O,因此耗时与数据量强相关,数据量越大,扫描时间越久。
相关性排序
除了慢,传统数据库无法计算查询词与存储字段的相关性,数据库只保证查的出来,不保证查的相关性够强。
倒排索引
搜索引擎利用倒排索引解决上述问题。
倒排索引的本质上就是:term -> posting list 的映射。
如何构建倒排索引呢?
分词 + 索引
分词
搜索引擎中提供分词器 Analyzer,用于数据在写入倒排或者查询倒排时将内容切分成 term,成为倒排索引中的 key:term。
eg:有如下文本:小米手机, 为发烧而生,经过 Analyzer 处理后会得到:
小米/手机/为/发烧/而生
常用的中文分词器有:ik,jieba 等。
一般都有以下几部分组成:
- 首先对文本进行预处理:字符过滤,去除特殊字符;
- 其次根据分词词典切分 term;
- 最后进行大小写转换、根据停用词词典去除停用词、根据相似词词典扩展同义词、近似词。
索引
根据切分的 term 和对应的 doc 构建倒排索引,比如:
1 | term: 小米 -> posting list: doc(小米手机, 为发烧而生) |
那么在搜索 小米手机 的时候,关键词 小米手机 被拆分为 小米、手机 ,然后搜索引擎读取两个 term 的倒排列表,取出 term 对应的 doc 合并就得到相关的结果。
ES 中的倒排索引
ElasticSearch 使用 Lucene 全文检索库构建倒排索引。
在 Lucene 中:
- term 设计为 FST(有限状态转换器)的数据结构;
- posting list 通过 FOR 和 位图等压缩技术,压缩比极高。
Reference
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Comment
