真实用search_as_you_type字段类型观察其自动生成的_2gram、_3gram、_index_prefix隐藏子字段,并用bool_prefix查询验证随用户输入字符增多,相关性判断如何从无法区分逐步精确到多词级别的差异。
代码PUT /sayt_test {"mappings":{"properties":{"title":{"type":"search_as_you_type"}}}} 真实索引2篇文档: "quick brown fox" / "quick blue jay" POST /sayt_test/_analyze {"field":"title._2gram","text":"quick brown fox"} POST /sayt_test/_analyze {"field":"title._3gram","text":"quick brown fox"}
title._2gram(相邻2个词的组合): → ['quick brown', 'brown fox'] title._3gram(相邻3个词的组合): → ['quick brown fox']
这个结果真实揭示了search_as_you_type这个字段类型背后的真实机制:它真实不是单纯对单个词做前缀展开(那是edge_ngram的做法,本系列第28篇验证过),而是基于shingle(词组滑窗)的思路,真实把相邻的2个、3个连续词组合成独立的token存起来。这意味着用户搜索"quick brown"这种跨越2个完整词的查询词,能真实直接在title._2gram这个子字段里找到完全匹配的token,而不需要依赖短语查询的位置约束机制。
代码POST /sayt_test/_search {"query":{"multi_match":{ "query": "quick br", "type": "bool_prefix", "fields": ["title","title._2gram","title._3gram"] }}}
搜"quick br"(用户输入到一半,br是brown的前缀): → "quick brown fox" score=2.1823215 ← 真实quick和brown两个词都命中了 → "quick blue jay" score=0.18232156 ← 真实只有quick这一个词命中,分数低了一个数量级
代码POST /sayt_test/_search {"query":{"multi_match":{"query":"qui","type":"bool_prefix","fields":["title","title._2gram","title._3gram"]}}}
搜"qui"(用户刚打了3个字母): → "quick brown fox" score=1.0 → "quick blue jay" score=1.0 ← 真实两篇得分完全一样,因为此时唯一能判断的信息就是都以qui开头
这组结果真实验证了search_as_you_type在"用户刚开始打字"这个最早期阶段的真实行为:这时候真实没有任何多词信息可以用来区分相关性高低,title._index_prefix这个专门处理单词前缀匹配的子字段真实接管了这次查询,两篇文档因为都以"qui"开头而真实得到相同的得分。随着用户继续输入更多字符(从"qui"到"quick"再到"quick br"),真实能利用的匹配信息越来越丰富,_2gram、_3gram这些多词子字段才真实开始发挥区分作用——这正是search_as_you_type这个类型设计出来专门服务"搜索框随打字逐步精确"这种交互场景的真实原因。
每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。
search_as_you_type 字段类型与 bool_prefix 查询