第二阶段 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

相关推荐
vHelios3 天前
【电商项目】商品搜索开发复盘(1):根据需求拆解搜索接口的设计逻辑
java·微服务·es
cfm_291412 天前
Logstash 8.x 入门实战
安全·es
倒流时光三十年18 天前
第五阶段 40 · 深分页与性能(from/size、search_after、scroll、PIT)
es
倒流时光三十年19 天前
第三阶段 29 · suggester 自动补全(搜索框联想 / 拼写纠错)
es
倒流时光三十年20 天前
第三阶段 24 · filter / filters 桶聚合
es
倒流时光三十年20 天前
第二阶段 17 · multi_match 多字段匹配
es
倒流时光三十年20 天前
第三阶段 23 · 嵌套与子聚合 / top_hits
es
倒流时光三十年22 天前
第二阶段 15 · prefix / wildcard / fuzzy 模糊匹配
es
粗体鱼22 天前
RAG/Agent 记忆混合检索多路召回:RRF 算法与Chunk RRF、Document RRF如何决策TopK
postgresql·milvus·es·rag·rff·mermory