1. Analysis

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


2. Analyzer

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

5. 分词器_分词器


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



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. 分词器_分词器_02




4. 中文分词器

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

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


4.1 问题

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

5. 分词器_elasticsearch_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. 分词器_elasticsearch_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. 分词器_analyzer_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. 分词器_elasticsearch_14



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

file -i my.dic


5. 分词器_elasticsearch_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. 分词器_elasticsearch_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. 分词器_elasticsearch_18



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

5. 分词器_analyzer_19



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

5. 分词器_analyzer_20



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

5. 分词器_elasticsearch_21