本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.
分词器在 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.
在上面,我们可以看到有一个 ’ 符号。在实际的分词中,我们希望去掉 ‘ 符号后面的所有字符。我们可以使用如下的例子来进行展示:
1. GET /_analyze 2. { 3. "tokenizer" : "standard", 4. "filter" : ["apostrophe"], 5. "text" : "Istanbul'a veya Istanbul'dan" 6. }
上面的 filter 产生如下的结果:
1. { 2. "tokens": [3. {4. "token": "Istanbul",5. "start_offset": 0,6. "end_offset": 10,7. "type": "<ALPHANUM>",8. "position": 09. },10. {11. "token": "veya",12. "start_offset": 11,13. "end_offset": 15,14. "type": "<ALPHANUM>",15. "position": 116. },17. {18. "token": "Istanbul",19. "start_offset": 16,20. "end_offset": 28,21. "type": "<ALPHANUM>",22. "position": 223. }24. ] 25. } `
在实际的使用中,我们可以使用如下的例子来进行展示:
1. PUT test 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "my_analyzer": { 7. "type": "custom", 8. "tokenizer": "standard", 9. "filter": [ 10. "apostrophe", 11. "lowercase" 12. ] 13. } 14. } 15. } 16. }, 17. "mappings": { 18. "properties": { 19. "text": { 20. "type": "text", 21. "analyzer": "my_analyzer" 22. } 23. } 24. } 25. } `
在上面,我们定义了一个叫做 test 的索引,并且它的 text 字段使用 my_analyzer。在没有特定指定 search_analyzer 的情况下,分词和搜索将使用同样的一个分词器:my_analyzer。我们使用如下的一个命令来写入一个文档:
1. PUT test/_doc/1 2. { 3. "text": "Istanbul'a veya Istanbul'dan" 4. }
那幺我们可以使用如下的一个搜索来搜索该文档:
1. GET test/_search 2. { 3. "query": { 4. "match": { 5. "text": "Istanbul" 6. } 7. } 8. }
上面的搜索结果为:
1. { 2. "tokens": [3. {4. "token": "Istanbul",5. "start_offset": 0,6. "end_offset": 10,7. "type": "<ALPHANUM>",8. "position": 09. },10. {11. "token": "veya",12. "start_offset": 11,13. "end_offset": 15,14. "type": "<ALPHANUM>",15. "position": 116. },17. {18. "token": "Istanbul",19. "start_offset": 16,20. "end_offset": 28,21. "type": "<ALPHANUM>",22. "position": 223. }24. ] 25. } `
ASCII folding token filter
将不在 Basic Latin Unicode 块中的字母、数字和符号字符(前 127 个 ASCII 字符)转换为它们的 ASCII 等效字符(如果存在)。 例如,过滤器将 à 更改为 a。
以下 analyze API 请求使用 asciifolding 过滤器删除 açaí à la carte 中的变音符号:
1. GET /_analyze 2. { 3. "tokenizer" : "standard", 4. "filter" : ["asciifolding"], 5. "text" : "açaí à la carte" 6. }
上面的命令返回:
1. { 2. "tokens": [3. {4. "token": "acai",5. "start_offset": 0,6. "end_offset": 4,7. "type": "<ALPHANUM>",8. "position": 09. },10. {11. "token": "a",12. "start_offset": 5,13. "end_offset": 6,14. "type": "<ALPHANUM>",15. "position": 116. },17. {18. "token": "la",19. "start_offset": 7,20. "end_offset": 9,21. "type": "<ALPHANUM>",22. "position": 223. },24. {25. "token": "carte",26. "start_offset": 10,27. "end_offset": 15,28. "type": "<ALPHANUM>",29. "position": 330. }31. ] 32. } `
Classic token filter
对经典分词器生成的术语执行可选的后处理。
此过滤器从单词末尾删除英语所有格 (‘s) 并从首字母缩略词中删除点。 它使用 Lucene 的ClassicFilter。例如:
1. GET /_analyze 2. { 3. "tokenizer" : "classic", 4. "filter" : ["classic"], 5. "text" : "The 2 Q.U.I.C.K. Brown-Foxes jumped over the lazy dog's bone." 6. }
上面将返回:
1. { 2. "tokens": [3. {4. "token": "The",5. "start_offset": 0,6. "end_offset": 3,7. "type": "<ALPHANUM>",8. "position": 09. },10. {11. "token": "2",12. "start_offset": 4,13. "end_offset": 5,14. "type": "<ALPHANUM>",15. "position": 116. },17. {18. "token": "QUICK",19. "start_offset": 6,20. "end_offset": 16,21. "type": "<ACRONYM>",22. "position": 223. },24. {25. "token": "Brown",26. "start_offset": 17,27. "end_offset": 22,28. "type": "<ALPHANUM>",29. "position": 330. },31. {32. "token": "Foxes",33. "start_offset": 23,34. "end_offset": 28,35. "type": "<ALPHANUM>",36. "position": 437. },38. {39. "token": "jumped",40. "start_offset": 29,41. "end_offset": 35,42. "type": "<ALPHANUM>",43. "position": 544. },45. {46. "token": "over",47. "start_offset": 36,48. "end_offset": 40,49. "type": "<ALPHANUM>",50. "position": 651. },52. {53. "token": "the",54. "start_offset": 41,55. "end_offset": 44,56. "type": "<ALPHANUM>",57. "position": 758. },59. {60. "token": "lazy",61. "start_offset": 45,62. "end_offset": 49,63. "type": "<ALPHANUM>",64. "position": 865. },66. {67. "token": "dog",68. "start_offset": 50,69. "end_offset": 55,70. "type": "<APOSTROPHE>",71. "position": 972. },73. {74. "token": "bone",75. "start_offset": 56,76. "end_offset": 60,77. "type": "<ALPHANUM>",78. "position": 1079. }80. ] 81. } `
显然,在 Q.U.I.CK. 中的点都被删除了,同时 dog’s 中的 ‘s 被去掉了。
Conditional token filter
将一组 token 过滤器应用于与提供的谓词脚本中的条件匹配的标记。此过滤器使用 Lucene 的 ConditionalTokenFilter。
以下analyze API 请求使用条件过滤器来匹配 THE QUICK BROWN FOX 中少于 5 个字符的标记。 然后它将 lowercase 过滤器应用于那些匹配的标记,将它们转换为小写。
1. GET /_analyze 2. { 3. "tokenizer": "standard", 4. "filter": [ 5. { 6. "type": "condition", 7. "filter": [ "lowercase" ], 8. "script": { 9. "source": "token.getTerm().length() < 5" 10. } 11. } 12. ], 13. "text": "THE QUICK BROWN FOX" 14. }
上面的命令返回:
1. { 2. "tokens": [3. {4. "token": "the",5. "start_offset": 0,6. "end_offset": 3,7. "type": "<ALPHANUM>",8. "position": 09. },10. {11. "token": "QUICK",12. "start_offset": 4,13. "end_offset": 9,14. "type": "<ALPHANUM>",15. "position": 116. },17. {18. "token": "BROWN",19. "start_offset": 10,20. "end_offset": 15,21. "type": "<ALPHANUM>",22. "position": 223. },24. {25. "token": "fox",26. "start_offset": 16,27. "end_offset": 19,28. "type": "<ALPHANUM>",29. "position": 330. }31. ] 32. } `
请注意上面的 script 指的是painless script。在上面,我们看到虽然有 lowercase 过滤器,但是它仅仅作用于 token 的长度小于 5 的 token 上面。从输出中,我们可以看到,BROWN 及 QUICK 并没有变为小写,原因是他们的长度是5,不满足条件。
自定义并添加到分词器
要自定义 conditional 过滤器,请将其复制以创建新的自定义标记过滤器的基础。 你可以使用其可配置参数修改过滤器。
例如,以下创建索引 API 请求使用自定义 conditional 过滤器来配置新的自定义分词器。 自定义条件过滤器匹配流中的第一个 token。 然后它使用反向过滤器反转匹配的 token。
1. PUT /palindrome_list 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "whitespace_reverse_first_token": { 7. "tokenizer": "whitespace", 8. "filter": [ "reverse_first_token" ] 9. } 10. }, 11. "filter": { 12. "reverse_first_token": { 13. "type": "condition", 14. "filter": [ "reverse" ], 15. "script": { 16. "source": "token.getPosition() === 0" 17. } 18. } 19. } 20. } 21. } 22. } `
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。例如:
以下analyze API 请求使用指纹过滤器为文本 zebra jumps over resting resting dog 创建单个输出 token:
1. GET _analyze 2. { 3. "tokenizer" : "whitespace", 4. "filter" : ["fingerprint"], 5. "text" : "zebra jumps over resting resting dog" 6. }
上面的命令返回:
1. { 2. "tokens": [ 3. { 4. "token": "dog jumps over resting zebra", 5. "start_offset": 0, 6. "end_offset": 36, 7. "type": "fingerprint", 8. "position": 0 9. } 10. ] 11. }
请注意的是它返回 仅 有一个 token。
Reverse token filter
反转流中的每个 token。 例如,你可以使用反向过滤器将 cat 更改为 tac。反转 token 对于基于后缀的搜索很有用,例如查找以 -ion 结尾的单词或按扩展名搜索文件名。请参阅我之前的文章 “ Elasticsearch:正确使用 regexp 搜索 ”。这个过滤器使用 Lucene 的ReverseStringFilter。
以下 analyze API 请求使用反向过滤器来反转 quick fox jumps 中的每个 token:
1. GET _analyze 2. { 3. "tokenizer" : "standard", 4. "filter" : ["reverse"], 5. "text" : "quick fox jumps" 6. }
上面的过滤器返回:
1. { 2. "tokens": [3. {4. "token": "kciuq",5. "start_offset": 0,6. "end_offset": 5,7. "type": "<ALPHANUM>",8. "position": 09. },10. {11. "token": "xof",12. "start_offset": 6,13. "end_offset": 9,14. "type": "<ALPHANUM>",15. "position": 116. },17. {18. "token": "spmuj",19. "start_offset": 10,20. "end_offset": 15,21. "type": "<ALPHANUM>",22. "position": 223. }24. ] 25. } `
就如第一个例子中显示的那样,我们可以使用如下的例子来定义并使用这个 filter:
1. PUT reverse_example 2. { 3. "settings" : { 4. "analysis" : { 5. "analyzer" : { 6. "whitespace_reverse" : { 7. "tokenizer" : "whitespace", 8. "filter" : ["reverse"] 9. } 10. } 11. } 12. }, 13. "mappings": { 14. "properties": { 15. "text": { 16. "type": "text", 17. "analyzer": "whitespace_reverse" 18. } 19. } 20. } 21. } `
我们可以使用如下的命令来写入一个文档:
1. PUT reverse_example/_doc/1 2. { 3. "text": "I like the speed of this network" 4. }
我们可以使用如下的方法来进行搜索:
1. GET reverse_example/_search 2. { 3. "query": { 4. "regexp": { 5. "text": "krow.*" 6. } 7. } 8. }
特别需要指出的是:当我们使用通配符在前面进行搜索时搜索比较慢。这个时候,我们可以选择 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 过滤器相同。
我们使用如下的例子来进行展示:
1. GET _analyze 2. { 3. "tokenizer" : "whitespace", 4. "filter" : ["unique"], 5. "text" : "the quick fox jumps the lazy fox" 6. }
上面的命令返回:
1. { 2. "tokens": [3. {4. "token": "the",5. "start_offset": 0,6. "end_offset": 3,7. "type": "word",8. "position": 09. },10. {11. "token": "quick",12. "start_offset": 4,13. "end_offset": 9,14. "type": "word",15. "position": 116. },17. {18. "token": "fox",19. "start_offset": 10,20. "end_offset": 13,21. "type": "word",22. "position": 223. },24. {25. "token": "jumps",26. "start_offset": 14,27. "end_offset": 19,28. "type": "word",29. "position": 330. },31. {32. "token": "lazy",33. "start_offset": 24,34. "end_offset": 28,35. "type": "word",36. "position": 437. }38. ] 39. } `
显然上面的返回中,只有一个 fox,而在原文档中有两个 fox。我们可以通过如下的方式来添加这个过滤器到 analyzer 中:
1. PUT custom_unique_example 2. { 3. "settings" : { 4. "analysis" : { 5. "analyzer" : { 6. "standard_truncate" : { 7. "tokenizer" : "standard", 8. "filter" : ["unique"] 9. } 10. } 11. } 12. } 13. }
我们可以通过如下的方式来定制这个过滤器:
1. PUT letter_unique_pos_example 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "letter_unique_pos": { 7. "tokenizer": "letter", 8. "filter": [ "unique_pos" ] 9. } 10. }, 11. "filter": { 12. "unique_pos": { 13. "type": "unique", 14. "only_on_same_position": true 15. } 16. } 17. } 18. } 19. } `
在上面,我们设置 only_on_same_position 为 true。在默认的情况下,这个值为 false。
Length token filter
删除比指定字符长度更短或更长的标记。 例如,你可以使用长度过滤器来排除短于 2 个字符的标记和长于 5 个字符的标记。此过滤器使用 Lucene 的LengthFilter。
提示:长度过滤器删除整个 token。 如果你希望将 token 缩短到特定长度,请使用truncate 过滤器。
例如:
1. GET _analyze 2. { 3. "tokenizer": "whitespace", 4. "filter": [ 5. { 6. "type": "length", 7. "min": 0, 8. "max": 4 9. } 10. ], 11. "text": "the quick brown fox jumps over the lazy dog" 12. }
上面的命令返回长度为 0 到 4 的 token:
1. { 2. "tokens": [3. {4. "token": "the",5. "start_offset": 0,6. "end_offset": 3,7. "type": "word",8. "position": 09. },10. {11. "token": "fox",12. "start_offset": 16,13. "end_offset": 19,14. "type": "word",15. "position": 316. },17. {18. "token": "over",19. "start_offset": 26,20. "end_offset": 30,21. "type": "word",22. "position": 523. },24. {25. "token": "the",26. "start_offset": 31,27. "end_offset": 34,28. "type": "word",29. "position": 630. },31. {32. "token": "lazy",33. "start_offset": 35,34. "end_offset": 39,35. "type": "word",36. "position": 737. },38. {39. "token": "dog",40. "start_offset": 40,41. "end_offset": 43,42. "type": "word",43. "position": 844. }45. ] 46. } `
这个过滤器对中文也有很多的帮助。比如,我们只想有超过两个字的中文 token:
1. PUT twitter 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "my_analyzer": { 7. "tokenizer": "ik_smart", 8. "filter": [ 9. "longer_than_2" 10. ] 11. } 12. }, 13. "filter": { 14. "longer_than_2": { 15. "type": "length", 16. "min": 2 17. } 18. } 19. } 20. }, 21. "mappings": { 22. "properties": { 23. "text": { 24. "type": "text", 25. "analyzer": "my_analyzer" 26. } 27. } 28. } 29. } `
我们使用上面的索引来进行测试:
1. GET twitter/_analyze 2. { 3. "analyzer": "my_analyzer", 4. "text": ["我爱北京天安门"] 5. }
上面的命令返回:
1. { 2. "tokens": [3. {4. "token": "北京",5. "start_offset": 2,6. "end_offset": 4,7. "type": "CN_WORD",8. "position": 29. },10. {11. "token": "天安门",12. "start_offset": 4,13. "end_offset": 7,14. "type": "CN_WORD",15. "position": 316. }17. ] 18. } `
显然它只返回 “北京” 及 “天安门” 这个两个长度超过 2 的 token。我们和如下的分词进行比较:
1. GET _analyze 2. { 3. "analyzer": "ik_smart", 4. "text": ["我爱北京天安门"] 5. }
1. { 2. "tokens": [3. {4. "token": "我",5. "start_offset": 0,6. "end_offset": 1,7. "type": "CN_CHAR",8. "position": 09. },10. {11. "token": "爱",12. "start_offset": 1,13. "end_offset": 2,14. "type": "CN_CHAR",15. "position": 116. },17. {18. "token": "北京",19. "start_offset": 2,20. "end_offset": 4,21. "type": "CN_WORD",22. "position": 223. },24. {25. "token": "天安门",26. "start_offset": 4,27. "end_offset": 7,28. "type": "CN_WORD",29. "position": 330. }31. ] 32. } `
很显然,当我们写入如下的文档:
1. PUT twitter/_doc/1 2. { 3. "text": "我爱北京天安门" 4. }
我们使用如下的命令来进行搜索:
1. GET twitter/_search 2. { 3. "query": { 4. "match": { 5. "text": "我" 6. } 7. } 8. }
它将不返回任何的文档,但是如果我们使用如下的命令来进行搜索:
1. GET twitter/_search 2. { 3. "query": { 4. "match": { 5. "text": "北京" 6. } 7. } 8. }
它将返回我们的文档。
Lower token filter
将 token 文本更改为小写。 例如,你可以使用 lowercase 过滤器将 THE Lazy DoG 更改为 the lazy dog。
除了默认过滤器之外,lowercase token 过滤器还提供对 Lucene 的希腊语、爱尔兰语和土耳其语的特定语言小写过滤器的访问。
例如:
1. GET _analyze 2. { 3. "tokenizer" : "standard", 4. "filter" : ["lowercase"], 5. "text" : "THE Quick FoX JUMPs" 6. }
上面的命令返回:
1. { 2. "tokens": [3. {4. "token": "the",5. "start_offset": 0,6. "end_offset": 3,7. "type": "<ALPHANUM>",8. "position": 09. },10. {11. "token": "quick",12. "start_offset": 4,13. "end_offset": 9,14. "type": "<ALPHANUM>",15. "position": 116. },17. {18. "token": "fox",19. "start_offset": 10,20. "end_offset": 13,21. "type": "<ALPHANUM>",22. "position": 223. },24. {25. "token": "jumps",26. "start_offset": 14,27. "end_offset": 19,28. "type": "<ALPHANUM>",29. "position": 330. }31. ] 32. } `
很显然,它把上面的大写字母都变为小写的了。
Upercase token filter
将 token 文本更改为大写。 例如,你可以使用大写过滤器将 Lazy Dog 更改为 THE LAZY DOG。此过滤器使用 Lucene 的UpperCaseFilter。
以下 analyze API 请求使用默认 uppercase 过滤器将 Quick FoX JUMP 更改为大写:
1. GET _analyze 2. { 3. "tokenizer" : "standard", 4. "filter" : ["uppercase"], 5. "text" : "the Quick FoX JUMPs" 6. }
上面的命令返回结果:
1. { 2. "tokens": [3. {4. "token": "THE",5. "start_offset": 0,6. "end_offset": 3,7. "type": "<ALPHANUM>",8. "position": 09. },10. {11. "token": "QUICK",12. "start_offset": 4,13. "end_offset": 9,14. "type": "<ALPHANUM>",15. "position": 116. },17. {18. "token": "FOX",19. "start_offset": 10,20. "end_offset": 13,21. "type": "<ALPHANUM>",22. "position": 223. },24. {25. "token": "JUMPS",26. "start_offset": 14,27. "end_offset": 19,28. "type": "<ALPHANUM>",29. "position": 330. }31. ] 32. } `
以下创建索引 API 请求使用 upercase 过滤器来配置新的自定义分词器。
1. PUT uppercase_example 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "whitespace_uppercase": { 7. "tokenizer": "whitespace", 8. "filter": [ "uppercase" ] 9. } 10. } 11. } 12. } 13. }
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:
1. GET /_analyze 2. { 3. "tokenizer": "standard", 4. "filter": [ "stop" ], 5. "text": "a quick fox jumps over the lazy dog" 6. }
上面的命令返回结果:
1. { 2. "tokens": [3. {4. "token": "quick",5. "start_offset": 2,6. "end_offset": 7,7. "type": "<ALPHANUM>",8. "position": 19. },10. {11. "token": "fox",12. "start_offset": 8,13. "end_offset": 11,14. "type": "<ALPHANUM>",15. "position": 216. },17. {18. "token": "jumps",19. "start_offset": 12,20. "end_offset": 17,21. "type": "<ALPHANUM>",22. "position": 323. },24. {25. "token": "over",26. "start_offset": 18,27. "end_offset": 22,28. "type": "<ALPHANUM>",29. "position": 430. },31. {32. "token": "lazy",33. "start_offset": 27,34. "end_offset": 31,35. "type": "<ALPHANUM>",36. "position": 637. },38. {39. "token": "dog",40. "start_offset": 32,41. "end_offset": 35,42. "type": "<ALPHANUM>",43. "position": 744. }45. ] 46. } `
从上面的输出结果中,我们可以看到 a 及 the 没有出现。
如果我们想自定义 stop 过滤器,我们可以仿照如下的方法:
1. PUT stop_example 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "my_analyzer": { 7. "tokenizer": "standard", 8. "filter": [ 9. "my_stop" 10. ] 11. } 12. }, 13. "filter": { 14. "my_stop": { 15. "type": "stop", 16. "stopwords": [ 17. "over", 18. "dog" 19. ] 20. } 21. } 22. } 23. }, 24. "mappings": { 25. "properties": { 26. "text": { 27. "type": "text", 28. "analyzer": "my_analyzer" 29. } 30. } 31. } 32. } `
在上面,我们自定义了一个叫做 my_stop 的 stop 过滤器。它自己含有 over 及 dog。也就是说 over 及 dog 将不会被分词。我们使用如下的命令来进行测试:
1. GET stop_example/_analyze 2. { 3. "analyzer": "my_analyzer", 4. "text": ["a quick fox jumps over the lazy dog"] 5. }
上面的命令返回结果:
1. { 2. "tokens": [3. {4. "token": "a",5. "start_offset": 0,6. "end_offset": 1,7. "type": "<ALPHANUM>",8. "position": 09. },10. {11. "token": "quick",12. "start_offset": 2,13. "end_offset": 7,14. "type": "<ALPHANUM>",15. "position": 116. },17. {18. "token": "fox",19. "start_offset": 8,20. "end_offset": 11,21. "type": "<ALPHANUM>",22. "position": 223. },24. {25. "token": "jumps",26. "start_offset": 12,27. "end_offset": 17,28. "type": "<ALPHANUM>",29. "position": 330. },31. {32. "token": "the",33. "start_offset": 23,34. "end_offset": 26,35. "type": "<ALPHANUM>",36. "position": 537. },38. {39. "token": "lazy",40. "start_offset": 27,41. "end_offset": 31,42. "type": "<ALPHANUM>",43. "position": 644. }45. ] 46. } `
从上面的结果中,我们可以看出来, dog 及 over 不见了。当然,我们也看到了 a 及 the 又同时出现了。如果我们还是想保持之前的默认的 stop 过滤器,我们可以重新设计 stop_example 索引:
1. DELETE stop_example 3. PUT stop_example 4. { 5. "settings": { 6. "analysis": { 7. "analyzer": { 8. "my_analyzer": { 9. "tokenizer": "standard", 10. "filter": [ 11. "my_stop", 12. "stop" 13. ] 14. } 15. }, 16. "filter": { 17. "my_stop": { 18. "type": "stop", 19. "stopwords": [ 20. "over", 21. "dog" 22. ] 23. } 24. } 25. } 26. }, 27. "mappings": { 28. "properties": { 29. "text": { 30. "type": "text", 31. "analyzer": "my_analyzer" 32. } 33. } 34. } 35. } `
由于 filter 可以是多个,而且它的执行顺序是从上而下执行的。在上面,它先执行 my_stop,然后是 stop 过滤器。我们使用同样的命令来进行测试:
1. GET stop_example/_analyze 2. { 3. "analyzer": "my_analyzer", 4. "text": ["a quick fox jumps over the lazy dog"] 5. }
这次显示的结果为:
1. { 2. "tokens": [3. {4. "token": "quick",5. "start_offset": 2,6. "end_offset": 7,7. "type": "<ALPHANUM>",8. "position": 19. },10. {11. "token": "fox",12. "start_offset": 8,13. "end_offset": 11,14. "type": "<ALPHANUM>",15. "position": 216. },17. {18. "token": "jumps",19. "start_offset": 12,20. "end_offset": 17,21. "type": "<ALPHANUM>",22. "position": 323. },24. {25. "token": "lazy",26. "start_offset": 27,27. "end_offset": 31,28. "type": "<ALPHANUM>",29. "position": 630. }31. ] 32. } `
显然,a 和 the 不见了。
Predicate script token filter
删除与提供的谓词脚本不匹配的标记。 该过滤器仅支持内联 Painless 脚本。 在分词谓词上下文中评估脚本。
示例:
以下 analyze API 请求使用 predicate_token_filter 过滤器仅输出c从 the fox jumps the lazy dog 长于三个字符的 token。
1. GET /_analyze 2. { 3. "tokenizer": "whitespace", 4. "filter": [ 5. { 6. "type": "predicate_token_filter", 7. "script": { 8. "source": """ 9. token.term.length() > 3 10. """ 11. } 12. } 13. ], 14. "text": "the fox jumps the lazy dog" 15. } `
上面的命令返回的结果为:
1. { 2. "tokens": [3. {4. "token": "jumps",5. "start_offset": 8,6. "end_offset": 13,7. "type": "word",8. "position": 29. },10. {11. "token": "lazy",12. "start_offset": 18,13. "end_offset": 22,14. "type": "word",15. "position": 416. }17. ] 18. } `
事实上,我们可以使用这个过滤器来实现上面描述的 length 过滤器。比如:
1. PUT predicate_example 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "my_analyzer": { 7. "tokenizer": "ik_smart", 8. "filter": [ 9. "my_predicate" 10. ] 11. } 12. }, 13. "filter": { 14. "my_predicate": { 15. "type": "predicate_token_filter", 16. "script": { 17. "source": """ 18. token.term.length() > 1 19. """ 20. } 21. } 22. } 23. } 24. }, 25. "mappings": { 26. "properties": { 27. "text": { 28. "type": "text", 29. "analyzer": "my_analyzer" 30. } 31. } 32. } 33. } `
我们使用如下的命令来进行测试:
1. GET predicate_example/_analyze 2. { 3. "analyzer": "my_analyzer", 4. "text": ["我爱北京天安门"] 5. }
1. { 2. "tokens": [3. {4. "token": "北京",5. "start_offset": 2,6. "end_offset": 4,7. "type": "CN_WORD",8. "position": 29. },10. {11. "token": "天安门",12. "start_offset": 4,13. "end_offset": 7,14. "type": "CN_WORD",15. "position": 316. }17. ] 18. } `
显然只有长度是大于 1 的 token 才会显示。在实际的使用中,脚本的执行速度较慢一些。如果你的脚本的长度或计算的时间较长,我们需要注意使用。
自定义并添加到分词器
要自定义 predicate_token_filter 过滤器,复制它以创建新的自定义 token 过滤器的基础。 你可以使用其可配置参数修改过滤器。
以下创建索引 API 请求使用自定义 predicate_token_filter 过滤器 my_script_filter 配置新的自定义分词器。
my_script_filter 过滤器删除除 ALPHANUM 之外的任何类型的 token。
1. PUT /my-index-000001 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "my_analyzer": { 7. "tokenizer": "standard", 8. "filter": [ 9. "my_script_filter" 10. ] 11. } 12. }, 13. "filter": { 14. "my_script_filter": { 15. "type": "predicate_token_filter", 16. "script": { 17. "source": """ 18. token.type.contains("ALPHANUM") 19. """ 20. } 21. } 22. } 23. } 24. } 25. } `
Trim token filter
从流中的每个 token 中删除前导和尾随空格。 虽然这可以更改 token 的长度,但 trim 过滤器不会更改 token 的偏移量。 trim 过滤器使用 Lucene 的TrimFilter。
例子:
要查看 trim 过滤器的工作原理,你首先需要生成一个包含空格的 token。以下 analyze API 请求使用keywordtokenizer 为“ fox ”生成 token。
1. GET _analyze 2. { 3. "tokenizer" : "keyword", 4. "text" : " fox " 5. }
API 返回以下响应。 请注意,“ fox ” token 包含原始文本的空格。 请注意,尽管更改了 token 的长度,但 start_offset 和 end_offset 保持不变。
1. { 2. "tokens": [ 3. { 4. "token": " fox ", 5. "start_offset": 0, 6. "end_offset": 5, 7. "type": "word", 8. "position": 0 9. } 10. ] 11. }
要删除空格,请将 trim 过滤器添加到之前的 analyze API 请求。
1. GET _analyze 2. { 3. "tokenizer" : "keyword", 4. "filter" : ["trim"], 5. "text" : " fox " 6. }
API 返回以下响应。 返回的 fox token 不包含任何前导或尾随空格。
1. { 2. "tokens": [ 3. { 4. "token": "fox", 5. "start_offset": 0, 6. "end_offset": 5, 7. "type": "word", 8. "position": 0 9. } 10. ] 11. }
以下创建索引 API 请求使用 trim 过滤器来配置新的自定义分词器。
1. PUT trim_example 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "keyword_trim": { 7. "tokenizer": "keyword", 8. "filter": [ "trim" ] 9. } 10. } 11. } 12. } 13. }
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 个字符的标记:
1. GET _analyze 2. { 3. "tokenizer" : "whitespace", 4. "filter" : ["truncate"], 5. "text" : "the quinquennial extravaganza carried on" 6. }
上面的命令返回:
1. { 2. "tokens": [3. {4. "token": "the",5. "start_offset": 0,6. "end_offset": 3,7. "type": "word",8. "position": 09. },10. {11. "token": "quinquenni",12. "start_offset": 4,13. "end_offset": 16,14. "type": "word",15. "position": 116. },17. {18. "token": "extravagan",19. "start_offset": 17,20. "end_offset": 29,21. "type": "word",22. "position": 223. },24. {25. "token": "carried",26. "start_offset": 30,27. "end_offset": 37,28. "type": "word",29. "position": 330. },31. {32. "token": "on",33. "start_offset": 38,34. "end_offset": 40,35. "type": "word",36. "position": 437. }38. ] 39. } `
我们可以发现 token 的长度不超过 10。10 是默认的值。
添加到分词仪
以下创建索引 API 请求使用截断过滤器来配置新的自定义分词器。
1. PUT custom_truncate_example 2. { 3. "settings" : { 4. "analysis" : { 5. "analyzer" : { 6. "standard_truncate" : { 7. "tokenizer" : "standard", 8. "filter" : ["truncate"] 9. } 10. } 11. } 12. } 13. }
我们甚至可以针对 truncate 过滤器进行定制:
1. PUT 5_char_words_example 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "lowercase_5_char": { 7. "tokenizer": "lowercase", 8. "filter": [ "5_char_trunc" ] 9. } 10. }, 11. "filter": { 12. "5_char_trunc": { 13. "type": "truncate", 14. "length": 5 15. } 16. } 17. } 18. } 19. } `
通过对 length 参数的定制,我们可以限制 token 的长度最多不超过 5,而不是默认的 10。
Limit token count token filter
限制输出 token 的数量。 限制过滤器通常用于根据 token 计数限制文档字段值的大小。默认情况下,限制过滤器仅保留流中的第一个 token。 例如,过滤器可以将 token 流 [one、two、three] 更改为 [one]。此过滤器使用 Lucene 的 LimitTokenCountFilter 。
示例:
1. GET _analyze 2. { 3. "tokenizer": "standard", 4. "filter": [ 5. { 6. "type": "limit", 7. "max_token_count": 2 8. } 9. ], 10. "text": "quick fox jumps over lazy dog" 11. }
上面的输出为:
1. { 2. "tokens": [3. {4. "token": "quick",5. "start_offset": 0,6. "end_offset": 5,7. "type": "<ALPHANUM>",8. "position": 09. },10. {11. "token": "fox",12. "start_offset": 6,13. "end_offset": 9,14. "type": "<ALPHANUM>",15. "position": 116. }17. ] 18. } `
也就是取前面的两个 token。
添加到分词器
以下创建索引 API 请求使用 limit 过滤器来配置新的自定义分词器。
1. PUT limit_example 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "standard_one_token_limit": { 7. "tokenizer": "standard", 8. "filter": [ "limit" ] 9. } 10. } 11. } 12. } 13. }
我们也可以定制 limit 过滤器:
1. PUT custom_limit_example 2. { 3. "settings": { 4. "analysis": { 5. "analyzer": { 6. "whitespace_five_token_limit": { 7. "tokenizer": "whitespace", 8. "filter": [ "five_token_limit" ] 9. } 10. }, 11. "filter": { 12. "five_token_limit": { 13. "type": "limit", 14. "max_token_count": 5 15. } 16. } 17. } 18. } 19. } `
上面的 max_token_count 在默认的情况下为 1。我们可以通过对它的定制来限制最多的 token 输出。
Shingle token filter
请详细阅读之前的文章 “ Elasticsearch: Ngrams, edge ngrams, and shingles ”。
中文相关的 filter
请详细阅读我之前的文章:
Elasticsearch:简体繁体转换分词器 – STConvert analysis
好了,今天的分享就到这里。更多的过滤器,请参阅官方文档。
参考:
【1】 Token filter reference | Elasticsearch Guide [8.4] | Elastic
Be First to Comment