prefix查询仅匹配字段开头且要求字段为keyword类型,不支持分词、通配符或大小写自动转换;suffix需通过反转字段+prefix实现;wildcard慎用前缀通配符;laravel中需正确构造dsl并验证mapping。

prefix 查询只匹配字段开头,别误用成全文模糊
ES 的 prefix 查询不是“包含前缀”,而是严格从字段值开头匹配——比如字段存 "apple-pie-2024",prefix 查 "apple" 能命中,查 "pie" 或 "2024" 完全无效。它底层走的是 keyword 类型的前缀索引,不经过分词器,也不支持通配符展开。
常见错误是拿它替代 wildcard 或 query_string 做中间/结尾匹配,结果查不到数据还怀疑 mapping 没生效。
- 必须确保字段 mapping 是
"type": "keyword",text 类型字段即使设了index_options: "offsets"也无效 - 不支持大小写自动转换,输入
"Apple"查不到小写开头的值,除非你建索引时用了 lowercase tokenizer - 性能虽好,但无法组合布尔逻辑(比如不能直接 and 一个
range),得包进bool/filter里
suffix 查询不存在,得靠 reverse + prefix 曲线救国
ES 官方没有 suffix 查询,因为倒排索引天生不适合尾部匹配。真要查结尾字符(如所有以 "-v2" 结尾的 SKU),唯一可靠办法是:在索引时把字段值反转,查询时也反转关键词,再用 prefix。
例如原始值 "sku-123-v2" → 存为 "2v-321-ukS";用户搜 "-v2" → 反转成 "2v-" → prefix 查 "2v-"。
- 反转逻辑必须在 ingest pipeline 或应用层完成,不能靠查询时 runtime script(9.x 已默认禁用)
- 反转字段需单独定义,比如
sku_reversed,mapping 明确设为keyword - 别试图用
regexp模拟 suffix,正则在大数据量下极易超时,且无法利用索引
首尾都查?用 wildcard 要慎设通配符位置
如果既要开头又要结尾(如 "abc*xyz"),wildcard 是最直白的选择,但性能代价明显。关键不是能不能写,而是怎么写才不至于拖垮集群:
- 前缀通配符(
*abc)禁止出现——它会强制扫描全部 term,9.x 默认已限流或拒绝 - 只允许后缀通配符(
abc*)或中缀(ab*c),且*前至少要有 3 个确定字符(避免爆炸式 expansion) - 字段必须是
keyword类型;text字段即使开了fielddata,wildcard 也无法命中分词后的碎片 - 线上环境务必加
"rewrite": "constant_score",否则评分计算会进一步放大开销
Laravel 中构造 prefix 查询的实操要点
用原生 ES 客户端(elasticsearch/elasticsearch)比 Scout 更可控,尤其对 prefix 这种简单但易错的查询:
- 参数必须扁平化传入,不能嵌套在
must里:['prefix' => ['field_name' => 'value']],不是['prefix' => ['field_name' => ['value' => 'xxx']]] - 若字段名含点号(如
"product.sku"),ES 9.x 要求显式加引号:'"product.sku"',否则解析失败 - 多个 prefix 条件要放
bool/filter下,别混进must——它不参与评分,放错位置会导致_score异常或缓存失效 - PHP 中拼 DSL 时,用
json_encode($body, JSON_UNESCAPED_UNICODE)避免中文被转义成 \uXXXX,影响调试
真正容易被忽略的是字段类型的硬约束:哪怕你 query 写得完全正确,只要 mapping 里该字段是 text 且没配 fields.keyword,prefix 就永远返回空。检查方式不是看文档,而是 GET /index/_mapping 看实际 type。











