ElasticSearch 倒排索引与分词详细说明

一、正排索引与倒排索引

正排索引:文档 Id 到文档内容、单词的关联关系
倒排索引:单词到文档 Id 的关联关系

根据以上数据,假设我们现在要查询包含 “搜索引擎” 的文档,具体的查询流程如下:

  1. 通过倒排索引获得 “搜索引擎” 对应的文档 Id 有 1 和 3
  2. 通过正排索引查询 1 和 3 的完整内容
  3. 返回用户最终结果
二、倒排索引

倒排索引是搜索引擎的核心,主要包含两部分:

1、单词词典(Term Dictionary):是倒排索引的重要组成,记录所有文档的单词,一般都比较大,记录单词到倒排列表的关联信息。

单词词典一般用 B+Trees 来实现:

2、倒排列表(Posting List):记录了单词对应的文档集合,由倒排索引项组成。

倒排索引项主要包含以下信息:
1)文档 ID,用来获取原始信息
2)单词频率(TF:Term Frequency),记录该单词在该文档中的出现次数,用于后续相关性算分
3)位置(Position),记录单词在文档中的分词位置(多个),用于做词语搜索
4)偏移(Offset),记录单词在文档的开始位置和结束位置,用于做高亮显示

以【搜索引擎】为例,我们来看一下倒排列表:

最后,单词字段和倒排列表整合在一起的结构如下(只列出了 docId):

另外,es 存储的是一个 json 格式的文档,其中包含多个字段,每个字段都会有自己的倒排索引:

{
	"username":"seina gao",
	"refuse_reason":"I can't agree"
}
三、分词

分词是指将文本转换成一系列单词的过程,也可以叫做文本分析,在 es 里面成为 Analysis,比如文本是【elasticsearch 是最流行的搜索引擎】,分词结果是【elasticsearch、流行、搜索引擎】

1 分词器

分词器是 es 中专门处理分词的组建,英文为 Analyzer,它的组成如下:

1) Character Filters:针对原始文本进行处理,比如去除 html 特殊标记符,自带的如下:

  • HTML Strip 去除 html 标签和转换 html 实体
  • Mapping 进行字符替换操作
  • Pattern Replace 进行正则匹配替换

示例:

POST _analyze
{
	"tokenizer":"keyword",
	"char_filter":["html_strip"],
	"text":"<p>I&appos;m so <b>happy</b>!</p>"
}

// 得到 I‘m so happy!

2)Tokenizer:将原始文本按照一定规则切分为单词,自带的如下:

  • standard 按照单词进行分割
  • letter 按照非字符类进行分割
  • whitespace 按照空格进行分割
  • UAX URL Email 按照 standard 分割,但不会分割邮箱和 url
  • NGram 和 Edge NGram 连词分割
  • Path Hierachy 按照文件路径进行分割

示例:

POST _analyze
{
	"tokenizer":"path_hierarchy",
	"text":"/one/two/three"
}

// 得到 /one、 /one/two、 /one/two/three

3) Token Filters:针对 tokenizer 处理的单词进行再加工,比如转小写、删除或新增等处理,自带的如下:

  • lowercase 将所有 term 转换为小写
  • stop 删除 stop words
  • NGram 和 Edge NGram 连词分割
  • Synonym 添加近义词的 term
// filter 可以有多个
POST _analyze
{
	"text":"a Hello world!",
	"tokenizer":"standard",
	"filter":[
	"stop", // 把 a 去掉了
	"lowercase",// 小写
	{
		"type":"ngram",
		"min_gram":"4",
		"max_gram":"4"
	}
	]
}

// 得到 hell、ello、worl、orld
2 分词器的调用顺序
3 Analyze API

es 提供了一个测试分词的 api 接口,方便验证分词效果,endpoint 是 _analyze:

  1. 可以直接指定 analyzer 进行测试
POST _analyze
{
	"analyzer":"standard",
	"text":"hello world"
}
  1. 可以直接指定索引中的字段进行测试
POST test_index_name/_analyze
{
	"filed":"username",
	"text":"hello world"
}
  1. 可以自定义分词器进行测试
POST _analyze
{
	"tokenizer":"standard",
	"filter":["lowercase"],
	"text":"hello world"
}
4 预定义的分词器

es 自带的分词器包括:
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+ 常见语言的分词器

5 中文分词(难点)

中文分词指的是将一个汉字序列切分成一个个单独的词。在英文中,单词之间是以空格作为自然分界符,汉语中词没有一个形式上的分界符。除此之外,上下文不同,分词结果也很迥异,比如交叉歧义问题,下面两种分词都很合理

  • 乒乓球拍/卖/完了
  • 乒乓球/拍卖/完了

常见的分词系统

  1. IK:实现中英文单词的切分,可自定义词库,支持热更新分词词典
  2. jieba:python 中最流行饿分词系统,支持分词和词性标注,支持繁体分词,自定义词典,并行分词
  3. Hanlp:由一系列模型与算法组成的 java 工具包,支持索引分词、繁体分词、简单匹配分词(极速模式)、基于 CRF 模型的分词、N- 最短路径分词等,实现了不少经典分词方法。目标是普及自然语言处理在生产环境中的应用

更多的中文分词了解请点击一篇文章总结语言处理中的分词问题

6 自定义分词器

当自带的分词无法满足需求时,可以自定义分词器,通过定义 Character Filters、Tokenizer、Token Filter 实现。自定义的分词需要在索引的配置中设定,示例如下所示:

// 自定义分词器
PUT test_index_name
{
	"settings":{ 
		"analysis":{
			"analyzer":{
				"my_customer_analyzer":{
					"type":"custome",
					"tokenizer":"standard",
					"char_filter":["html_strip"],
					"filter":["lowercase", "asciifolding"]
				}
			}
		}
	}
}

// 测试自定义分词器效果:
POST test_index/_analyze
{
	"analyzer":"my_custom_analyzer",
	"text":"Is this <b>a box</b>?"
}

// 得到 is、this、a、box
7 分词使用说明

分词会在如下两个时机使用:

  • 创建或者更新文档时,会对相应的文档进行分词处理
  • 查询时,会对查询语句进行分词

明确字段是否需要分词,不需要分词的字段就将 type 设置为 keyword,可以节省空间和提高写性能

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值