特别声明:本文整理自Elasticsearch实战
一书,具体详情可参考原书,本文仅做个人学习使用。
1、什么是分析
在文档被发送并加入索引之前,ES在其主体上进行了操作,让每个被分析字段经过一系列的处理步骤:
- 字符过滤:使用字符过滤器转变字符
- 文本切分为分词:将文本切分为单个或者多个分词
- 分词过滤:使用分词过滤器转变每个分词
- 分词索引:将这些分词存储到索引中
1.1 字符过滤
第一步就是字符过滤,这些过滤器将特定的字符序列转变为其他的字符序列。例如:可以将I & You
转变为I and you
1.2 切分为分词
在字符过滤之后,文本需要被分隔为可以操作的片段。分词是从文本片段生成的,可能会产生任意数量的分词。例如,在英文中,一个通用的分词是标准分词器。她根据空格、换行和破折号等其他字符将文本分割为分词。例如:i love you
分解为I
、love
、you
.
1.3 分词过滤器
文本被转换为分词后,ES将会对每个分词运用分词过滤器,这些分词过滤器可以将一个分词作为输入,然后根据需要进行修改,添加,删除。最为有用的和常用的分词过滤器是小写分词过滤器,他将输入的分词小写,确保在搜索词条nosql
的时候,可以返回NoSql
的结果。分词可以经过多个分词过滤器,每个分词过滤器进行不同的操作,将数据塑造成最佳的形式,便于后面索引使用。
1.4 分词索引
当分词经历过分词过滤器之后,他们将被发送到Lucene进行文档的索引。这些分词组成了倒排索引。
所有上述部分组成了一个分析器,他可以定义0个和多个字符过滤器,一个分词器,0个或多个分词过滤器。
2、 在文档上使用分析器
可以在映射中指定分析器使用哪个单独的分词器和分词过滤器,海鸥哪些字段使用哪些分析器,有以下两种方式指定字段使用的分析器
- 在创建索引的时候,为特定的索引设置
- 在ES配置文件中,设置全局的分析器
无论使用那种方式设置,需要在索引的映射中指定哪些字段使用哪些分析器,可以是在索引创建时设置映射,或者稍后使用put mapping API
进行设置。
2.1 创建索引时,指定
curl -XPOST 'localhost:9200/myindex' -d '{
"settings": {
"number_of_shards": 2, //主分片
"number_of_replicas": 1, // 副本分片
"index": {
"analysis": {
"analyzer":{
"myCustomAnalyzer":{
"type":"custom",
"tokenizer":"myCustomTokenizer",
"filter":["myCustomFilter1", "myCustomFilter2"],
"char_filter": ["myCustomCharFilter"]
}
},
"tokenizer":{
"myCustomTokenizer":{
"type":"letter"
}
},
"filter":{
"myCustomFilter1":{
"type":"lowercase"
},
"myCustomFilter2":{
"type":"kstem"
}
},
"char_filter":{
"myCustomCharFilter":{
"type":"mapping",
"mappings": ["ph=>f", "u=>you"]
}
}
}
}
},
"mappings":{
"messages":{
"properties":{
"title":{
"type": "string"
},
"summary": {
"type": "string"
},
"created_at": {
"type": "date",
"format": "dateOptionalTime"
}
}
}
}
}'
2.2 在配置文件中配置
在配置文件中配置,需要重启ES后才会生效,在改动很小时,这种方式更合适。
index:
analysis:
analyzer:
myCustomAnalyzer:
type: custom
tokenizer: myCustomTokenizer
filter: [myCustomFilter1, myCustomFilter2]
char_filter: myCustomCharFilter
tokenizer:
myCustomTokenizer:
type: letter
filter:
myCustomFilter1:
type: lowercase
myCustomFIlter2:
type: kstem
char_filter:
myCustomCharFilter:
type: mapping
mappings: ["pf=>f", "u =>you"]
2.3 在映射中指定某个字段的分析器
{
"mappings":{
"document":{
"properties":{
"content":{
"type": "string",
"analyzer": "myCustomAnalyzer"
}
}
}
}
}
通常,可以同时搜索字段分析后的文本和原始未经过分析的文本,这个是非常有价值的。可以像下面这样:
curl -XPOST 'localhost:9200/get-together' -d '{
"mappings":{
"events":{
"properties":{
"title":{
"type": "string",
"analyzer": "standard",
"fields": {
"raw": {
"index": "not_analyzed",
"type": "string"
}
}
}
}
}
}
}'
3、使用Api分析文本
当跟踪信息是如何在ES索引中存储的时候,使用分析API来测试分析的过程是很有用的。
curl -XPOST 'localhost:9200/_analyze?analyzer=standard' -d 'how to change you feeling & feel manager'
4、内置的分析器
一个分析器包括一个可选的字符过滤器,一个单个分词器,0个或1个分词过滤器。
4.1 分析器
4.1.1 标准分析器
当没有指定分析器时,标准分析器时默认的分析器。它综合了对大多欧洲语言来说合理的默认模块,包括标准分词器,标准分词过滤器,小写转换分词过滤器和停用词分词过滤器。如果不为某个字段指定分析器,那么该字段就会使用标准的分析器。
4.1.2 简单分析器
他只是用了小写转换分词器,对亚洲语言效果不佳
4.1.3 空白分析器
只根据空白将文本切分为若干分词
4.1.4 停用词分析器
和简单分析器相似,只是在分词六中额外的过滤了停用词。
4.1.5 关键词分析器
将整个字段当做一个单独的分词,特别注意,最好是将inex设置为not_analyzed,而不是在映射中设置使用关键词分析器
4.1.6 模式分析器
指定一个分词切分的模式
4.1.7 多语言分析器
支持直接使用的特定语言分析器
4.1.8 雪球分析器
除了使用标准的分词器和分词过滤器,也使用了小写分词过滤器和停用词过滤器。他还使用了雪球词干器对文本进行词干提取。
4.2 分词器
4.2.1 标准分词器
基于语法的分词器。对于大多数欧洲语言是不错的。分词默认的最大长度为255.移除了逗号和句号这样的标点符号。
4.2.2 关键词分词器
将整个文本作为单个的分词,提供给分词过滤器,只想应用分词过滤器,而不作任何分词操作时,有用。
4.2.3 字母分词器
根据非字母的符号。将文本切分为分词。比如I love you
,分词后为I
, love
, you
,因为空格不是字母。
4.2.4 小写分词器
结合了常规的字母分词器和小写分词过滤器的行为。通过一个单独的分词器来实现的主要原因是,一次进行两项操作会获取更好的性能。
4.2.5 空白分词器
通过空白分割不同的分词,空白包括空格,制表符,换行等。这种分词器不会删除任何标点符号。
4.2.6 模式分词器
指定一个任意的模式,将文本切分为分词。被指定的模式应该匹配间隔符号。
curl -XPOST 'localhost:9200/pattern' -d '{
"settings":{
"index":{
"analysis":{
"tokenizer":{
"pattern1":{
"type":"pattern",
"pattern":"\\.-\\."
}
}
}
}
}
}'
curl -XPOST 'localhost:9200/pattern/_analyze?tokernizer=pattern1' -d 'breadking.-.some.-.test'
4.2.7 电子邮件分词器
tokenizer=uax_url_email
4.2.8 路径层次分词器
一特定的方式索引文件系统的路径。tokenizer=path_hierarchy
4.3 分词过滤器
4.3.1 标准分词过滤器
什么事情也没做
4.3.2 小写分词过滤器
将任何经过的分词转换为小写
4.3.3 长度分词过滤器
将长度超过最短和最长限制范围的单词过滤掉,例如如果min:2,max=5,那么任何小于2个字符和任何大于5个字符的分词将会被移除。
4.3.4 停用词分词过滤器
将停用词从分词流中移除。
curl 'localhost:9200/stopwords' -d '{
"settings":{
"index":{
"analysis";{
"analyzer":{
"stop1":{
"type":"custom",
"tokenizer": "standard",
"filter":["mystopfilter"]
}
},
"fitler":{
"mystopfilter":{
"type": "stop",
"stopwords_path": "config/stopwords.txt"
}
}
}
}
}
}'
4.3.5 截断分词过滤器、修剪分词过滤器和限制分词数量的过滤器
- 截断: 配置length参数,截断超过长度的分词,默认length=10
- 修剪:删除一个分词中的所有空白部分
- 限制分词数量:限制某个字段可包含分词的最大数量
4.3.6 颠倒分词过滤器
处理分词流,并颠倒每个分词。如果使用侧边N元语法过滤器或者是进行前统配搜索,很有用。比如,*Tok
这样搜索的时候,性能很差,而 koT*
就快很多.
4.3.7 唯一分词过滤器
只保留唯一的分词。
4.3.8 ASCII折叠分词过滤器
将不是普通ASCII字符的Unicode字符转换为ASCII重等同的字符,前提是这种等同存在。
4.3.9 同义词分词过滤器
在分词流中的同样位移处,使用关键词的同义词取代原始分词。
5、 N元语法,侧边N元语法和滑动窗口
n元语法是将一个单词切分为多个子单词。N元语法和侧边N元语法过滤器允许指定min_gram
和max_gram
,这些设置控制单词背切分为分词的数量。 例如 单词spaghetti
,一元语法过滤器后,是s
,p
,a
,g
,h
,e
,s
,t
,i
.二元语法过滤器后是sp
,pa
,ag
,gh
,he
,et
,tt
,ti
.三元语法过滤器后是,spa
,pag
,agh
,ghe
,het
,ett
,tti
.
设置min_gram
,max_gram
,如果指定前者为2,后者为3.会将上面两个集合进行合并。
侧边N元语法过滤器是N元语法过滤器的变体。仅仅从前端的边缘开始构建N元语法。上面的例子,将获得分词sp
,spa
.可以看到,每个分词都是从最前端的边缘开始的,也可以使用side
属性,让边缘从后端开始,而不是默认的前端开始。
curl 'localhost:9200/ng' -d '{
"settings":{
"index":{
"analysis";{
"analyzer":{
"ng1":{
"type":"custom",
"tokenizer": "standard",
"filter":["reverse", "ngf1", "reverse"]
}
},
"fitler":{
"ngf1":{
"type": "edgeNgram",
"min_gram": 2,
"max_gram": 3
}
}
}
}
}
}'
滑动窗口分词过滤器和上面的过滤器使用了同样的方式。基本上是分词级别的N元语法。例如,I love you
.将min_shingle_size
=2 max_shingle_size
=3,将产生一下分词:I
,I love
,I love you
,love
,love you
,you
,因为默认情况下,滑动窗口过滤器包含了原始分词,所有原始的分词器会产生单个分词的结果。而滑动窗口产生的分词结果为I love
,I love you
,love you
.这个结果已合并就是最终的结果。你可以将output_unigrams:false
来关闭这种行为
6、 提取词干
提取词干是将单词缩减到基本或词根的形式,这意味着用户可以匹配单词的复数,以及有同样词根的单词。
6.1 算法提取词干
为每个分词使用公式或者一组规则来对其进行词干的获取。有三种算法snowball
/porter term
和kstem
过滤器,表现行为基本一致,区别是提取词干有多激进。
6.2 字典提取词干
可以使用hunspell
分词过滤器,结合一个词典,来处理词干。词干提取的质量和使用的字典的质量有关系。只能处理字典里存在的单词。在创建一个hunspell
分析器时,字典文件需要放置在名为hunspell
的目录里,而这个目录需要和elasticsearch.yml
处于同一个目录。