第二阶段 19 · _source 字段裁剪

阶段:第二阶段 / 查询能力

ES:_source includes/excludes | PostgreSQL:SELECT col1, col2 而非 SELECT *


1. 概念

默认查询会返回整个文档(_source,相当于 SELECT *)。

_source 过滤可以只返回需要的字段,减少网络传输和内存开销,尤其字段多、文档大时收益明显。


2. PostgreSQL 对照

sql 复制代码
-- SELECT *
SELECT * FROM salesdata WHERE material = 'ThinkPad-X1';

-- 只取需要的列
SELECT invoice_number, net_amount FROM salesdata WHERE material = 'ThinkPad-X1';

3. ES DSL

只返回指定字段(includes)

复制代码
GET salesdata_idx/_search
{
  "_source": ["invoice_number", "net_amount"],
  "query": { "term": { "material": "ThinkPad-X1" } }
}

排除字段(excludes)

复制代码
GET salesdata_idx/_search
{
  "_source": {
    "includes": ["invoice_number", "net_amount", "material"],
    "excludes": ["description"]
  },
  "query": { "match_all": {} }
}

完全不返回 _source(只要命中/计数)

复制代码
GET salesdata_idx/_search
{
  "_source": false,
  "query": { "match_all": {} }
}

支持通配:"customer_*" 匹配一组字段。


4. Spring Boot 实现

本项目在 AbstractEsHepler#buildSource 里就做了字段裁剪:

java 复制代码
// 本项目原样:只 include 指定字段
public void buildSource(boolean t, SearchRequest.Builder builder, EsDataQuery query) {
    if (t) {
        builder.source(SourceConfig.of(s -> s.filter(
                f -> f.includes(Arrays.asList(query.get_source())))));
    }
}

独立示例:

java 复制代码
@Component
public class Doc19SourceFilter {

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    /** 只返回 includes 里的字段 */
    public List<Map<String, Object>> selectFields(String indexName, Query query,
                                                  List<String> includes) throws IOException {
        SearchResponse<Map> resp = elasticsearchClient.search(s -> s
                .index(indexName)
                .query(query)
                .source(sc -> sc.filter(f -> f.includes(includes))),
                Map.class);
        return resp.hits().hits().stream()
                .map(Hit::source).filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    /** includes + excludes */
    public List<Map<String, Object>> selectWithExcludes(String indexName, Query query,
                                                        List<String> includes,
                                                        List<String> excludes) throws IOException {
        SearchResponse<Map> resp = elasticsearchClient.search(s -> s
                .index(indexName)
                .query(query)
                .source(sc -> sc.filter(f -> f.includes(includes).excludes(excludes))),
                Map.class);
        return resp.hits().hits().stream()
                .map(Hit::source).filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
}

5. 坑与最佳实践

  1. 别习惯性 SELECT *:只取需要字段能明显降低响应体积和 GC 压力。
  2. _source 过滤不等于「不读磁盘」 :ES 仍会读整个 _source 再裁剪;
    要彻底避免读大字段,可在 mapping 里对该字段设 "store": true 配合 stored_fields,或拆索引。
  3. 配合排序/聚合 :聚合场景通常 "_source": false,只要桶结果不要文档体。
  4. 通配符方便但小心"*_dt" 之类通配匹配要确认不会漏带关键字段。

阶段小结

第二阶段(查询)完成,你已掌握 match / term / range / bool / exists / prefix-wildcard-fuzzy /

match_phrase / multi_match / 排序分页 / 字段裁剪,覆盖日常 90% 的检索需求。

下一篇

进入第三阶段聚合:20-metric-指标聚合.md

相关推荐
倒流时光三十年2 天前
第二阶段 15 · prefix / wildcard / fuzzy 模糊匹配
es
粗体鱼2 天前
RAG/Agent 记忆混合检索多路召回:RRF 算法与Chunk RRF、Document RRF如何决策TopK
postgresql·milvus·es·rag·rff·mermory
huisheng_qaq2 个月前
【项目篇-01】Vmware虚拟机和环境安装配置
redis·mysql·canal·rocketmq·es·vaware虚拟机
JAVA面经实录9172 个月前
Elasticsearch 完整版完整知识体系
java·elasticsearch·搜索引擎·es
代码讲故事2 个月前
在没有kibana的ES(elasticsearch)线上生产环境集群中,如何通过命令行修改或增加字段而不需要reindex?
大数据·elasticsearch·搜索引擎·命令行·es·索引·模版
yurenpai(27届找实习中)2 个月前
Elasticsearch 核心总结 + 面试题实战(黑马点评项目)
redis·es
徐小青青啊2 个月前
es集群不中断实时数据更新损坏节点硬盘
大数据·elasticsearch·搜索引擎·es
醇氧2 个月前
【Hermes Agent】使用阿里云百炼 Token Plan(方式一:命令行一键配置)
阿里云·云计算·es·openclaw
RemainderTime3 个月前
基于Spring AI + 阿里百炼 DashScope:构建 AI Agent RAG 企业级知识助手
人工智能·后端·spring·ai·es