ES查询返回空数组时,应先确认索引是否存在(HEAD)、文档数量(_count)、字段类型与可搜索性(_mapping、_field_caps)、查询DSL是否匹配类型、Laravel Scout同步状态及mapping是否重建。

查索引是否存在且有数据
ES 返回空数组,第一反应不该是代码写错,而是先确认目标索引压根有没有、里面有没有文档。很多“查不到”本质是 index_not_found_exception 被静默吞掉,或客户端没抛错只返回空 hits。
- 用
HEAD /your-index-name检查索引是否存在(返回 200 表示存在,404 表示不存在) - 用
GET /your-index-name/_count看文档数,别信hits.total.value—— 它可能被缓存或统计延迟误导 - 如果用别名(如
goods-alias),得查GET /goods-alias/_count,而不是底层索引名 - 别名指向多个索引时,加
?ignore_unavailable=true避免因某个索引不可用导致整个请求失败
确认字段类型和可搜索性
字段明明有值,但搜不出来?大概率是字段类型不对或没开启搜索能力。ES 不像 MySQL,text 和 keyword 行为完全不同,且默认不开启 searchable。
- 运行
GET /your-index-name/_mapping查看cateName字段类型:如果是"type": "keyword",就得用term查询;如果是"type": "text",才支持match或短语查询 - 用
GET /your-index-name/_field_caps?fields=cateName看响应里"searchable": true是否为true;若为false,说明该字段未被索引(即使有值也搜不到) - 特别注意:Laravel Scout 默认把字符串映射为
text,但如果你手动改过 mapping,又没重建索引,旧文档不会自动重索引
验证查询 DSL 是否匹配字段类型
同一个字段,term 和 match 不能混用。搜 “开关” 返回空,但搜单字 “开” 有结果?基本就是用了 term 去查 text 字段——term 是精确匹配分词后的词条,而中文分词后 “开关” 很可能被拆成 “开”、“关”,导致无法命中。
- 对
text字段,必须用match、match_phrase或multi_match - 对
keyword字段,才用term、terms、prefix - Laravel Scout 的
search()默认走match,但如果你在自定义引擎里硬写了term查询,就得同步改字段类型或换查询方式 - 聚合返回空数组?检查是否对
text字段做了terms聚合——必须用其.keyword子字段,例如"field": "cateName.keyword"
排查 Laravel Scout 数据同步状态
ES 里有数据,但 Laravel 查不到?不是 ES 问题,是 Scout 没把数据导进去。Scout 不是实时双写,它依赖 scout:import 或模型事件触发同步。
- 运行
php artisan scout:import "App\Models\Goods"手动触发导入,别只信“保存时自动同步”——中间件、事务、队列失败都会导致漏同步 - 检查模型是否实现了
Searchabletrait,且没被shouldBeSearchable()拦截(比如条件返回false) - 如果用了队列,确认
SCOUT_QUEUE=true且队列服务正常消费;否则数据会卡在队列里,ES 始终为空 - 别用
elasticquent这类老包——它不兼容 ES 6+,同步逻辑早已失效,scout:import可能静默失败
最常被忽略的点:mapping 改了但没重建索引,或重建了索引但没重新导入数据。ES 不会自动把旧文档按新 mapping 重索引,这一步必须手动做。


















