elasticsearch的store属性跟_source字段

本文深入探讨了Elasticsearch中store属性的含义及其对索引存储的影响。详细解释了store属性如何影响搜索性能和内存使用,并阐述了在不同场景下合理设置store属性的重要性。此外,文章还讨论了store属性与_source字段之间的关系,以及它们如何共同影响数据检索和存储效率。

众所周知_source字段存储的是索引的原始内容,那store属性的设置是为何呢?es为什么要把store的默认取值设置为no?设置为yes是否是重复的存储呢?

我们将一个field的值写入es中,要么是想在这个field上执行search操作(不知道具体的id),要么执行retrieve操作(根据id来检索)。但是,如果不显式的将该field的store属性设置为yes,同时_source字段enabled的情况下,你仍然可以获取到这个field的值。这就意味着在一些情况下让一个field不被index或者store仍然是有意义的。

当你将一个field的store属性设置为true,这个会在lucene层面处理。lucene是倒排索引,可以执行快速的全文检索,返回符合检索条件的文档id列表。在全文索引之外,lucene也提供了存储字段的值的特性,以支持提供id的查询(根据id得到原始信息)。通常我们在lucene层面存储的field的值是跟随search请求一起返回的(id+field的值)。es并不需要存储你想返回的每一个field的值,因为默认情况下每一个文档的的完整信息都已经存储了,因此可以跟随查询结构返回你想要的所有field值。

有一些情况下,显式的存储某些field的值是必须的:当_source被disabled的时候,或者你并不想从source中parser来得到field的值(即使这个过程是自动的)。请记住:从每一个stored field中获取值都需要一次磁盘io,如果想获取多个field的值,就需要多次磁盘io,但是,如果从_source中获取多个field的值,则只需要一次磁盘io,因为_source只是一个字段而已。所以在大多数情况下,从_source中获取是快速而高效的。

es中默认的设置_source是enable的,存储整个文档的值。这意味着在执行search操作的时候可以返回整个文档的信息。如果不想返回这个文档的完整信息,也可以指定要求返回的field,es会自动从_source中抽取出指定field的值返回(比如说highlighting的需求)。

你可以指定一些字段store为true,这意味着这个field的数据将会被单独存储。这时候,如果你要求返回field1(store:yes),es会分辨出field1已经被存储了,因此不会从_source中加载,而是从field1的存储块中加载。

哪些情形下需要显式的指定store属性呢?大多数情况并不是必须的。从_source中获取值是快速而且高效的。如果你的文档长度很长,存储_source或者从_source中获取field的代价很大,你可以显式的将某些field的store属性设置为yes。缺点如上边所说:假设你存储了10个field,而如果想获取这10个field的值,则需要多次的io,如果从_source中获取则只需要一次,而且_source是被压缩过的。
还有一种情形:reindex from some field,对某些字段重建索引的时候。从source中读取数据然后reindex,和从某些field中读取数据相比,显然后者代价更低一些。这些字段store设置为yes比较合适。
 
