笔记列表:ElasticSearch
ES 分词器功能用于 text 类型的 field,分词效果和全文检索的结果相关。
ES 内置了多个分词器 Built-in analyzer,并且支持自定义分词起 Create a custom analyzer。
Analyzer 由三部分组成,分别负责前、中、后三个阶段的文本处理,Anatomy of an analyzer:
1. Character filter:字符过滤,用于移除不需要的字符(比如 html 标签)、字符转换等(比如印度语的数字转换成阿拉伯数字)
2. Tokenizer:断词,将连续的文本字符断开成多个独立的词,并记录每个词开头和结尾的位置
3. Token filter:词过滤,将 Tokenizer 的断词进行规整处理,比如全部转为消息、同义词合并、舍弃 the 等 stop word。过滤不改变 Tokenizer 记录的词的位置
Analyzer 必须有且只有一个 Tokenizer,可以有零个或任意多个 Character filters、Token filter。
Analyzer 的工作场合由两个:
通常情况下,Index Analyzer 应当和 Search Analyzer 保持一致,但是 es 支持:
1、在搜索时指定不同的 Analyzer
GET my-index-000001/_search
{
"query": {
"match": {
"message": {
"query": "Quick foxes",
"analyzer": "stop" <-- Query时指定 Search Analyzer
}
}
}
}
2、在 mapping 中分别定义 field 的 Index Analyzer 和 Search Analyzer。
PUT my-index-000001
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "whitespace", <-- Index Analyzer
"search_analyzer": "simple" <-- Search Analyzer
}
}
}
}
3、在 setting 中分别定义默认的 Index Analyzer 和 Search Analyzer
PUT my-index-000001
{
"settings": {
"analysis": {
"analyzer": {
"default": { <-- 默认的 Index Analyzer
"type": "simple"
},
"default_search": { <-- 默认的 Search Analyzer
"type": "whitespace"
}
}
}
}
}
英文单词在不同的语境下会变形成不同的字符,譬如 walk、walking、walked 等。在 Index 以及 Search 的时候需要这些变形词转换成统一的根词(root form)。ES 把这个过程叫做 Stemming,相应的 filter 称为 Stemmer token filter。
Token graphs 详细解释了 Token 的记录方式,这里不展开。
Configure text analysis 介绍了 Analyzer 的使用和配置方法
ES 提供了 Analyze API,可以直接用它直接验证 ES 内置的分词器的效果,Built-in analyzer reference。不过,ES 内置的分词器都不适用于中文,比如 “standard” analyzer 将每个汉字认为是一个词,不符合中文语法。内置的 30 多个不同语种的 Language analyzers 中没有中文。对中文分词需要另外安装开源社区提供的中文分词插件。
下面是 ES 内置的常规分词器,执行后会发现对中文基本无效:
GET /_analyze
{
"analyzer" : "standard",
"text" : "那年冬天,祖母死了,父亲的差使也交卸了,正是祸不单行的日子。我从北京到徐州,打算跟着父亲奔丧回家。到徐州见着父亲,看见满院狼藉的东西,又想起祖母,不禁簌簌地流下眼泪。父亲说:“事已如此,不必难过,好在天无绝人之路!"
}
GET /_analyze
{
"analyzer" : "simple",
"text" : "那年冬天,祖母死了,父亲的差使也交卸了,正是祸不单行的日子。我从北京到徐州,打算跟着父亲奔丧回家。到徐州见着父亲,看见满院狼藉的东西,又想起祖母,不禁簌簌地流下眼泪。父亲说:“事已如此,不必难过,好在天无绝人之路!"
}
GET /_analyze
{
"analyzer" : "whitespace",
"text" : "那年冬天,祖母死了,父亲的差使也交卸了,正是祸不单行的日子。我从北京到徐州,打算跟着父亲奔丧回家。到徐州见着父亲,看见满院狼藉的东西,又想起祖母,不禁簌簌地流下眼泪。父亲说:“事已如此,不必难过,好在天无绝人之路!"
}
GET /_analyze
{
"analyzer" : "stop",
"text" : "那年冬天,祖母死了,父亲的差使也交卸了,正是祸不单行的日子。我从北京到徐州,打算跟着父亲奔丧回家。到徐州见着父亲,看见满院狼藉的东西,又想起祖母,不禁簌簌地流下眼泪。父亲说:“事已如此,不必难过,好在天无绝人之路!"
}
GET /_analyze
{
"analyzer" : "keyword",
"text" : "那年冬天,祖母死了,父亲的差使也交卸了,正是祸不单行的日子。我从北京到徐州,打算跟着父亲奔丧回家。到徐州见着父亲,看见满院狼藉的东西,又想起祖母,不禁簌簌地流下眼泪。父亲说:“事已如此,不必难过,好在天无绝人之路!"
}
GET /_analyze
{
"analyzer" : "pattern",
"text" : "那年冬天,祖母死了,父亲的差使也交卸了,正是祸不单行的日子。我从北京到徐州,打算跟着父亲奔丧回家。到徐州见着父亲,看见满院狼藉的东西,又想起祖母,不禁簌簌地流下眼泪。父亲说:“事已如此,不必难过,好在天无绝人之路!"
}
GET /_analyze
{
"analyzer" : "fingerprint",
"text" : "那年冬天,祖母死了,父亲的差使也交卸了,正是祸不单行的日子。我从北京到徐州,打算跟着父亲奔丧回家。到徐州见着父亲,看见满院狼藉的东西,又想起祖母,不禁簌簌地流下眼泪。父亲说:“事已如此,不必难过,好在天无绝人之路!"
}
每个 Analyzer 有各自的可配置参数,可以通过这些参数影响 Analyzer 的分词行为,详情见各个 Analyzer 的文档 Built-in analyzer reference。
这里的自定义 Analyzer 是指在 Index 的 setting 中自行组合 charater fileter、tokenizer(有且只有一个) 和 token fileter 形成一个 Analyzer,Create a custom analyzer。
PUT my-index-000001
{
"settings": {
"analysis": {
"analyzer": {
"my_custom_analyzer": { <-- 自定义的 Analyzer
"type": "custom",
"tokenizer": "standard", <-- tokenizer
"char_filter": [ <-- character filter
"html_strip"
],
"filter": [ <-- token filter
"lowercase",
"asciifolding"
]
}
}
}
}
}
下面是可用于搭配 Analyzer 的组件的索引:
前面已经讲过,Analyzer 用于 Index 和 Search 两个过程,分别可以 Search 参数、Index 的 mapping 和 Index 的 Setting 中引用。这里不赘述,见前面的内容或者阅读 Specify an analyzer。
Normalizers 可以理解成不含 tokenizer 的 Analyzer,它的作用是将输入的文本加工成一个 token,只做字符处理不进行分词。
PUT index
{
"settings": {
"analysis": {
"char_filter": {
"quote": {
"type": "mapping",
"mappings": [
"« => \"",
"» => \""
]
}
},
"normalizer": {
"my_normalizer": { <-- 定义 normalizer
"type": "custom",
"char_filter": ["quote"],
"filter": ["lowercase", "asciifolding"]
}
}
}
},
"mappings": {
"properties": {
"foo": {
"type": "keyword",
"normalizer": "my_normalizer" <-- 引用 normalizer
}
}
}
}
用 es 的 elasticsearch-plugin
命令安装,注意插件的版本需要和 es 的版本一致,否则暗转不上。比如 v7.9.2 的 es 安装对应 v7.9.2 版本的 ik 插件 elasticsearch-analysis-ik。
ik 分词器维护者曾勇目前负责 es 在中国区的顾问资讯业务, ik 更新比较及时,ik插件release下载。
./bin/elasticsearch-plugin -v install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.9.2/elasticsearch-analysis-ik-7.9.2.zip
查看已安装插件:
./bin/elasticsearch-plugin list
analysis-ik
插件安装完成后需要重启 es。
ik 提供了 ik_max_word
和 ik_smart
两种分词模式,前者分词时会组合出尽可能多的词,后者进行粗粒度的分词。
GET /_analyze
{
"analyzer" : "ik_max_word",
"text" : ["你这是画龙点睛"]
}
GET /_analyze
{
"analyzer" : "ik_smart",
"text" : ["你这是画龙点睛"]
}
清华大学自然语言处理与社会人文计算实验室开发的 THULAC 分词包也可以用于 es:elasticsearch-thulac-plugin。
这个插件的维护有点跟不上,es 版本已经到 8.2 ,thulac 的分词插件才更新到 7.9.1。
不过分词程序包可以从 THULAC 下载使用,主观感觉 thulac 的分词效果比 ik 要好,thulac 还能给出词性。