WEBKT

技术干货:深入解析 _source 字段在文档检索与更新中的妙用

2 0 0 0

1. 什么是 _source?

2. _source 在检索中的作用

2.1. 默认行为:返回 _source

2.2. 禁用 _source

2.3. 包含或排除字段

2.4. 最佳实践:根据需求选择

3. _source 在更新中的作用

3.1. 全量更新 (PUT)

3.2. 部分更新 (POST - _update)

3.3. 脚本更新 (POST - _update with script)

3.4. 最佳实践:根据场景选择

4. 配置 _source,提升查询效率

4.1. 禁用 _source(谨慎使用)

4.2. 包含或排除字段

4.3. 压缩 _source

4.4. 最佳实践:根据数据特点选择

5. 总结

6. 常见问题解答 (FAQ)

7. 进阶技巧与注意事项

8. 结语

你好,我是老码农。今天我们来聊聊在文档检索和更新中一个非常关键的字段:_source。如果你是一位需要优化文档搜索和更新效率的开发者,那么这篇文章绝对值得你花时间阅读。

1. 什么是 _source

简单来说,_source 字段是文档在索引时原始 JSON 文档的存储。它可以理解为 ElasticSearch 中每个文档的“备份”。当你向 ElasticSearch 索引一个文档时,默认情况下,_source 字段会保存你提交的原始 JSON 数据。

举个栗子:

假设你索引了如下文档:

{
"title": "深入理解 ElasticSearch",
"author": "老码农",
"content": "这篇文章介绍了 ElasticSearch 的核心概念...",
"tags": ["elasticsearch", "搜索", "技术"]
}

ElasticSearch 内部存储的结构大致如下:

{
"_index": "my_index",
"_type": "my_type",
"_id": "1",
"_version": 1,
"_source": {
"title": "深入理解 ElasticSearch",
"author": "老码农",
"content": "这篇文章介绍了 ElasticSearch 的核心概念...",
"tags": ["elasticsearch", "搜索", "技术"]
}
}

可以看到,原始的 JSON 数据被存储在 _source 字段中。 _source 字段的好处显而易见:

  • 数据完整性: 保证了原始数据的完整性,方便后续的检索和展示。
  • 快速获取原始数据: 通过 _source 字段,你可以快速获取文档的原始数据,而无需重新从数据库或其他数据源读取。
  • 支持更新和部分更新: 基于 _source 字段,ElasticSearch 能够支持文档的更新操作,包括完全替换和部分更新(使用 update API)。

2. _source 在检索中的作用

_source 在检索中扮演着至关重要的角色。当你执行搜索操作时,你可以通过配置来决定是否返回 _source 字段。

2.1. 默认行为:返回 _source

默认情况下,ElasticSearch 的搜索结果会返回 _source 字段。这意味着,当你执行一个简单的搜索请求时,ElasticSearch 会返回匹配的文档以及它们的原始 JSON 数据。

示例:

GET /my_index/_search
{
"query": {
"match": {
"content": "elasticsearch"
}
}
}

上述请求会搜索 content 字段中包含 “elasticsearch” 的文档,并返回这些文档的 _source 字段。

2.2. 禁用 _source

在某些情况下,你可能不需要返回完整的 _source 字段,例如,你只需要获取文档的 ID 或其他元数据。此时,你可以通过设置 _source 参数来禁用 _source 字段的返回。这可以显著减少网络传输的数据量,提高搜索性能。

示例:

GET /my_index/_search
{
"_source": false,
"query": {
"match": {
"content": "elasticsearch"
}
}
}

在这个例子中,搜索结果将不会包含 _source 字段。你只会得到文档的元数据,如 _id_index 等。

2.3. 包含或排除字段

除了完全禁用 _source 之外,你还可以通过 _source 参数来控制返回的字段。这允许你只返回 _source 中的特定字段,或者排除某些字段。这在优化搜索结果的展示和减少数据传输方面非常有用。

  • 包含字段:
GET /my_index/_search
{
"_source": ["title", "author"],
"query": {
"match": {
"content": "elasticsearch"
}
}
}

上述请求只返回 titleauthor 字段,其他字段将被排除。

  • 排除字段:
GET /my_index/_search
{
"_source": {
"excludes": ["content", "tags"]
},
"query": {
"match": {
"content": "elasticsearch"
}
}
}

上述请求排除了 contenttags 字段,只返回剩余的字段。

2.4. 最佳实践:根据需求选择

  • 如果需要展示完整的文档信息: 保持默认配置,返回完整的 _source
  • 如果只需要文档的 ID 或少量元数据: 禁用 _source 或使用 _source: false
  • 如果只需要文档的特定字段: 使用 _source: ["field1", "field2"] 包含特定字段。
  • 如果需要排除某些敏感或不重要的字段: 使用 _source: { "excludes": ["field1", "field2"]} 排除特定字段。

3. _source 在更新中的作用

_source 字段在文档更新中也发挥着关键作用。 ElasticSearch 提供了多种更新文档的方式,而 _source 字段是这些更新操作的基础。

3.1. 全量更新 (PUT)

