es查询中用_source.includes可精确返回指定字段(如id、title、status),需写完整路径,不支持模糊匹配;若字段未在tosearchablearray()中同步或mapping未设store:true,则无法返回。

ES 查询时用 _source.includes 精确控制返回字段
想让 Elasticsearch 只返回 id、title、status,其他一概不带?别靠应用层后处理,直接在查询 DSL 里用 _source.includes。它比全量查再 array_filter 快得多,也省带宽。
-
_source.includes是白名单机制:只返回列出的字段,未声明的自动丢弃(包括 nested、object 子字段) - 字段名要写完整路径,比如
user.name、tags.0.value,不能写模糊匹配 - 如果字段是
text类型且没开store: true,_source里本来就没有原始值,includes 也拿不到 —— 这不是配置问题,是 mapping 限制 - 和
_source.excludes不能共存;同时设会报错Validation Failed: 1: cannot specify both includes and excludes patterns;
Laravel + Scout 或原生客户端怎么传 includes
用 Laravel Scout 默认不支持 _source 控制,得绕过 Scout 直接调 ES 客户端;若用 elasticsearch-php 或 spring-data-elasticsearch,就得手动拼参数。
- 原生 PHP 客户端示例:
$params = ['index' => 'posts', 'body' => ['_source' => ['includes' => ['id','title','updated_at']], 'query' => ['match_all' => new \stdClass()]]]; $client->search($params); - Spring Data Elasticsearch:
new FetchSourceFilter(new String[]{"id","title"}, new String[0])传给withSourceFilter() - Scout 扩展方案:重写
buildPayload()方法,在body里注入_source配置 —— 但要注意 Scout v10+ 的 payload 结构已变,buildPayload不再直接暴露 body 数组
别把 Laravel select() 和 ES _source 混了
看到 Post::select('id','title') 就想套到 ES 上?这是常见误解。Laravel 的 select() 是 SQL 层字段投影,ES 没有表结构,_source 控制的是 JSON 文档序列化输出,两者语义不同、实现机制也完全隔离。
- Eloquent
select()不影响 Scout 同步到 ES 的内容;ES 里存什么,就只能从那里面挑字段 - 如果你在同步时用了
toSearchableArray()删掉了敏感字段(比如password_hash),那就算_source.includes写了它,也查不到 —— 因为源数据压根没存 - 调试技巧:先用 Kibana Dev Tools 跑一遍裸 DSL,确认
_source行为符合预期,再往 Laravel 里集成,避免多层封装掩盖真实响应
嵌套字段过滤容易漏掉点号路径
查 comments.author.name 却只写了 comments.author?结果整个 author object 都被返回,没达到精简目的。ES 的 _source.includes 对 nested 和 object 字段必须精确到叶子节点。
- 正确写法:
"includes": ["id", "title", "comments.author.name", "comments.author.avatar_url"] - 错误写法:
"includes": ["comments.author"]→ 返回整个 author 对象,含所有子字段 - 如果嵌套层级深或动态字段多(如
metadata.*),includes不支持通配符,得提前知道结构;这时考虑用excludes黑名单更实际











