笔记源自 : Elastic 中国社区官方博客
前言
什么是 analysis?
Elasticsearch 在文档发送之前对文档正文执行的过程,以添加到反向索引中(inverted index)。 在将文档添加到索引之前,Elasticsearch 会为每个分析的字段执行许多步骤:
- Character filtering (字符过滤器): 使用字符过滤器转换字符
- Breaking text into tokens (把文字转化为标记): 将文本分成一组一个或多个标记
- Token filtering:使用标记过滤器转换每个标记
- Token indexing:把这些标记存于索引中
如下例子,显示了 “share your experience with NoSql & big data technologies" 为分析的标记:share, your, experience, with, nosql, big, data,tools 及 technologies。
所展示的是一个由 character 过滤器,标准的 tokenizer 及 Token filter 组成的定制 analyzer。所展示的是一个由 character 过滤器,标准的 tokenizer 及 Token filter 组成的定制 analyzer。简洁地描述一个 analyzer 的基本组成部分,以及每个部分所需要表述的东西。
每当一个文档被 ingest 节点纳入,它需要经历如下的步骤,才能最终把文档写入到 Elasticsearch的 数据库中:
上面中间的那部分就叫做 analyzer,即分析器。它有三个部分组成:Char Filters, Tokenizer 及 Token Filter。它们的作用分别如下:
- Char Filter: 字符过滤器的工作是执行清除任务,例如剥离 HTML 标记,还有上面的把 “&” 转换为 “and” 字符串
- Tokenizer: 下一步是将文本拆分为称为标记的术语。 这是由 tokenizer 完成的。 可以基 于任何规则(例如空格)来完成拆分。 有关 tokenizer 的更多详细信息,请访问以下 URL:https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis- tokenizers.html。
- Token filter: 一旦创建了 token,它们就会被传递给 token filter,这些过滤器会对 token 进行规范化。 Token filter 可以更改 token,删除术语或向 token 添加术语。
一个 analyzer 有且只有一个 tokenizer,有0个或一个以上的 char filter 及 token filter。
Elasticsearch 已经提供了比较丰富的开箱即用 analyzer。我们可以自己创建自己的 token analyzer,甚至可以利用已经有的 char filter,tokenizer 及 token filter 来重新组合成一个新的 analyzer,并可以对文档中的每一个字段分别定义自己的 analyzer。如果大家对 analyzer 比较感兴趣的话, 请参阅网址
在默认的情况下,standard analyzer 是 Elasticsearch 的缺省分析器:
- 没有 Char Filter
- 使用 standard tokonizer
- 把字符串变为小写,同时有选择地删除一些 stop words 等。默认的情况下 stop words 为 none,也即不过滤任何 stop words。
下图说明了不同的分析器如何拆分 token 以及有多少 token 它们为相同的文本流生成的标记:
针对英文或其它西方文字 stemming filter。它的意思是找出相应词的词源:
Apps 的词源是 app。如下的 english analyzer 调用将使用 stemmer 过虑器从而返回这些词的词源,使用 _analyze API 来测试 analyzer 如何解析我们的字符串的,比如::
GET _analyze
{
"analyzer": "english",
"text": "Running Apps in a Phone"
}
将返回如下的结果:
{
"tokens" : [
{
"token" : "run",
"start_offset" : 0,
"end_offset" : 7,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "app",
"start_offset" : 8,
"end_offset" : 12,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "phone",
"start_offset" : 18,
"end_offset" : 23,
"type" : "<ALPHANUM>",
"position" : 4
}
]
}
Running ===> run ; Apps ===> app
设置分词器
在创建索引的时候,手动设置Mapping ,为属性指定分词器
PUT multifield
{
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "standard",
"fields": {
"english": {
"type": "text",
"analyzer": "english"
}
}
}
}
}
}
使用 :
插入数据
PUT multifield/_doc/1
{
"content": "We are excited to introduce the world to X-Pack"
}
搜索:
GET /multifield/_search
{
"query": {
"match": {
"content": "the"
}
}
}
结果 :
"hits" : [
{
"_index" : "multifield",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"content" : "We are excited to introduce the world to X-Pack"
}
}
]
但是如果我们使用如下的方法:
GET /multifield/_search
{
"query": {
"match": {
"content.english": "the"
}
}
}
我们啥也看不到,这是因为 “the” 在 english analyzer 里 “the” 被认为是 stop word,而被忽略。
定制的分析器
GET _analyze
{
"text": "I am so excited to go to the x-game",
"analyzer": "standard"
}
可以看到这样的结果:x-game 在这里被分为两个 token:x 及 game。如果我们想把 x-game 当做一个该怎么办呢?我们可以通过设置特有的 mapping 来实现。
比如我们有一个叫做 blog 的索引:
PUT blogs
{
"settings": {
"analysis": {
"char_filter": {
"xgame_filter": {
"type": "mapping",
"mappings": [
"X-Game => XGame"
]
}
},
"analyzer": {
"my_content_analyzer": {
"type": "custom",
"char_filter": [
"xgame_filter"
],
"tokenizer": "standard",
"filter": [
"lowercase"
]
}
}
}
},
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "my_content_analyzer"
}
}
}
}
定义了一个称之为 xgame_filter 的 char_filter,它可以帮我们把 “x-game” 转化为 “XGame”。紧接着,我们利用 xgame_filter 定义了一个叫做 “my_content_analyzer”。它是一个定制的类型。我们定义它的char_filter, tokenizer 及 filter。现在我们可以利用我们刚才定义 my_content_analyzer 来分析我们的字符串。
在 mappings 里可以看到:
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "my_content_analyzer"
}
}
}
通过如下的方法来测试它是否工作:
POST blogs/_analyze
{
"text": "I am so excited to go to the X-Game",
"analyzer": "my_content_analyzer"
}
可以看到 “xgame” 这个 token。
从上面的返回的结果来看,我们还是可以看到 “the”,“to” 这样的 token。如果我们想去掉这些 token 的话,我们可以做做如下的设置:
DELETE blogs
PUT blogs
{
"settings": {
"analysis": {
"char_filter": {
"xschool_filter": {
"type": "mapping",
"mappings": [
"X-Game => XGame"
]
}
},
"analyzer": {
"my_content_analyzer": {
"type": "custom",
"char_filter": [
"xschool_filter"
],
"tokenizer": "standard",
"filter": [
"lowercase",
"my_stop"
]
}
},
"filter": {
"my_stop": {
"type": "stop",
"stopwords": ["so", "to", "the"]
}
}
}
},
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "my_content_analyzer"
}
}
}
}
重新加入了一个叫做 my_stop 的过滤器:
"filter": {
"my_stop": {
"type": "stop",
"stopwords": ["so", "to", "the"]
}
}
再测试查看已经把 so, to 及 the 作为 stop words 去掉了。
Filters 的顺序也很重要
GET _analyze
{
"tokenizer": "whitespace",
"filter": [
"lowercase",
"stop"
],
"text": "To Be Or Not To Be"
}
先进行 lowercase 的过滤器,先变成小写字母,再进行 stop 过滤器,那么返回的结果是[],也即没有。
GET _analyze
{
"tokenizer": "whitespace",
"filter": [
"stop",
"lowercase"
],
"text": "To Be Or Not To Be"
}
这里先进行 stop 过滤器,因为这里的词有些是大写字母,所以不被认为是 stop 词,那么没有被过滤掉。之后进行 lowercase,显示的结果是 to, be, or, not, to, be 这些 token。
关于Search_analyzer
每当一个文档在被录入到 Elasticsearch中 时,需要一个叫做 index 的过程。在 index 的过程中,它会为该字符串进行分词,并最终形成一个一个的 token,并存于数据库。但是,每当我们搜索一个字符串时,在搜索时,我们同样也要对该字符串进行分词,也会建立token。当然这些token不会被存放于数据库中。
例 :
GET /chinese/_search
{
"query": {
"match": {
"content": "Happy a birthday"
}
}
}
对于这个搜索来说,我们在默认的情况下,会把 “Happy a birthday” 使用同样的 analyzer 进行分词。如果我们的 analyzer 里含有stop 过滤器,它极有可能把字母 “a” 过滤掉,那么直剩下 “happy” 及 “birthday” 这两个词,而 “a” 将不进入搜索之中。
在实际的使用中,我们可以通过上面所述的定制分析器去定制自己的分词器,然后再最后的mapping指定对搜索进行制定具体的 search_analyzer。
"mappings": {
"properties": {
"content": {
"type": "text",
"analyzer": "my_content_analyzer",
"search_analyzer": "standard"
}
}
}
内置分析器参考
Standard Analyzer
标准分析器按照 Unicode 文本分割算法的定义,将文本划分为单词边界上的术语。它删除了大多数标点符号、小写术语,并支持删除停用词。
Simple Analyzer
只要遇到一个不是字母的字符,简单的分析器就会将文本分成术语。它小写所有术语。
Whitespace Analyzer
每当遇到任何空白字符时,空白分析器都会将文本划分为术语。它不使用小写术语。
Stop Analyzer
停止分析器就像简单的分析器,但也支持去除停用词。
Keyword Analyzer
关键字分析器是一个 “noop” 分析器,它接受给定的任何文本并输出与单个术语完全相同的文本。
Pattern Analyzer
模式分析器使用正则表达式将文本拆分为术语。它支持小写和停用词。
Language Analyzers
Elasticsearch 提供了许多特定于语言的分析器,如英语或法语。
Fingerprint Analyzer
指纹分析仪是一种专业分析仪,可创建可用于重复检测的指纹。