一、前言
ES进行文档分析就会涉及到分析器,无论是内置的分析器,还是自定义的分析器,都是由一个分词器(
tokenizers
) 、0或多个词项过滤器(token filters
)、0或多个字符过滤器(character filters
)组成。
二、内置分析器
Elasticsearch 还附带了可以直接使用的预包装的分析器。以下会用
"Set the shape to semi-transparent by calling set_trans(5)" 这段字符串对内置的各种分析器进行区分。
一、标准分析器
标准分析器是 Elasticsearch 默认使用的分析器。它是分析各种语言文本最常用的选择。 它根据 Unicode 联盟定义的单词边界划分文本,删除绝大部分标点。最后,将词条小写。 它会产生:
set, the, shape, to, semi, transparent, by, calling, set_trans, 5
二、简单分析器
简单分析器在任何不是字母的地方分隔文本,将词条小写。它会产生:
set, the, shape, to, semi, transparent, by, calling, set, trans
三、空格分析器
空格分析器在空格的地方划分文本。它会产生:
Set, the, shape, to, semi-transparent, by, calling, set_trans(5)
四、语言分析器
特定语言分析器可用于 很多语言。它们可以考虑指定语言的特点。例如, 英语 分析 器附带了一组英语无用词(常用单词,例如 and 或者 the ,它们对相关性没有多少影响), 它们会被删除。 由于理解英语语法的规则,这个分词器可以提取英语单词的 词干 。
英语 分词器会产生下面的词条:
set, shape, semi, transpar, call, set_tran, 5
注意看 transparent、 calling 和 set_trans 已经变为词根格式
三、IK分词器
一、IK分词器测试
当Elasticsearch在你的文档中检测到一个新的字符串域,它会自动设置其为一个全文 字 符串 域,使用 标准 分析器对它进行分析。你不希望总是这样。可能你想使用一个不同的 分析器,适用于你的数据使用的语言。有时候你想要一个字符串域就是一个字符串域—不使用分析,直接索引你传入的精确值,例如用户 ID 或者一个内部的状态域或标签。要做到这 一点,我们必须手动指定这些域的映射。
很多时候我们使用默认的分析器,是无法达到我们的需求的。例如:
GET http://localhost:9200/_analyze
{
"text":"测试单词"
}
如果使用内置的分析器,会产生:
{
"tokens": [{
"token": "测",
"start_offset": 0,
"end_offset": 1,
"type": "<IDEOGRAPHIC>",
"position": 0
},
{
"token": "试",
"start_offset": 1,
"end_offset": 2,
"type": "<IDEOGRAPHIC>",
"position": 1
},
{
"token": "单",
"start_offset": 2,
"end_offset": 3,
"type": "<IDEOGRAPHIC>",
"position": 2
},
{
"token": "词",
"start_offset": 3,
"end_offset": 4,
"type": "<IDEOGRAPHIC>",
"position": 3
}
]
}这是由于ES 的默认分词器无法识别中文中测试、单词这样的词汇,而是简单的将每个字拆完分为一 个词。这样的结果显然不符合我们的使用要求,所以我们需要下载 ES 对应版本的中文分词器。
IK 中文分词器地址:
https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v7.8.0 将解压后的后的文件夹放入 ES 根目录下的 plugins 目录下,重启 ES 即可使用。
1、ik_max_word:会将文本做最细粒度的拆分
2、ik_smart:会将文本做最粗粒度的拆分
我们这次加入新的查询参数"analyzer":"ik_max_word"
GET http://localhost:9200/_analyze
{
"text":"测试单词",
"analyzer":"ik_max_word"
}
{
"tokens": [{
"token": "测试",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 0
},
{
"token": "单词",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 1
}
]
}
二、IK分词器拓展
ES 中也可以进行扩展词汇,首先查询
GET http://localhost:9200/_analyze
{
"text":"弗雷尔卓德",
"analyzer":"ik_max_word"
}
{
"tokens": [{
"token": "弗",
"start_offset": 0,
"end_offset": 1,
"type": "CN_CHAR",
"position": 0
}, {
"token": "雷",
"start_offset": 1,
"end_offset": 2,
"type": "CN_CHAR",
"position": 1
}, {
"token": "尔",
"start_offset": 2,
"end_offset": 3,
"type": "CN_CHAR",
"position": 2
}, {
"token": "卓",
"start_offset": 3,
"end_offset": 4,
"type": "CN_CHAR",
"position": 3
}, {
"token": "德",
"start_offset": 4,
"end_offset": 5,
"type": "CN_CHAR",
"position": 4
}]
}仅仅可以得到每个字的分词结果,我们需要做的就是使分词器识别到弗雷尔卓德也是一个词 语
首先进入 ES 根目录中的 plugins 文件夹下的 ik 文件夹,进入 config 目录,创建 custom.dic 文件,写入弗雷尔卓德。同时打开 IKAnalyzer.cfg.xml 文件,将新建的 custom.dic 配置其中, 重启 ES 服务器。
四、分析器使用场景
当我们 索引 一个文档,它的全文域被分析成词条以用来创建倒排索引。 但是,当我 们在全文域 搜索 的时候,我们需要将查询字符串通过 相同的分析过程 ,以保证我们搜索 的词条格式与索引中的词条格式一致。
1、当你查询一个全文域时,会对查询字符串应用相同的分析器,以产生正确的搜 索词条列表。
2、当你查询一个 精确值 域时,不会分析查询字符串,而是搜索你指定的精确值。
五、测试分析器
有些时候很难理解分词的过程和实际被存储到索引中的词条,特别是你刚接触 Elasticsearch。为了理解发生了什么,你可以使用 analyze API 来看文本是如何被分析的。 在消息体里,指定分析器和要分析的文本
GET http://localhost:9200/_analyze
{
"analyzer": "standard",
"text": "Text to analyze"
}
结果中每个元素代表一个单独的词条:
{
"tokens": [{
"token": "text",
"start_offset": 0,
"end_offset": 4,
"type": "",
"position": 1
}, {
"token": "to",
"start_offset": 5,
"end_offset": 7,
"type": "",
"position": 2
}, {
"token": "analyze",
"start_offset": 8,
"end_offset": 15,
"type": "",
"position": 3
}]
}token 是实际存储到索引中的词条。
position 指明词条在原始文本中出现的位置。
start_offset 和 end_offset 指明字符在原始字符串中的位置。
六、自定义分析器
虽然 Elasticsearch 带有一些现成的分析器,然而在分析器上 Elasticsearch 真正的强大之 处在于,你可以通过在一个适合你的特定数据的设置之中组合字符过滤器、分词器、词汇单 元过滤器来创建自定义的分析器。一个 分析器 就是在一个包 里面组合了三种函数的一个包装器, 三种函数按照顺序被执行:
1、字符过滤器:
字符过滤器 用来 整理 一个尚未被分词的字符串。例如,如果我们的文本是 HTML 格 式的,它会包含像
或者这样的 HTML 标签,这些标签是我们不想索引的。我 们可以使用 html 清除 字符过滤器 来移除掉所有的 HTML 标签,并且像把 Á 转换 为相对应的 Unicode 字符 Á 这样,转换 HTML 实体。一个分析器可能有 0 个或者多个字符 过滤器。
2、分词器:
一个分析器 必须 有一个唯一的分词器。 分词器把字符串分解成单个词条或者词汇单 元。 标准 分析器里使用的 标准 分词器 把一个字符串根据单词边界分解成单个词条,并 且移除掉大部分的标点符号,然而还有其他不同行为的分词器存在。 例如, 关键词 分词器 完整地输出 接收到的同样的字符串,并不做任何分词。 空格分词器只根据空格分割文本 。正则分词器 根据匹配正则表达式来分割文本 。
3、词单元过滤器:
经过分词,作为结果的 词单元流 会按照指定的顺序通过指定的词单元过滤器 。 词单元过滤器可以修改、添加或者移除词单元。我们已经提到过 lowercase 和 stop 词过滤 器 ,但是在 Elasticsearch 里面还有很多可供选择的词单元过滤器。词干过滤器 把单词 遏 制 为 词干。 ascii_folding 过滤器移除变音符,把一个像 "très" 这样的词转换为 "tres"。ngram 和 edge_ngram 词单元过滤器 可以产生 适合用于部分匹配或者自动补全的词单元。
创建自定义的分析器 :
PUT http://localhost:9200/my_index
{
"settings": {
"analysis": {
"char_filter": { // 字符串过滤器
"&_to_and": {
"type": "mapping",
"mappings": ["&=> and "] // 将& 转换为 and
}
},
"filter": {
"my_stopwords": {
"type": "stop",
"stopwords": ["the", "a"]
}
},
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": ["html_strip", "&_to_and"],
"tokenizer": "standard",
"filter": ["lowercase", "my_stopwords"]
}
}
}
}
}
结果:
{
"tokens": [{
"token": "quick",
"start_offset": 4,
"end_offset": 9,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "and",
"start_offset": 10,
"end_offset": 11,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "brown",
"start_offset": 12,
"end_offset": 17,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "fox",
"start_offset": 18,
"end_offset": 21,
"type": "<ALPHANUM>",
"position": 4
}
]
}