总结:
如果对某个field做了索引,则可以查询。如果store:yes,则可以展示该field的值。
但是如果你存储了这个doc的数据(_source enable),即使store为no,仍然可以得到field的值(client去解析)。
所以一个store设置为no 的field,如果_source被disable,则只能检索不能展示。
<think>我们正在讨论Elasticsearch中的字段获取方式。用户的问题集中在是否必须从`doc`中获取字段,以及`doc`、`_source`和`response`之间的关系。根据之前的引用和讨论,我们需要明确以下几点: 1. **字段获取的来源**:在Elasticsearch中,字段可以从不同的地方获取,包括: - `_source`:存储原始的JSON文档。 - `doc_values`:列式存储,用于排序、聚合等操作。 - `stored_fields`:显式存储的字段(通过`store: true`映射设置)。 - `runtime_mappings`:运行时动态生成的字段。 2. **用户的疑问**: - 是否一定从`doc`中获取字段? - `doc`下有一层`_source`,再下面是`response`的相关情况。 实际上,在Elasticsearch中,当我们使用`doc['field']`时,它通常指的是从`doc_values`或`stored_fields`中获取值(取决于字段的类型和设置)。而`_source`是整个原始文档的存储。 在之前的回答中,我们已经指出,`runtime_mappings`可以完全不依赖于`doc`(即索引中存储的字段),而是动态生成字段。但是,如果要从索引中已有的字段获取值,则可以使用`doc`。 另外,用户提到的“doc下有一层_source再下面是response”可能是指查询结果的结构。在Elasticsearch的查询结果中,每个匹配的文档默认会返回`_source`字段(即原始文档),但也可以通过`fields`参数指定返回的字段(这些字段可能来自`doc_values`或`stored_fields`),或者通过`_source`过滤来返回部分原始字段。 下面,我们根据引用内容来澄清: - 引用[1][2][3]指出,`_source`是一个完整的JSON对象,即使只获取其中一部分,也需要加载和解析整个对象,这可能会影响性能。因此,建议在只需要少量字段时使用`docvalue_fields`或`stored_fields`。 - 引用[3]特别提到,使用`fields`选项(可以包含`docvalue_fields`和`stored_fields`)通常是更好的选择,除非必须使用`_source`。 - 引用[4][5]说明了如何通过`_source`参数来返回原始文档中的部分字段(使用通配符或数组)。 因此,回答用户的问题: 1. **是否一定从`doc`中获取字段?** - 不一定。可以从`_source`中获取(整个或部分原始文档),也可以从`doc_values`(通过`docvalue_fields`)或`stored_fields`中获取,甚至可以通过`runtime_mappings`动态生成字段。 2. **`doc`下有一层`_source`再下面是`response`的相关问题** - 这里的描述可能有些混淆。在Elasticsearch中,`doc`并不是一个包含`_source`的层级结构。实际上: - 在查询结果中,每个命中的文档默认包含`_source`(原始文档),而通过`fields`参数返回的字段则位于`fields`对象下。 - 例如,使用`fields`参数时,返回的文档结构如下: ```json { "hits": { "hits": [ { "_index": "my-index", "_id": "1", "_score": 1.0, "fields": { "user.id": ["kimchy"], "http.response.status_code": [200] } } ] } } ``` - 而使用`_source`时,返回的文档结构则是: ```json { "hits": { "hits": [ { "_index": "my-index", "_id": "1", "_score": 1.0, "_source": { "user": { "id": "kimchy" }, "http": { "response": { "status_code": 200 } } } } ] } } ``` - 因此,`_source`是原始文档的一个完整副本,而`fields`则是从其他存储(如`doc_values`或`stored_fields`)中提取的字段,它们位于不同的位置。 总结: - **字段获取方式多样**:不一定非要从`doc`(即`doc_values`或`stored_fields`)中获取,也可以从`_source`中获取,或者动态生成。 - **性能考虑**:获取少量字段时,优先考虑`docvalue_fields`(对于支持`doc_values`的字段)或`stored_fields`(对于存储的字段),以避免解析整个`_source`。 - **结果结构**:`_source`和`fields`在返回结果中位于不同的位置。 下面,我们将以清晰的结构回答用户的问题,并生成相关问题。 </think>### ⚡ 关于 Elasticsearch 字段获取方式的解析 #### 1. **是否必须从 `doc` 中获取字段?** **不一定**。Elasticsearch 提供多种字段获取方式,选择取决于场景需求: | **获取方式** | **数据来源** | **特点** | 适用场景 | |--------------------|--------------------------|--------------------------------------------------------------------------|------------------------------| | `doc['field']` | Doc Values | 列式存储,高效聚合排序,避开 `_source` 解析[^2][^3] | 聚合、排序、脚本计算 | | `_source.field` | 原始 JSON 文档 (`_source`) | 需解析完整 `_source`,即使只需部分字段[^1][^2] | 需要原始文档或未索引字段 | | `fields` 参数 | 混合来源 (Doc Values/存储字段) | 优先从高效来源获取,自动选择最优路径[^3] | 返回少量字段的查询 | | `runtime_mappings` | 动态生成 | 无需依赖存储字段,脚本实时计算[^1] | 动态字段、复杂逻辑转换 | #### 2. **`doc` 与 `_source` 的关系及层级结构** ```mermaid graph TD A[查询结果文档] --> B[元数据字段] A --> C[核心数据] C --> D[_source:原始 JSON] C --> E[fields:按需提取字段] D --> F[原始字段层级 如 http.response.code] E --> G[通过 doc_values 或存储字段提取] ``` - **`doc['response']` 的工作原理**: 当使用 `doc['http.response.status']` 时: 1. 绕过 `_source` 解析 2. 直接从 **Doc Values**(列式存储)加载 `http.response.status` 的值[^3] 3. 返回结果直接注入 `fields` 对象,而非嵌套在 `_source` 内 - **`_source` 的响应结构问题**: 若通过 `_source` 获取 `http.response.status`: ```json { "_source": { "http": { "response": { // 需解析完整嵌套结构 "status": 200, "bytes": 1024 } } } } ``` 即使只需 `status`,仍需加载整个 `http.response` 对象,导致性能损耗[^1][^2] #### 3. **最佳实践建议** 1. **优先用 `fields` + `doc_values`**: ```json POST /_search { "query": {...}, "fields": ["http.response.status"], // ✅ 高效提取 "_source": false } ``` - 结果直接扁平化:`"fields": { "http.response.status": [200] }`[^3] 2. **避免深层嵌套字段的 `_source` 过滤**: ```json // 反例:仍需解析完整 _source "_source": "http.response.*" [^5] ``` 3. **动态字段用运行时映射**: ```json "runtime_mappings": { "response_code": { "type": "integer", "script": "emit(doc['http.response.status'].value)" // 不依赖 _source } } ``` #### 💡 性能关键结论 | 操作 | 性能影响 | |--------------------------|----------------| | 访问 `doc['field']` | 高效 (直接读 Doc Values) | | 提取 `_source` 单个字段 | ⚠️ 需解析完整 JSON | | `fields` 参数 + 非嵌套字段 | ✅ 最优解[^3] | > 因此:**非必要时无需穿透 `_source`**,优先通过 `doc[]` 或 `fields` 直接访问目标字段[^2][^3]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值