Elasticsearch:分词器中的 token 过滤器使用示例
2022年9月16日 | by mebius
分词器在 Elasticsearch 的使用中非常重要。分词器中的过滤器可以帮我们对最终的分词进行处理,从而使得我们得到的最终分词会影响存储的大小和搜索的方式。在今天的文章中,我来分享一下一些常用的分词器中的 token 过滤器。更多有关 token 过滤器的内容可以在 Elastic 的官方文档查询。有关更多关于 analyzer 的阅读,请参考我之前的文章 “Elasticsearch: analyzer”。
如上图所示,在分词器的构成中,它可以含有0或多个 char filters,有且只有一个 tokenizer,0或多个 token filters。
安装
在今天的展示中,我们需要安装中文最为流行的 IK 分词器。详细的安装步骤请参考文章 “Elasticsearch:IK 中文分词器”。
Apostrophe token filter
去掉撇号后的所有字符,包括撇号本身。这个在英文中比较常见。比如,我们写如下的句子:
This is Tom's clothes.
在上面,我们可以看到有一个 ’ 符号。在实际的分词中,我们希望去掉 ‘ 符号后面的所有字符。我们可以使用如下的例子来进行展示:
GET /_analyze
{
"tokenizer" : "standard",
"filter" : ["apostrophe"],
"text" : "Istanbul'a veya Istanbul'dan"
}
上面的 filter 产生如下的结果:
{
"tokens": [
{
"token": "Istanbul",
"start_offset": 0,
"end_offset": 10,
"type": "",
"position": 0
},
{
"token": "veya",
"start_offset": 11,
"end_offset": 15,
"type": "",
"position": 1
},
{
"token": "Istanbul",
"start_offset": 16,
"end_offset": 28,
"type": "",
"position": 2
}
]
}
在实际的使用中,我们可以使用如下的例子来进行展示:
PUT test
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"apostrophe",
"lowercase"
]
}
}
}
},
"mappings": {
"properties": {
"text": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
}
在上面,我们定义了一个叫做 test 的索引,并且它的 text 字段使用 my_analyzer。在没有特定指定 search_analyzer 的情况下,分词和搜索将使用同样的一个分词器:my_analyzer。我们使用如下的一个命令来写入一个文档:
PUT test/_doc/1
{
"text": "Istanbul'a veya Istanbul'dan"
}
那么我们可以使用如下的一个搜索来搜索该文档:
GET test/_search
{
"query": {
"match": {
"text": "Istanbul"
}
}
}
上面的搜索结果为:
{
"tokens": [
{
"token": "Istanbul",
"start_offset": 0,
"end_offset": 10,
"type": "",
"position": 0
},
{
"token": "veya",
"start_offset": 11,
"end_offset": 15,
"type": "",
"position": 1
},
{
"token": "Istanbul",
"start_offset": 16,
"end_offset": 28,
"type": "",
"position": 2
}
]
}
ASCII folding token filter
将不在 Basic Latin Unicode 块中的字母、数字和符号字符(前 127 个 ASCII 字符)转换为它们的 ASCII 等效字符(如果存在)。 例如,过滤器将 更改为 a。
以下 analyzeAPI 请求使用 asciifolding 过滤器删除 aa la carte 中的变音符号:
GET /_analyze
{
"tokenizer" : "standard",
"filter" : ["asciifolding"],
"text" : "aa la carte"
}
上面的命令返回:
{
"tokens": [
{
"token": "acai",
"start_offset": 0,
"end_offset": 4,
"type": "",
"position": 0
},
{
"token": "a",
"start_offset": 5,
"end_offset": 6,
"type": "",
"position": 1
},
{
"token": "la",
"start_offset": 7,
"end_offset": 9,
"type": "",
"position": 2
},
{
"token": "carte",
"start_offset": 10,
"end_offset": 15,
"type": "",
"position": 3
}
]
}
Classic token filter
对经典分词器生成的术语执行可选的后处理。
此过滤器从单词末尾删除英语所有格 (‘s) 并从首字母缩略词中删除点。 它使用 Lucene 的 ClassicFilter。例如:
GET /_analyze
{
"tokenizer" : "classic",
"filter" : ["classic"],
"text" : "The 2 Q.U.I.C.K. Brown-Foxes jumped over the lazy dog's bone."
}
上面将返回:
{
"tokens": [
{
"token": "The",
"start_offset": 0,
"end_offset": 3,
"type": "",
"position": 0
},
{
"token": "2",
"start_offset": 4,
"end_offset": 5,
"type": "",
"position": 1
},
{
"token": "QUICK",
"start_offset": 6,
"end_offset": 16,
"type": "",
"position": 2
},
{
"token": "Brown",
"start_offset": 17,
"end_offset": 22,
"type": "",
"position": 3
},
{
"token": "Foxes",
"start_offset": 23,
"end_offset": 28,
"type": "",
"position": 4
},
{
"token": "jumped",
"start_offset": 29,
"end_offset": 35,
"type": "",
"position": 5
},
{
"token": "over",
"start_offset": 36,
"end_offset": 40,
"type": "",
"position": 6
},
{
"token": "the",
"start_offset": 41,
"end_offset": 44,
"type": "",
"position": 7
},
{
"token": "lazy",
"start_offset": 45,
"end_offset": 49,
"type": "",
"position": 8
},
{
"token": "dog",
"start_offset": 50,
"end_offset": 55,
"type": "",
"position": 9
},
{
"token": "bone",
"start_offset": 56,
"end_offset": 60,
"type": "",
"position": 10
}
]
}
显然,在 Q.U.I.CK. 中的点都被删除了,同时dog’s 中的 ‘s 被去掉了。
Conditional token filter
将一组 token 过滤器应用于与提供的谓词脚本中的条件匹配的标记。此过滤器使用 Lucene 的 ConditionalTokenFilter。
以下 analyzeAPI 请求使用条件过滤器来匹配 THE QUICK BROWN FOX 中少于 5 个字符的标记。 然后它将 lowercase 过滤器应用于那些匹配的标记,将它们转换为小写。
GET /_analyze
{
"tokenizer": "standard",
"filter": [
{
"type": "condition",
"filter": [ "lowercase" ],
"script": {
"source": "token.getTerm().length()
上面的命令返回:
{
"tokens": [
{
"token": "the",
"start_offset": 0,
"end_offset": 3,
"type": "",
"position": 0
},
{
"token": "QUICK",
"start_offset": 4,
"end_offset": 9,
"type": "",
"position": 1
},
{
"token": "BROWN",
"start_offset": 10,
"end_offset": 15,
"type": "",
"position": 2
},
{
"token": "fox",
"start_offset": 16,
"end_offset": 19,
"type": "",
"position": 3
}
]
}
请注意上面的 script 指的是 painless script。在上面,我们看到虽然有 lowercase 过滤器,但是它仅仅作用于 token 的长度小于 5 的 token 上面。从输出中,我们可以看到,BROWN及 QUICK 并没有变为小写,原因是他们的长度是5,不满足条件。
自定义并添加到分词器
要自定义 conditional 过滤器,请将其复制以创建新的自定义标记过滤器的基础。 你可以使用其可配置参数修改过滤器。
例如,以下创建索引 API 请求使用自定义 conditional 过滤器来配置新的自定义分词器。 自定义条件过滤器匹配流中的第一个 token。 然后它使用反向过滤器反转匹配的 token。
PUT /palindrome_list
{
"settings": {
"analysis": {
"analyzer": {
"whitespace_reverse_first_token": {
"tokenizer": "whitespace",
"filter": [ "reverse_first_token" ]
}
},
"filter": {
"reverse_first_token": {
"type": "condition",
"filter": [ "reverse" ],
"script": {
"source": "token.getPosition() === 0"
}
}
}
}
}
}
Fingerprint token filter
从 token 流中排序和删除重复的 token,然后将流连接成单个输出 token。例如,此过滤器将 [ the, fox, was, very, very, quick ] 标记流更改如下:
- 将 token 按字母顺序排序为 [ fox, quick, the, very, very, was ]
- 删除 very token 的重复实例。
- 将 token 流连接到输出单个 token:[fox quick the very was]
此过滤器使用 Lucene 的 FingerprintFilter。例如:
以下 analyzeAPI 请求使用指纹过滤器为文本 zebra jumps over resting resting dog 创建单个输出 token:
GET _analyze
{
"tokenizer" : "whitespace",
"filter" : ["fingerprint"],
"text" : "zebra jumps over resting resting dog"
}
上面的命令返回:
{
"tokens": [
{
"token": "dog jumps over resting zebra",
"start_offset": 0,
"end_offset": 36,
"type": "fingerprint",
"position": 0
}
]
}
请注意的是它返回仅有一个 token。
Reverse token filter
反转流中的每个 token。 例如,你可以使用反向过滤器将 cat 更改为 tac。反转 token 对于基于后缀的搜索很有用,例如查找以 -ion 结尾的单词或按扩展名搜索文件名。请参阅我之前的文章 “Elasticsearch:正确使用 regexp 搜索”。这个过滤器使用 Lucene 的 ReverseStringFilter。
以下 analyze API 请求使用反向过滤器来反转 quick fox jumps 中的每个 token:
GET _analyze
{
"tokenizer" : "standard",
"filter" : ["reverse"],
"text" : "quick fox jumps"
}
上面的过滤器返回:
{
"tokens": [
{
"token": "kciuq",
"start_offset": 0,
"end_offset": 5,
"type": "",
"position": 0
},
{
"token": "xof",
"start_offset": 6,
"end_offset": 9,
"type": "",
"position": 1
},
{
"token": "spmuj",
"start_offset": 10,
"end_offset": 15,
"type": "",
"position": 2
}
]
}
就如第一个例子中显示的那样,我们可以使用如下的例子来定义并使用这个 filter:
PUT reverse_example
{
"settings" : {
"analysis" : {
"analyzer" : {
"whitespace_reverse" : {
"tokenizer" : "whitespace",
"filter" : ["reverse"]
}
}
}
},
"mappings": {
"properties": {
"text": {
"type": "text",
"analyzer": "whitespace_reverse"
}
}
}
}
我们可以使用如下的命令来写入一个文档:
PUT reverse_example/_doc/1
{
"text": "I like the speed of this network"
}
我们可以使用如下的方法来进行搜索:
GET reverse_example/_search
{
"query": {
"regexp": {
"text": "krow.*"
}
}
}
特别需要指出的是:当我们使用通配符在前面进行搜索时搜索比较慢。这个时候,我们可以选择 reverse 过滤器来进行反转。
Unique token filter
从流中删除重复的 token。 例如,你可以使用 unique 过滤器将 the lazy lazy dog 更改为 the lazy dog。如果 only_on_same_position 参数设置为 true,则unique 过滤器仅删除同一位置的重复标记。
注意:当 only_on_same_position 为 true 时,unique 过滤器的工作方式与 remove_duplicates 过滤器相同。
我们使用如下的例子来进行展示:
GET _analyze
{
"tokenizer" : "whitespace",
"filter" : ["unique"],
"text" : "the quick fox jumps the lazy fox"
}
上面的命令返回:
{
"tokens": [
{
"token": "the",
"start_offset": 0,
"end_offset": 3,
"type": "word",
"position": 0
},
{
"token": "quick",
"start_offset": 4,
"end_offset": 9,
"type": "word",
"position": 1
},
{
"token": "fox",
"start_offset": 10,
"end_offset": 13,
"type": "word",
"position": 2
},
{
"token": "jumps",
"start_offset": 14,
"end_offset": 19,
"type": "word",
"position": 3
},
{
"token": "lazy",
"start_offset": 24,
"end_offset": 28,
"type": "word",
"position": 4
}
]
}
显然上面的返回中,只有一个 fox,而在原文档中有两个 fox。我们可以通过如下的方式来添加这个过滤器到 analyzer 中:
PUT custom_unique_example
{
"settings" : {
"analysis" : {
"analyzer" : {
"standard_truncate" : {
"tokenizer" : "standard",
"filter" : ["unique"]
}
}
}
}
}
我们可以通过如下的方式来定制这个过滤器:
PUT letter_unique_pos_example
{
"settings": {
"analysis": {
"analyzer": {
"letter_unique_pos": {
"tokenizer": "letter",
"filter": [ "unique_pos" ]
}
},
"filter": {
"unique_pos": {
"type": "unique",
"only_on_same_position": true
}
}
}
}
}
在上面,我们设置only_on_same_position 为 true。在默认的情况下,这个值为 false。
Length token filter
删除比指定字符长度更短或更长的标记。 例如,你可以使用长度过滤器来排除短于 2 个字符的标记和长于 5 个字符的标记。此过滤器使用 Lucene 的 LengthFilter。
提示:长度过滤器删除整个 token。 如果你希望将 token 缩短到特定长度,请使用 truncate 过滤器。
例如:
GET _analyze
{
"tokenizer": "whitespace",
"filter": [
{
"type": "length",
"min": 0,
"max": 4
}
],
"text": "the quick brown fox jumps over the lazy dog"
}
上面的命令返回长度为 0 到 4 的 token:
{
"tokens": [
{
"token": "the",
"start_offset": 0,
"end_offset": 3,
"type": "word",
"position": 0
},
{
"token": "fox",
"start_offset": 16,
"end_offset": 19,
"type": "word",
"position": 3
},
{
"token": "over",
"start_offset": 26,
"end_offset": 30,
"type": "word",
"position": 5
},
{
"token": "the",
"start_offset": 31,
"end_offset": 34,
"type": "word",
"position": 6
},
{
"token": "lazy",
"start_offset": 35,
"end_offset": 39,
"type": "word",
"position": 7
},
{
"token": "dog",
"start_offset": 40,
"end_offset": 43,
"type": "word",
"position": 8
}
]
}
这个过滤器对中文也有很多的帮助。比如,我们只想有超过两个字的中文 token:
PUT twitter
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "ik_smart",
"filter": [
"longer_than_2"
]
}
},
"filter": {
"longer_than_2": {
"type": "length",
"min": 2
}
}
}
},
"mappings": {
"properties": {
"text": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
}
我们使用上面的索引来进行测试:
GET twitter/_analyze
{
"analyzer": "my_analyzer",
"text": ["我爱北京天安门"]
}
上面的命令返回:
{
"tokens": [
{
"token": "北京",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 2
},
{
"token": "天安门",
"start_offset": 4,
"end_offset": 7,
"type": "CN_WORD",
"position": 3
}
]
}
显然它只返回 “北京” 及 “天安门” 这个两个长度超过 2 的 token。我们和如下的分词进行比较:
GET _analyze
{
"analyzer": "ik_smart",
"text": ["我爱北京天安门"]
}
{
"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": 4,
"type": "CN_WORD",
"position": 2
},
{
"token": "天安门",
"start_offset": 4,
"end_offset": 7,
"type": "CN_WORD",
"position": 3
}
]
}
很显然,当我们写入如下的文档:
PUT twitter/_doc/1
{
"text": "我爱北京天安门"
}
我们使用如下的命令来进行搜索:
GET twitter/_search
{
"query": {
"match": {
"text": "我"
}
}
}
它将不返回任何的文档,但是如果我们使用如下的命令来进行搜索:
GET twitter/_search
{
"query": {
"match": {
"text": "北京"
}
}
}
它将返回我们的文档。
Lower token filter
将 token 文本更改为小写。 例如,你可以使用 lowercase 过滤器将 THE Lazy DoG 更改为 the lazy dog。
除了默认过滤器之外,lowercase token 过滤器还提供对 Lucene 的希腊语、爱尔兰语和土耳其语的特定语言小写过滤器的访问。
例如:
GET _analyze
{
"tokenizer" : "standard",
"filter" : ["lowercase"],
"text" : "THE Quick FoX JUMPs"
}
上面的命令返回:
{
"tokens": [
{
"token": "the",
"start_offset": 0,
"end_offset": 3,
"type": "",
"position": 0
},
{
"token": "quick",
"start_offset": 4,
"end_offset": 9,
"type": "",
"position": 1
},
{
"token": "fox",
"start_offset": 10,
"end_offset": 13,
"type": "",
"position": 2
},
{
"token": "jumps",
"start_offset": 14,
"end_offset": 19,
"type": "",
"position": 3
}
]
}
很显然,它把上面的大写字母都变为小写的了。
Upercase token filter
将 token 文本更改为大写。 例如,你可以使用大写过滤器将 Lazy Dog 更改为 THE LAZY DOG。此过滤器使用 Lucene 的 UpperCaseFilter。
以下 analyze API 请求使用默认 uppercase 过滤器将 Quick FoX JUMP 更改为大写:
GET _analyze
{
"tokenizer" : "standard",
"filter" : ["uppercase"],
"text" : "the Quick FoX JUMPs"
}
上面的命令返回结果:
{
"tokens": [
{
"token": "THE",
"start_offset": 0,
"end_offset": 3,
"type": "",
"position": 0
},
{
"token": "QUICK",
"start_offset": 4,
"end_offset": 9,
"type": "",
"position": 1
},
{
"token": "FOX",
"start_offset": 10,
"end_offset": 13,
"type": "",
"position": 2
},
{
"token": "JUMPS",
"start_offset": 14,
"end_offset": 19,
"type": "",
"position": 3
}
]
}
以下创建索引 API 请求使用 upercase 过滤器来配置新的自定义分词器。
PUT uppercase_example
{
"settings": {
"analysis": {
"analyzer": {
"whitespace_uppercase": {
"tokenizer": "whitespace",
"filter": [ "uppercase" ]
}
}
}
}
}
Stop token filter
从 token 流中删除停用词。未自定义时,过滤器默认删除以下英文停用词:
a, an, and, are, as, at, be, but, by, for, if, in, into, is, it, no, not, of, on, or, such, that, the, their, then, there, these, they, this, to, was, will, with
除了英语之外,stop 过滤器还支持多种语言的预定义 stop 词列表。 你还可以将自己的 stop 词指定为数组或文件。stop 过滤器使用 Lucene 的 StopFilter。
例子:
下面的 analyze API 请求使用 stop 过滤器从 a quick fox jumps over the lazy dog 来删除停用词a 和 the:
GET /_analyze
{
"tokenizer": "standard",
"filter": [ "stop" ],
"text": "a quick fox jumps over the lazy dog"
}
上面的命令返回结果:
{
"tokens": [
{
"token": "quick",
"start_offset": 2,
"end_offset": 7,
"type": "",
tgcode "position": 1
},
{
"token": "fox",
"start_offset": 8,
"end_offset": 11,
"type": "",
"position": 2
},
{
"token": "jumps",
"start_offset": 12,
"end_offset": 17,
"type": "",
"position": 3
},
{
"token": "over",
"start_offset": 18,
"end_offset": 22,
"type": "",
"position": 4
},
{
"token": "lazy",
"start_offset": 27,
"end_offset": 31,
"type": "",
"position": 6
},
{
"token": "dog",
"start_offset": 32,
"end_offset": 35,
"type": "",
"position": 7
}
]
}
从上面的输出结果中,我们可以看到 a 及 the 没有出现。
如果我们想自定义 stop 过滤器,我们可以仿照如下的方法:
PUT stop_example
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "standard",
"filter": [
"my_stop"
]
}
},
"filter": {
"my_stop": {
"type": "stop",
"stopwords": [
"over",
"dog"
]
}
}
}
},
"mappings": {
"properties": {
"text": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
}
在上面,我们自定义了一个叫做 my_stop 的 stop 过滤器。它自己含有 over 及 dog。也就是说 over 及 dog 将不会被分词。我们使用如下的命令来进行测试:
GET stop_example/_analyze
{
"analyzer": "my_analyzer",
"text": ["a quick fox jumps over the lazy dog"]
}
上面的命令返回结果:
{
"tokens": [
{
"token": "a",
"start_offset": 0,
"end_offset": 1,
"type": "",
"position": 0
},
{
"token": "quick",
"start_offset": 2,
"end_offset": 7,
"type": "",
"position": 1
},
{
"token": "fox",
"start_offset": 8,
"end_offset": 11,
"type": "",
"position": 2
},
{
"token": "jumps",
"start_offset": 12,
"end_offset": 17,
"type": "",
"position": 3
},
{
"token": "the",
"start_offset": 23,
"end_offset": 26,
"type": "",
"position": 5
},
{
"token": "lazy",
"start_offset": 27,
"end_offset": 31,
"type": "",
"position": 6
}
]
}
从上面的结果中,我们可以看出来, dog 及 over 不见了。当然,我们也看到了 a 及 the 又同时出现了。如果我们还是想保持之前的默认的 stop 过滤器,我们可以重新设计 stop_example 索引:
DELETE stop_example
PUT stop_example
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "standard",
"filter": [
"my_stop",
"stop"
]
}
},
"filter": {
"my_stop": {
"type": "stop",
"stopwords": [
"over",
"dog"
]
}
}
}
},
"mappings": {
"properties": {
"text": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
}
由于 filter 可以是多个,而且它的执行顺序是从上而下执行的。在上面,它先执行 my_stop,然后是 stop 过滤器。我们使用同样的命令来进行测试:
GET stop_example/_analyze
{
"analyzer": "my_analyzer",
"text": ["a quick fox jumps over the lazy dog"]
}
这次显示的结果为:
{
"tokens": [
{
"token": "quick",
"start_offset": 2,
"end_offset": 7,
"type": "",
"position": 1
},
{
"token": "fox",
"start_offset": 8,
"end_offset": 11,
"type": "",
"position": 2
},
{
"token": "jumps",
"start_offset": 12,
"end_offset": 17,
"type": "",
"position": 3
},
{
"token": "lazy",
"start_offset": 27,
"end_offset": 31,
"type": "",
"position": 6
}
]
}
显然,a 和 the 不见了。
Predicate script token filter
删除与提供的谓词脚本不匹配的标记。 该过滤器仅支持内联 Painless 脚本。 在分词谓词上下文中评估脚本。
示例:
以下 analyze API 请求使用 predicate_token_filter 过滤器仅输出c从 the fox jumps the lazy dog 长于三个字符的 token。
GET /_analyze
{
"tokenizer": "whitespace",
"filter": [
{
"type": "predicate_token_filter",
"script": {
"source": """
token.term.length() > 3
"""
}
}
],
"text": "the fox jumps the lazy dog"
}
上面的命令返回的结果为:
{
"tokens": [
{
"token": "jumps",
"start_offset": 8,
"end_offset": 13,
"type": "word",
"position": 2
},
{
"token": "lazy",
"start_offset": 18,
"end_offset": 22,
"type": "word",
"position": 4
}
]
}
事实上,我们可以使用这个过滤器来实现上面描述的 length 过滤器。比如:
PUT predicate_example
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "ik_smart",
"filter": [
"my_predicate"
]
}
},
"filter": {
"my_predicate": {
"type": "predicate_token_filter",
"script": {
"source": """
token.term.length() > 1
"""
}
}
}
}
},
"mappings": {
"properties": {
"text": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
}
我们使用如下的命令来进行测试:
GET predicate_example/_analyze
{
"analyzer": "my_analyzer",
"text": ["我爱北京天安门"]
}
{
"tokens": [
{
"token": "北京",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 2
},
{
"token": "天安门",
"start_offset": 4,
"end_offset": 7,
"type": "CN_WORD",
"position": 3
}
]
}
显然只有长度是大于 1 的 token 才会显示。在实际的使用中,脚本的执行速度较慢一些。如果你的脚本的长度或计算的时间较长,我们需要注意使用。
自定义并添加到分词器
要自定义 predicate_token_filter 过滤器,复制它以创建新的自定义 token 过滤器的基础。 你可以使用其可配置参数修改过滤器。
以下创建索引 API 请求使用自定义 predicate_token_filter 过滤器 my_script_filter 配置新的自定义分词器。
my_script_filter 过滤器删除除 ALPHANUM 之外的任何类型的 token。
PUT /my-index-000001
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "standard",
"filter": [
"my_script_filter"
]
}
},
"filter": {
"my_script_filter": {
"type": "predicate_token_filter",
"script": {
"source": """
token.type.contains("ALPHANUM")
"""
}
}
}
}
}
}
Trim token filter
从流中的每个 token 中删除前导和尾随空格。 虽然这可以更改 token 的长度,但 trim 过滤器不会更改 token 的偏移量。 trim 过滤器使用 Lucene 的 TrimFilter。
例子:
要查看 trim 过滤器的工作原理,你首先需要生成一个包含空格的 token。以下 analyze API 请求使用 keywordtokenizer 为“ fox ”生成 token。
GET _analyze
{
"tokenizer" : "keyword",
"text" : " fox "
}
API 返回以下响应。 请注意,“ fox ” token 包含原始文本的空格。 请注意,尽管更改了 token 的长度,但 start_offset 和 end_offset 保持不变。
{
"tokens": [
{
"token": " fox ",
"start_offset": 0,
"end_offset": 5,
"type": "word",
"position": 0
}
]
}
要删除空格,请将 trim 过滤器添加到之前的 analyzeAPI 请求。
GET _analyze
{
"tokenizer" : "keyword",
"filter" : ["trim"],tgcode
"text" : " fox "
}
API 返回以下响应。 返回的 fox token 不包含任何前导或尾随空格。
{
"tokens": [
{
"token": "fox",
"start_offset": 0,
"end_offset": 5,
"type": "word",
"position": 0
}
]
}
以下创建索引 API 请求使用 trim 过滤器来配置新的自定义分词器。
PUT trim_example
{
"settings": {
"analysis": {
"analyzer": {
"keyword_trim": {
"tokenizer": "keyword",
"filter": [ "trim" ]
}
}
}
}
}
Synonym token filter
这是一个同义词过滤器。你可以阅读我之前的文章 “Elasticsearch:使用同义词 synonyms 来提高搜索效率”。
Truncate token filter
Truncate 超过指定字符限制的标记。 此限制默认为 10,但可以使用长度参数进行自定义。例如,你可以使用 truncate 过滤器将所有 token 缩短为 3 个字符或更少,将 jumping fox 更改为 jum fox。此过滤器使用 Lucene 的 TruncateTokenFilter。
例子:
以下 analyze API 请求使用 truncate 过滤器来缩短 quinquennial extravaganza carried on 中超过 10 个字符的标记:
GET _analyze
{
"tokenizer" : "whitespace",
"filter" : ["truncate"],
"text" : "the quinquennial extravaganza carried on"
}
上面的命令返回:
{
"tokens": [
{
"token": "the",
"start_offset": 0,
"end_offset": 3,
"type": "word",
"position": 0
},
{
"token": "quinquenni",
"start_offset": 4,
"end_offset": 16,
"type": "word",
"position": 1
},
{
"token": "extravagan",
"start_offset": 17,
"end_offset": 29,
"type": "word",
"position": 2
},
{
"token": "carried",
"start_offset": 30,
"end_offset": 37,
"type": "word",
"position": 3
},
{
"token": "on",
"start_offset": 38,
"end_offset": 40,
"type": "word",
"position": 4
}
]
}
我们可以发现 token 的长度不超过 10。10 是默认的值。
添加到分词仪
以下创建索引 API 请求使用截断过滤器来配置新的自定义分词器。
PUT customtgcode_truncate_example
{
"settings" : {
"analysis" : {
"analyzer" : {
"standard_truncate" : {
"tokenizer" : "standard",
"filter" : ["truncate"]
}
}
}
}
}
我们甚至可以针对 truncate 过滤器进行定制:
PUT 5_char_words_example
{
"settings": {
"analysis": {
"analyzer": {
"lowercase_5_char": {
"tokenizer": "lowercase",
"filter": [ "5_char_trunc" ]
}
},
"filter": {
"5_char_trunc": {
"type": "truncate",
"length": 5
}
}
}
}
}
通过对 length 参数的定制,我们可以限制 token 的长度最多不超过 5,而不是默认的 10。
Limit token count token filter
限制输出 token 的数量。 限制过滤器通常用于根据 token 计数限制文档字段值的大小。默认情况下,限制过滤器仅保留流中的第一个 token。 例如,过滤器可以将 token 流 [one、two、three] 更改为 [one]。此过滤器使用 Lucene 的 LimitTokenCountFilter。
示例:
GET _analyze
{
"tokenizer": "standard",
"filter": [
{
"type": "limit",
"max_token_count": 2
}
],
"text": "quick fox jumps over lazy dog"
}
上面的输出为:
{
"tokens": [
{
"token": "quick",
"start_offset": 0,
"end_offset": 5,
"type": "",
"position": 0
},
{
"token": "fox",
"start_offset": 6,
"end_offset": 9,
"type": "",
"position": 1
}
]
}
也就是取前面的两个 token。
添加到分词器
以下创建索引 API 请求使用 limit 过滤器来配置新的自定义分词器。
PUT limit_example
{
"settings": {
"analysis": {
"analyzer": {
"standard_one_token_limit": {
"tokenizer": "standard",
"filter": [ "limit" ]
}
}
}
}
}
我们也可以定制 limit 过滤器:
PUT custom_limit_example
{
"settings": {
"analysis": {
"analyzer": {
"whitespace_five_token_limit": {
"tokenizer": "whitespace",
"filter": [ "five_token_limit" ]
}
},
"filter": {
"five_token_limit": {
"type": "limit",
"max_token_count": 5
}
}
}
}
}
上面的max_token_count 在默认的情况下为 1。我们可以通过对它的定制来限制最多的 token 输出。
Shingle token filter
请详细阅读之前的文章 “Elasticsearch: Ngrams, edge ngrams, and shingles”。
中文相关的 filter
请详细阅读我之前的文章:
好了,今天的分享就到这里。更多的过滤器,请参阅官方文档。
参考:
【1】Token filter reference | Elasticsearch Guide [8.4] | Elastic
文章来源于互联网:Elasticsearch:分词器中的 token 过滤器使用示例