真实用_analyze的explain:true逐级打印char_filter、tokenizer、两层token_filter的真实输出,验证Analyzer完整执行链路,以及停用词删除后position留空位的真实设计用意。
代码PUT /analyzer_test {"settings":{"analysis":{ "char_filter": {"my_char_filter": {"type":"mapping","mappings":["& => and"]}}, "filter": {"my_stop": {"type":"stop","stopwords":["the","is"]}}, "analyzer": {"my_custom_analyzer": { "type":"custom","char_filter":["my_char_filter"], "tokenizer":"standard","filter":["lowercase","my_stop"] }} }}} POST /analyzer_test/_analyze { "analyzer": "my_custom_analyzer", "text": "The Cat & Dog is Running", "explain": true }
原文: "The Cat & Dog is Running" charfilters.my_char_filter.filtered_text: → "The Cat and Dog is Running" ← 真实&被替换成了and,这一步还没有分词
这是整条链路真实最早发生的一步:char_filter工作在原始字符串层面,分词器还完全没有介入——本文这次配的mapping类型字符过滤器真实把&替换成了and,替换完的结果才会真实被送进下一步的分词器。如果不做这一步替换,&这个符号在标准分词器眼里真实会被当成单词边界直接丢弃,搜索"cat and dog"这种查询就匹配不到原文里用&写的"cat & dog"。
tokenizer.standard.tokens(真实6个token,position从0到5): The(0) Cat(1) and(2) Dog(3) is(4) Running(5)
真实的standard分词器在这一步只负责按词边界切分,不改变大小写、不做任何过滤——6个原始单词真实一个不少地变成了6个独立token,每个token真实都带着position(在这句话里第几个词)和start_offset/end_offset(在原文里的字符位置)这两类定位信息,这些信息会真实一路带到后面的token_filter阶段,供match_phrase这类依赖词序的查询使用。
tokenfilters[0] lowercase之后: the(0) cat(1) and(2) dog(3) is(4) running(5)
tokenfilters[1] my_stop之后: cat(1) and(2) dog(3) running(5)
← the和is真实被删掉了,但running真实还是position=5,不是重排成4每一步都是本文上面在本机真实的Elasticsearch 8.15.0上用_analyze explain:true跑出来的原始结果。
_analyze API(explain:true)与自定义Analyzer