1. Analysis

Analysis,译为“分析”,在es中指的是对文本(text)的分析,所谓文本分析就是把一段文本转换为一系列单词(term/token)的过程,也叫分词。Analysis是通过Analyzer来实现的。

2. Analyzer

分析器(analyzer)都由三部分组成的:character filters, tokenizers , token filters

5. 分词器_analyzer

我们可以看出,存入文档数据时,检索文档数据时,都会用到分词器!

3. 内置分词器

 https://www.elastic.co/guide/en/elasticsearch/reference/7.x/analysis-tokenizers.html

3.1 Standard Analyzer

The standard tokenizer provides grammar based tokenization (based on the Unicode Text Segmentation algorithm, as specified in  Unicode Standard Annex #29) and works well for most languages.

POST _analyze

{

"tokenizer": "standard",

"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."

}

[ The, 2, QUICK, Brown, Foxes, jumped, over, the, lazy, dog's, bone ]

3.2 Letter tokenizer

The letter tokenizer breaks text into terms whenever it encounters a character which is not a letter. It does a reasonable job for most European languages, but does a terrible job for some Asian languages, where words are not separated by spaces.

POST _analyze

{

"tokenizer": "letter",

"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."

}

[ The, QUICK, Brown, Foxes, jumped, over, the, lazy, dog, s, bone ]

3.3 Simple Analyzer

按照非字母切分,非字母则会被去除,英文大写转小写

GET _analyze

{

"analyzer": "simple",

"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."

}

[the,quick,brown,foxes,jumped,over,the,lazy,dog,s,bone]

3.4 Stop Analyzer

停用词过滤(the,a, an, is),按照非字母切分,非字母则会被去除

GET _analyze

{

"analyzer": "stop",

"text": "The 2 a is 3 QUICK Brown-Foxes jumped over the lazy dog's bone."

}

[quick,brown,foxes,jumped,over,lazy,dog,s,bone]

3.5 Whitespace Analyzer

按空格切分,英文不区分大小写,中文不分词

GET _analyze

{

"analyzer": "whitespace",

"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."

}

[The,2,QUICK,Brown-Foxes,jumped,over,the,lazy,dog's,bone.]

3.6 Keyword Analyzer

不分词,当成一整个 term 输出

GET _analyze

{

"analyzer": "keyword",

"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone."

}

[The 2 QUICK Brown-Foxes jumped over the lazy dog's bone.]

3.8 多分词器

在es默认创建索引时(比如添加文档的同时,就创建不存在的索引),其中的text类型的字段,总会自动再创建出keyword类型的索引。比如在bank中的address和address.keyword。

当我们自己手动创建索引的时候,把一个字段定成什么类型,那就只有什么类型,不会额外生产什么keyword类型的索引的。

当然,我们也可以自己指定索引中的一个字段同时建立多个不同的索引,这多个不同的索引可以使用不同的类型和分词器,如下:

DELETE foo

PUT foo

{

"mappings": {

"properties": {

"name": {

"type": "keyword"

},

"addr": {

"type": "text",

"analyzer": "standard",

"search_analyzer": "standard",

"fields": {

"sd": {

"type": "text",

"analyzer": "standard"

},

"kw": {

"type": "keyword"

}

}

}

}

}

}

PUT foo/_doc/1

{

刘德华",

中国陕西省西安市"

}

GET foo/_search

{

"query": {

"match": {

中国陕西省"

}

}

}

5. 分词器_elasticsearch_02

4. 中文分词器

汉语中,句子是单词的组合。除标点符号外,汉语词语之间不存在分隔符。这就给中文分词带来了挑战。

比如,“首饰和服装”,“苹果不大好吃”。幸运的是,无论中文分词是有多么的复杂,与我们都没有关系,我们直接使用中文分词器即可。

4.1 问题

当我们在kibana中,发起如下请求时,会发现es对中文处理得很简单:

5. 分词器_analyzer_03

4.2 解决

为了让es能更好地处理中文,我们需要下载es的ik分词器插件,下载地址如下:

 https://github.com/medcl/elasticsearch-analysis-ik/releases

特别注意,下载的ik分词器的版本,必须与你所安装的es的版本一致!比如目前我安装的es版本是7.10.2,那么下载的ik分词器的版本也必须是7.10.2

5. 分词器_分词器_04

切换到root用户,将ik分词器插件上传给linux,上传目录为:/home/elk/elasticsearch-7.10.2/plugins

rz -y

然后在/home/elk/elasticsearch-7.10.2/plugins目录中,再创建一个ik目录,注意目录的名字必须是ik

mkdir ik

将ik分词器考入到ik目录中:

mv elasticsearch-analysis-ik-7.10.2.zip ik/

进入ik目录,解压ik分词器文件

unzip elasticsearch-analysis-ik-7.10.2.zip

5. 分词器_elasticsearch_05

记得将ik分词器的拥有者改为elk用户:

chown -R elk ik

否则在启动es服务的时候,总是会显示这个错误:java.io.FileNotFoundException: /usr/es/logs/my-application.log (权限不够)

然后以elk用户,重启es,再此进行测试,此时就可以使用ik_smart和ik_max_word分词器了!

5. 分词器_elasticsearch_06

ik_smart和ik_max_word,这两个分词器的区别就是分词粒度不同:

5. 分词器_analyzer_07

5. 分词器_elasticsearch_08

5. 指定查询分词器

指定查询分词器的时机,有三个:

1. 访问_anaylze时,通过请求体中的参数analyzer指定

2. 定义索引时,通过mapping指定

3. 检索文档时,通过request body指定

在访问_analyze时,通过

GET _analyze

{

"analyzer": "ik_max_word",

好好学习天天向上"

}

创建索引时,在mapping中指定分词器

DELETE foo

PUT foo

{

"mappings": {

"properties": {

"name": {

"type": "keyword"

},

"addr": {

"type": "text",

"analyzer": "ik_max_word",

"search_analyzer": "ik_max_word"

}

}

}

}

PUT foo/_doc/1

{

刘德华",

西安"

}

再观察一下不同分词器的效果:

GET _analyze { "analyzer": "ik_smart", "text": "西安市" }

5. 分词器_analyzer_09

GET _analyze { "analyzer": "ik_max_word", "text": "西安市" }

5. 分词器_elasticsearch_10

查询时,在request body中指定分词器

5. 分词器_elasticsearch_11

5. 分词器_elasticsearch_12

无结果

有结果

6. 设置索引的默认分词器

es默认的分词器是standard,我们在创建索引时,指定当前索引的默认分词器

delete foo

PUT foo

{

"settings" : {

"index" : {

"analysis.analyzer.default.type": "ik_max_word"

}

}

}

7. 配置词典

7.1 问题

当我们输入一些特有的中文名词,尤其是一些网络用语时,ik分词器也会将这些特有的中文名词分隔

我们以“小星辰”为例,我们想让ik分词器把“小星辰”当做一个整体的词语来对待,但结果却不是这样:

5. 分词器_elasticsearch_13

7.2 配置本地词典

以root用户,进入ik分词器的配置文件夹中:/home/elk/elasticsearch-7.10.2/plugins/ik/config,创建my.dic

touch my.dic

在my.dic中,写入“小星辰”

5. 分词器_分词器_14

确保my.dic文件的编码为:utf-8

file -i my.dic

5. 分词器_分词器_15

然后修改 IKAnalyzer.cfg.xml,配置好自己创建的my.dic

<?xml versinotallow="1.0" encoding="UTF-8"?>

<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">

<properties>

扩展配置</comment>

用户可以在这里配置自己的扩展字典 -->

<entry key="ext_dict">my.dic</entry>

用户可以在这里配置自己的扩展停用词字典-->

<entry key="ext_stopwords"></entry>

用户可以在这里配置远程扩展字典 -->

<!-- <entry key="remote_ext_dict">words_location</entry> -->

用户可以在这里配置远程扩展停止词字典-->

<!-- <entry key="remote_ext_stopwords">words_location</entry> -->

</properties>

以elk,重启es,再次测试

5. 分词器_elasticsearch_16

我们发现,“小星辰”这个词,已经被当做一个完整的词了。

7.3 配置远程词典

使用IK分词器,对网络词汇“洛天依 ”进行分词

GET _analyze

{

"analyzer": "ik_max_word",

洛天依"

}

并没有把“洛天依”当成一个完整的词

["洛", "天" ,"依"]

在tomcat中,发布一个web应用,在该web应用中,发布一个文件:words.dic,内容如下:

5. 分词器_分词器_17

如果有多个词的话,则一个词占一行

访问地址为:

 http://192.168.1.100:8080/mydic/words.dic

修改ik分词器的配置:IKAnalyzer.cfg.xml

<?xml versinotallow="1.0" encoding="UTF-8"?>

<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">

<properties>

扩展配置</comment>

<entry key="ext_dict"></entry>

<entry key="ext_stopwords"></entry>

<entry key="remote_ext_dict">http://192.168.1.100:8080/mydic/words.dic</entry>

<!-- <entry key="remote_ext_stopwords">words_location</entry> -->

</properties>

以elk用户,重启es,然后再次进行测试

5. 分词器_analyzer_18

我们发现,洛天依被当做一个词汇了。配置远程词典的方式,还支持热更新,比如,我们使用IK分词器对网络词语:“乔碧萝”进行分词:

5. 分词器_分词器_19

发现,IK分词器并没有把“乔碧萝”当做一个词,此时我们修改tomcat下的words.dic文件:

5. 分词器_分词器_20

不用重启es,但是要稍等一下,我们再次测试:

5. 分词器_分词器_21