第02章-倒排索引与分词
# 一、倒排索引
# 1.1 倒排索引定义
正排索引:文档ld到文档内容、单词的关联关系
倒排索引:单词到文档Id的关联关系
查询包含“搜索引擎”的文档步骤:
- 通过倒排索引获得
搜索引擎
对应的文档id有1和3 - 通过正排索引查询1和3的完整内容
- 返回用户最终结果
# 1.2 倒排索引组成
倒排索引是搜索引擎的核心,主要包含两部分,单词词典 和 倒排列表
1. 单词词典(Term Dictionary):是记录倒排索引的重要组成
- 记录所有文档的单词,一般都比较大
- 记录单词到倒排列表的关联信息
单词字典的实现一般是用 B+Tree,下图排序采用拼音实现
2. 倒排列表(Posting List) :记录了单词对应的文档集合,由 倒排索引项(Posting) 组成
倒排索引项主要包含如下信息:
- 文档 id:用于获取原始信息
- 单词频率(TF,Term Frequency):记录该单词在该文档中的出现次数,用于后续相关性算分
- 位置(Position):记录单词在文档中的分词位置(多个),用于做词语搜索(Phrase Query)
- 偏移(Offset):记录单词在文档的开始和结束位置,用于做高亮显示
以关键词 搜索引擎
为例,倒排列表构建如下图:
单词词典对应倒排列表,每一个单词对应一个倒排索引项。单词字典与倒排列表整合在一起的结构如下:
es存储的是一个json格式的文档,其中包含多个字段,每个字段会有自己的倒排索引,类似下图:
# 二、分词
# 2.1 分词和分词器
分词 是指将文本转换成一系列单词的过程,也可以叫做文本分析,在 es 里面称为 Analysis
分词器 是 es 中专门处理分词的组件,英文为 Analyzer,它的组成如下:
- Character Filters:针对原始文本进行处理,比如去除 html 特殊标记符
- Tokenizer:将原始文本按照一定规则切分为单词
- Token Filters:针对 tokenizer 处理的单词就行再加工,比如转小写、删除或新增等处理
分词器调用顺序如下图:
# 2.2 分词验证
es 提供了一个测试分词的接口 _analyze
,方便验证分词效果
可以直接指定分词器进行测试
可以直接指定索引中的字段进行测试
可以自定义分词器进行测试
# 2.3 ES 内置分词器
ES 内置分词器有:Standard, Simple, Whitespace, Stop, Keyword, Pattern, Language
1、Standard Analyzer
默认分词器
- 按词切分,支持多语言
- 小写处理
2、Simple Analyzer
- 按照非字母切分
- 小写处理
3、Whitespace Analyzer
- 按空格切分
4、Stop Analyzer
Stop Word 指语气助词等修饰性的词语,比如the、an、的、这等等
- 相比Simple Analyzer多了Stop Word处理
5、Keyword Analyzer
- 不分词,直接将输入作为一个单词输出
6、Pattern Analyzer
- 通过正则表达式自定义分割符
- 默认是
\W+
,即非字词的符号作为分隔符
7、Language Analyzer
- 提供了30+常见语言的分词器
# 2.4 中文分词器
常用分词系统
IK分词器
- 实现中英文单词的切分,支持 ik_smart、ik_maxword 等模式
- 可自定义词库,支持热更新分词词典
- https://github.com/medcl/elasticsearch-analysis-ik
jieba
- python 中最流行的分词系统,支持分词和词性标注
- 支持繁体分词、自定义词典、并行分词等
- https://github.com/sing1ee/elasticsearch-jieba-plugin
自然语言分词器
Hanlp
- 由一系列模型与算法组成的 Java 工具包,目标是普及自然语言处理在生产环境中的应用
- https://github.com/hankcs/HanLP
THULAC
- THU Lexical Analyzer for Chinese,由清华大学自然语言处理与社会人文计算实验室研制推出的一套中文词法分析工具包,具有中文分词和词性标注功能
- https://github.com/microbun/elasticsearch-thulac-plugin
# 2.5 分词器组成
当自带的分词无法满足需求时,可以自定义分词,通过自定义 Character Filters、 Tokenizer 和 Token Filters 实现
# 2.5.1 Character Filters
- 在 Tokenizer 之前对原始文本进行处理,比如增加、删除或替换字符等
- 自带的如下:
- HTML Strip:去除 html 标签和转换 html 实体
- Mapping:进行字符替换操作
- Pattern Replace:进行正则匹配替换
- 会影响后续 tokenizer 解析的 position 和 offset 信息
# 2.5.2 Tokenizer
将原始文本按照一定规则切分为单词(term or token),自带的如下:
- standard:按照单词进行分割
- letter:按照非字符类进行分割
- whitespace:按照空格进行分割
- UAX URL Email:按照 standard 分割,但不会分割邮箱和 url
- NGram 和 Edge NGram:连词分割
- Path Hierarchy:按照文件路径进行切割
# 2.5.3 Token Filters
对于 tokenizer 输出的单词(term)进行增加、删除、修改等操作,自带的如下:
- lowercase:将所有 term 转换为小写
- stop:删除 stop words
- NGram 和 Edge NGram:连词分割
- Synonym:添加近义词的 term
# 2.6 自定义分词
自定义分词需要在索引的配置中设定,如下所示:
自定义分词器 一
自定义分词 my_custom_analyzer 如下:
测试结果:
自定义分词器 二
这里使用将分词器的三个组成部分都进行了自定义
测试结果:
# 2.7 分词使用说明
分词有以下两个使用时机
索引时分词(Index Time)
创建或更新文档时,会对相应的文档进行分词处理。索引时分词是通过配置 Index Mapping 中每个字段的 analyzer 属性实现的,不指定分词时,使用默认 standard
查询时分词(Search Time)
指定查询时的分词器,对查询语句进行分词。指定方式有如下几种:
- 查询的时候通过 analyzer 指定分词器(仅本次查询有效)
- 通过 index mapping 设置 search analyzer 实现(创建索引时指定索引分词器和查询语句分词器)
一般不需要特别指定查询时分词器,直接使用索引时分词器即可,否则会出现无法匹配的情况。
另外还需要明确字段是否需要分词,不需要分词的字段就将 type 设置为 keyword,可以节省空间和提高写性能。