ElasticSearch核心之——分词
前言
我们知道ElasticSearch(简称ES)底层的搜索使用的是倒排索引依赖于分词器的实现,那么分词器的规则可以如何制定、ES中都提供了哪些常用的分词器给我们去使用呢?本文将围绕分词器的使用和细节进行讲解,希望能够对想要了解ES分词器的小伙伴们一个参考。
一、说在前面的概念
(一)分词
分词是将文本转换成一系列单词的过程,也可以叫做文本分析,在ES中被称为Analysis。其实在日常生活中,分词这个概念我们应该并不陌生,比如我们使用百度/谷歌搜索引擎进行检索的时候,我们常常可以发现,我们输入的一段句子会被分割成不同的关键词关联查询。
以“windows打开控制面板命令”为例子,我们在百度中进行搜索,会发现它被分割为windows
、控制面板
、命令
等关键字来查询。
(二)分词器
对语句进行分词的前提是定义了分词的规则。ES中为我们提供了许多功能强大、场景丰富的分词器组件,英文是Analyzer,它的组成如下:
- Character Filter
-针对原始的文本进行处理,比如去除html标记 - Tokenizer
-将原始的文本按照一定的规则切分为单词 - Token Filter
-针对tokenizer处理的单词进行再加工,比如转小写、删除或新增等处理
我们可以看到分词器可以由三种组件组成,原始的数据流从Character Filter -> Tokenizer -> Token Filter一路下来,可以一步步地去除多余的数据再进去分割存储(输出)。
二、分词器的API
(一)简单的使用分词器
ES给我们提供了一个测试分词的API接口,方便验证分词效果,在这个API中我们可以指定使用的分词器和索引来源,还可以使用自定义的分词器进行查看。
POST _analyze
{
"analyzer": "standard",
"text": [
"hello es"
]
}
执行后结果如下:
上面的例子中,我们使用的是默认的分词器,我们也可以自定义分词器来进行使用
POST _analyze
{
"tokenizer": "standard",
"filter": ["lowercase"],
"text": ["Hello World ElasticSearch"]
}
(二)ES中自带的分词器
1. Standard 标准分词器
Standard是ES的默认分词器,具备按词切分、支持多语言;小写处理等特点。其具体组成如下图:
POST _analyze
{
"analyzer": "standard",
"text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}
2. Simple Analyzer 简单分词器
简单分词器有着按照非字母切分、小写处理的特点,其具体组成如下图:
POST _analyze
{
"analyzer": "simple",
"text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}
3. Whitespace Analyzer 空格分词器
这个分词器很好理解,就是将文本根据空格进行分词。其组成如下图
POST _analyze
{
"analyzer": "whitespace",
"text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}
4. Stop Analyzer 语气助词分词器
Stop Word
指的是语气助词等修饰性的词语,比如the
、an
、的
、这
等等,其组成如下图:
POST _analyze
{
"analyzer": "stop",
"text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}
5. Keyword Analyzer 关键字分词器
Keyword分词器是一个比较特殊的存在,它不会对输入的句子进行分词,而是直接将输入作为一个单词输出,也就是说会将输入看成是一个整体。其组成如下:
POST _analyze
{
"analyzer": "keyword",
"text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}
6. Pattern Analyzer 正则分词器
正则分词器很好理解,就是根据我们提供的正则表达式来进行分词,默认会按照 \W+
,即非字词的符号作为分隔符。其组成如下:
POST _analyze
{
"analyzer": "pattern",
"text": ["The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."]
}
7. Langueage Analyzer 多语言分词器
多语言分词器提供了30+种常见语言的分词器
诸如:arabic
, armenian
, basque
, bengali
, brazilian
, bulgarian
, catalan
, cjk
, czech
, danish
, dutch
, english
, estonian
, finnish
, french
, galician
, german
, greek
, hindi
, hungarian
, indonesian
, irish
, italian
, latvian
, lithuanian
, norwegian
, persian
, portuguese
, romanian
, russian
, sorani
, spanish
, swedish
, turkish
, thai
.
(详细用法可点击具体的语言,通过超链接进入es官网查看)
(三)中文分词器
上述的分词都是基于英文来进行分词的,对于中文而言,并不能完全适用。中文分词是指将一个汉字序列切分成一个个单独的词,在英文中,单词之间是通过空格作为自然分隔符,汉字中没有一个形式上的分词符。
同时,汉字中存在着一词多义,一词多性(可做动词也可做名词),比如:"乒乓 / 球拍 / 卖完了" 和“乒乓球 / 拍卖 / 完了”。同样的一句话可以有多种分词方式,所以中文分词的难度较大,往往需要自己根据实际情况进行定义。常用的中文分词器有 ik分词器
和 jieba
分词器。
IK分词器
IK分词器可以实现中英文单词的切分,支持ik_smart、ik_maxword等模式,可以自定义词库和支持热更新分词词典。其插件下载地址为:
https://github.com/medcl/elasticsearch-analysis-ikjieba 分词器
jieba分词器是Python中最流行的分词系统,支持分词和词性标注,支持繁体分词和自定义词典、并行分词等,下载地址为:
https://github.com/sing1ee/elasticsearch-jieba-pluginHanlp 分词器
由一系列模型与算法组成的Java工具包,目标是普及自然语言处理在生产环境中的应用,其下载地址为:https://github.com/hankcs/HanLPTHULAC 分词器
THU Lexical Analyzer for Chinese,由清华大学自然语言处理与社会人文计算实验室研制推出的一套中文词法分析工具包,具有中文分词和词性标注功能,下载地址为:
https://github.com/microbun/elasticsearch-thulac-plugin
三、自定义分词器
当ES提供的分词器不能满足我们的分词需要的时候,我们可以通过自定义分词器来满足我们的工作需要,下面我们就从ES分词器的各个组件来进行自定义分词的测试吧。
(一)Character Filter 字符过滤器
我们知道最先到达分词器的组件是Character Filter,他会在 Tokenizer 之前对文本进行处理,比如增加、删除、或替换字符等。
ES中自带的Character Filter有HTML Strip
(去除html标签和转换html实体)、Mapping
(进行字符替换等操作)、Pattern Replace
(进行正则字符替换)。
POST _analyze
{
"tokenizer": "keyword",
"char_filter": ["html_strip"],
"text": ["<p>I'm so <b>happy</b>!</p>"]
}
(二)Tokenizer 字符切分者
Tokenizer会将原始文本(此处是指已经经过char_filter处理过的文本)按照一定的规则切分为单词,自带的Tokenizer如下:
Tokenizer | 功能 |
---|---|
standard | 按照单词进行分割 |
letter | 按照非字符类进行分割 |
whitespace | 按照空格进行分割 |
UAX URL Email | 按照standard分割,但不会分割邮箱和url |
NGram和Edge NGram | 连词分割 |
Path Hierarchy | 按照文件路径进行切割 |
POST _analyze
{
"tokenizer": "uax_url_email",
"text": ["his email is 123123@123.com"]
}
(三)Token Filter
Token Filter会对 tokenizer输出的单词(term)进行增加、删除和修改等操作
自带的Token Filter如下:
token filter | 功能 |
---|---|
lowercase | 将所有的term转换为小写 |
stop | 删除stop words |
NGram和Edge NGram | 连词分割 |
Synonym | 添加近义词的term |
POST _analyze
{
"tokenizer": "standard",
"text": ["a Hello,Word!"],
"filter": [
"stop",
"lowercase",
{
"type": "ngram",
"min_gram": 3,
"max_gram": 4
}
]
}
(四)自定义分词的API
通过上面的介绍,我们可以知道分词器的三个组件的使用方法,下面我们就来学习一下如何定义一个自己的分词器吧。
分词器的使用需要在索引的配置中设定,如下所示:
PUT index_test
{
"settings": {
"analysis": {
"char_filter": {},
"tokenizer": {},
"filter": {},
"analyzer": {}
}
}
}
比如我们要自定义这样结构的一个分词器:
具体的定义语句如下:
PUT index_test
{
"settings": {
"analysis": {
"analyzer": {
"my_custom_analyzer": {
"type": "custom",
"char_filter": ["html_strip"],
"tokenizer": "standard",
"filter": [
"lowercase",
"asciifolding"
]
}
}
}
}
}
我们再来举一个例子:
想要定义这样一个分词器,我们的建分词器语句为:
PUT /index_test
{
"settings": {
"analysis": {
"analyzer": {
"my_coustom_analyzer": {
"type": "custom",
"char_filter": [
"emoticons"
],
"tokenizer": "punctuation",
"filter": [
"lowercase",
"english_stop"
]
}
},
"tokenizer": {
"punctuation": {
"type": "pattern",
"pattern": "[ .!,?]"
}
},
"char_filter": {
"emoticons": {
"type": "mapping",
"mappings": [
":) => _happy_",
":( => _sad_"
]
}
},
"filter": {
"english_stop": {
"type": "stop",
"stopwords": "_english_"
}
}
}
}
}
四、分词的使用说明
对于ES分词的使用,一共有两个时机,一个是创建文档和更新文档(Index time)时,会对相应的文档进行分词处理;第二是查询时,会对查询语句进行分词。
- 索引时分词
索引时分词是通过配置Index Mapping 中每个字段的analyzer属性实现的
PUT /index_test
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "standard" # 为字段指定analyzer
}
}
}
}
- 查询时分词
查询时分词可以有两种形式,分别是查询的时候通过analyzer指定分词器以及通过index mapping设置search_analyzer实现
我们可以发现,在创建index的时候也可以定义查询时分词,一般来说,如果在创建索引的时候定义了查询时使用的分词器,那么我们在执行查询的过程中,也是要使用相同的分词器,否则会出现无法匹配的情况!!!
五、使用分词的建议
1、明确字段是否需要分词,不需要分词的字段就将type设置为keyword,可以节省空间和提高写性能
2、对于不太清楚的分词效果,可以自己动手调试或者查看一下官方文档,个人觉得官方文档还是写的比较全面的。
官方文档链接如下:
https://www.elastic.co/guide/en/elasticsearch/reference/7.x/analysis-index-search-time.html(自己根据实际版本看对应的文档)