term查不到数据的根本原因是字段类型非keyword,如status被映射为text会分词导致无法原样匹配,需确认mapping为keyword或使用status.keyword后缀。

直接用 term 查询,但必须确保字段是 keyword 类型,否则会查不到结果。
为什么 term 查不到数据?
常见现象:明明文档里有 "status": "published",用 term 却返回空数组。
根本原因不是语法错,而是字段类型不对——如果 status 被映射为 text(默认行为),ES 会先分词,存进去的是 ["published"],但分词器可能做了小写转换或去标点,导致原始值无法原样匹配。
实操建议:
- 检查 mapping:
GET /products/_mapping,确认目标字段的"type"是"keyword",不是"text" - 若已是
text,需同时查status.keyword(前提是启用了fields: { keyword: { type: keyword } }) - 新建索引时显式定义:
"status": { "type": "keyword" },避免依赖默认行为
Laravel 中调用 term 的正确写法
不推荐用 Scout 封装层做精确匹配,它容易把 term 自动转成 match 或加额外过滤逻辑;直接用官方客户端最稳。
示例(使用 elasticsearch/elasticsearch 客户端):
$client = app('elasticsearch');
$response = $client->search([
'index' => 'products',
'body' => [
'query' => [
'term' => [
'category.keyword' => 'electronics' // 注意 .keyword 后缀
]
]
]
]);
关键点:
- 字段名带
.keyword后缀是硬性要求,除非你 100% 确认该字段 mapping 就是keyword类型 - 值不能带通配符、不能分词——
"electronics*"或"Electronics"(大小写不一致)都会失败 - 布尔值、数字、日期也走
term,例如:['in_stock' => true]或['price' => 99]
和 match 混用时的典型陷阱
错误做法:在同一个 bool 查询里,把 term 放进 must 块,又把全文检索也塞进去,结果评分被拉低、缓存失效。
正确拆分方式(Laravel 中构造 bool 查询):
'query' => [
'bool' => [
'must' => [
['multi_match' => ['query' => $q, 'fields' => ['title^3', 'desc']]]
],
'filter' => [ // 这里放 term、range、exists 等确定性条件
['term' => ['status.keyword' => 'published']],
['range' => ['price' => ['gte' => 0]]]
]
]
]
注意:
-
filter不参与相关度计算,可被缓存,性能更好 -
must里的term会参与打分,且无法利用 filter 缓存,纯属浪费 - ES 9.x 强制要求
bool必须显式区分must/filter/should,混用会报错
真正难的不是写对一行 term,而是从建索引那一刻就规划好字段类型、提前验证 mapping、并在查询层严格区分语义——漏掉任意一环,term 就只是个摆设。


