全量更新是指使用新的文档替换现有的文档。这种更新方式会完全替换 _source 字段中的数据。 虽然简单,但这种方式需要你提供完整的文档数据,效率相对较低。

示例:

PUT /my_index/_doc/1
{
"title": "更新后的标题",
"author": "老码农",
"content": "这篇文章已经更新了...",
"tags": ["elasticsearch", "搜索", "技术", "更新"]
}

在这个例子中,文档 ID 为 1 的文档将被完全替换。 请注意,如果你没有提供某个字段,那么该字段将会从文档中删除。

3.2. 部分更新 (POST - _update)

部分更新允许你只更新文档的特定字段,而保留其他字段不变。 这是更常用、更高效的更新方式。 ElasticSearch 提供了 _update API 来实现部分更新。 _update API 内部使用 _source 字段来获取原始文档数据,然后应用更新操作。

示例:

POST /my_index/_update/1
{
"doc": {
"title": "部分更新后的标题"
}
}

在这个例子中,只有 title 字段被更新,其他字段保持不变。 doc 字段包含了需要更新的字段和值。 _update API 内部会先从 _source 字段获取原始文档,然后将 doc 字段中的数据合并到原始文档中,最后将更新后的文档重新索引。

3.3. 脚本更新 (POST - _update with script)

除了使用 doc 字段进行部分更新之外,你还可以使用脚本来执行更复杂的更新操作。 脚本更新允许你使用脚本语言(如 Groovy, Painless)来操作文档的字段。 脚本更新同样依赖于 _source 字段来获取原始文档数据。

示例:

POST /my_index/_update/1
{
"script": {
"source": "ctx._source.views += params.count",
"params": {
"count": 1
}
}
}

在这个例子中,我们使用脚本将文档的 views 字段增加 1。 ctx._source 代表 _source 字段中的数据。 params 字段传递了脚本需要的参数。

3.4. 最佳实践:根据场景选择

  • 如果需要完全替换文档: 使用全量更新 (PUT)。
  • 如果只需要更新部分字段: 使用部分更新 (POST - _update)。 这是最常用的更新方式。
  • 如果需要执行复杂的逻辑或计算: 使用脚本更新 (POST - _update with script)。 脚本更新提供了更大的灵活性。
  • 注意版本控制: 在更新文档时,建议使用版本控制(version 参数)来避免并发更新导致的数据冲突。

4. 配置 _source,提升查询效率

虽然 _source 字段非常有用,但它也会占用存储空间。 在某些场景下,你可以通过配置来优化 _source 字段,从而提升查询效率和降低存储成本。

4.1. 禁用 _source(谨慎使用)

前面我们提到过,你可以在索引时禁用 _source 字段。 这会减少存储空间,并略微提高索引速度。 但是,禁用 _source 后,你将无法进行更新操作,也无法直接获取文档的原始数据。 因此,禁用 _source 应该谨慎使用,只适用于你确定不需要更新和获取原始数据的场景。

配置示例(创建索引时):

PUT /my_index
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"content": {
"type": "text"
}
},
"_source": {
"enabled": false
}
}
}

4.2. 包含或排除字段

与搜索时类似,你可以在索引时配置 _source 字段,来控制哪些字段被存储在 _source 中。 这允许你只存储必要的字段,从而减少存储空间。

配置示例(创建索引时):

  • 只包含特定字段:
PUT /my_index
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"content": {
"type": "text"
},
"author": {
"type": "keyword"
}
},
"_source": {
"includes": ["title", "author"]
}
}
}

在这个例子中,只有 titleauthor 字段被存储在 _source 中。 content 字段不会被存储。

  • 排除特定字段:
PUT /my_index
{
"mappings": {
"properties": {
"title": {
"type": "text"
},
"content": {
"type": "text"
},
"tags": {
"type": "keyword"
}
},
"_source": {
"excludes": ["content", "tags"]
}
}
}

在这个例子中,contenttags 字段不会被存储在 _source 中。 其他字段(title)会被存储。

4.3. 压缩 _source

ElasticSearch 允许你对 _source 字段进行压缩,以减少存储空间。 你可以使用 compresscompress_threshold 参数来配置压缩。 compress_threshold 参数定义了文档大小超过多少时才进行压缩。

配置示例(创建索引时):

PUT /my_index
{
"settings": {
"index": {
"codec": "best_compression",
"store.compress": "true",
"store.compress_threshold": "1kb"
}
},
"mappings": {
"properties": {
"title": {
"type": "text"
},
"content": {
"type": "text"
}
}
}
}

在这个例子中,我们配置了 best_compression 编解码器,并且启用压缩,阈值为 1kb。 这意味着,当文档大小超过 1kb 时,_source 字段将被压缩。

4.4. 最佳实践:根据数据特点选择

  • 如果你的数据非常大,并且不需要更新和获取原始数据: 考虑禁用 _source(谨慎使用)。
  • 如果你的数据包含一些不重要的字段: 使用 includesexcludes 排除或只包含必要的字段。
  • 如果你的文档大小较大: 启用压缩。 这可以显著减少存储空间。

5. 总结

_source 字段是 ElasticSearch 中一个非常重要的特性,它在文档检索和更新中发挥着关键作用。 通过理解 _source 的作用和配置选项,你可以优化搜索性能、减少存储空间,并提高文档更新的效率。 希望这篇文章能帮助你更好地使用 ElasticSearch。

如果你有任何问题,欢迎在评论区留言,我会尽力解答。

6. 常见问题解答 (FAQ)

  • Q: 禁用 _source 后,我还能进行更新操作吗?
    A: 不能。 禁用 _source 后,你将无法进行部分更新,因为 _update API 依赖于 _source 字段来获取原始文档数据。

  • Q: _source 字段会影响索引速度吗?
    A: 是的。 存储 _source 字段会增加索引时间,因为 ElasticSearch 需要将原始数据存储起来。 但是,这种影响通常是可以接受的,因为 _source 字段带来了很多好处。 如果你非常关注索引速度,并且确定不需要更新和获取原始数据,那么可以考虑禁用 _source(谨慎使用)。

  • Q: 压缩 _source 会影响查询速度吗?
    A: 可能会。 压缩 _source 会增加 CPU 的负载,因为 ElasticSearch 需要在查询时解压缩 _source 字段。 但是,这种影响通常是微小的,并且可以通过调整压缩阈值来控制。 在大多数情况下,压缩 _source 带来的存储空间节省大于解压缩带来的性能损失。

  • Q: _source 字段的存储空间如何计算?
    A: _source 字段的存储空间取决于原始 JSON 文档的大小。 ElasticSearch 会根据原始数据的字节数来计算存储空间。 你可以使用 _cat/indices API 查看索引的存储空间占用情况。

  • Q: 如何查看 _source 字段的内容?
    A: 你可以使用 GET 请求来获取文档,从而查看 _source 字段的内容。 例如,GET /my_index/_doc/1 将会返回文档 ID 为 1 的文档的 _source 字段和其他元数据。

  • Q: _source 字段的 _source 字段是什么?
    A: 这是一个有趣的灵魂问题! _source 字段本身就是存储原始文档的 JSON 数据,所以它没有“_source”的“_source”字段。 如果你看到类似的问题,可能是理解出现了偏差,或者在讨论某个特定场景下的数据结构。 记住,_source 字段就是原始数据的容器。

7. 进阶技巧与注意事项

除了上述内容,还有一些进阶技巧和注意事项,可以帮助你更好地利用 _source 字段。

  • 使用动态映射 (Dynamic Mapping): ElasticSearch 默认使用动态映射,这意味着当你索引文档时,ElasticSearch 会自动推断字段类型。 动态映射会影响 _source 字段的内容,因为它决定了如何存储原始数据。 在某些情况下,你可能需要手动配置映射,以控制字段类型和存储方式,从而优化 _source 字段的使用。
  • 监控索引大小: 定期监控索引的大小,特别是 _source 字段的存储空间占用情况。 如果索引大小增长过快,你需要检查数据结构、索引配置,并考虑使用压缩、排除字段等优化策略。
  • 使用 _routing 在多分片环境下,使用 _routing 可以将文档路由到特定的分片。 这可以提高搜索和更新的效率,并减少跨分片的查询。 _routing 字段也会影响 _source 字段的内容,因为它会影响文档在集群中的分布。
  • 使用 _id 生成策略: ElasticSearch 允许你自定义 _id 生成策略。 选择合适的 _id 生成策略可以提高索引和检索效率。 _id 字段通常与 _source 字段一起使用,因为它们共同定义了文档的唯一标识。
  • 注意数据安全: _source 字段存储了原始数据,因此你需要注意数据安全。 如果你的数据包含敏感信息,你需要采取适当的安全措施,如加密、访问控制等,以保护数据的安全。
  • 结合使用 stored fields stored fields 允许你单独存储文档的特定字段,而无需将它们包含在 _source 中。 这对于需要频繁访问的字段很有用,因为你可以直接从存储字段中获取数据,而无需从 _source 字段中提取。 stored fields 可以与 _source 字段结合使用,以实现更灵活的存储和查询策略。
  • 利用 copy_to copy_to 允许你将多个字段的值复制到另一个字段。 这对于创建复合字段或提高搜索相关性很有用。 copy_to 会影响 _source 字段,因为它会改变原始数据的结构。

希望这些进阶技巧能帮助你更深入地理解和使用 _source 字段。

8. 结语

_source 字段是 ElasticSearch 中一个非常重要的概念,它对文档的检索和更新至关重要。 通过理解 _source 的作用、配置选项和最佳实践,你可以优化你的搜索和更新操作,提高系统的性能和效率。 希望这篇文章能帮助你更好地掌握 ElasticSearch,成为一名更优秀的开发者!

如果你在实践过程中遇到任何问题,欢迎随时提问。 祝你 coding 愉快!

老码农 Elasticsearch_source文档检索文档更新搜索

评论点评

打赏赞助
sponsor

感谢您的支持让我们更好的前行

分享

QRcode

https://www.webkt.com/article/8235