官方文档:Managing Elasticsearch Fields When Searching
要想最大限度提高Elasticsearch的性能,控制搜索请求返回的字段数量是很重要的。在这一章,我们将讲解如何优化我们的应用,在每一个搜索结果中仅有选择地返回那些我们需要的字段。
在搜索中,使用参数fields
允许限制每一个查询命中项(查询结果 hit)返回的列(fields)。这个特性通常被用来优化大批量数据传输,当Elasticsearch查询结果中有大量返回列时,使其只返回相关的列。当然它听起来很简单(实际上它确实很简单),但是它却对性能有极大的影响,查询性能与返回文档的数量和每一个文档大小两个因素成反比。
考虑这样一种情况,当每一个文档的平均大小是20KB,那么每一次查询请求返回10个查询结果则是平均200KB的数据。如果每秒请求100次,那么我们就需要20M的带宽。作一个合理的假设,假如我们如果只返回有用的字段,可以降低文档大小到800字节,那么每一次请求大致就只返回8KB的数据量,每秒请求100次则只需要800KB的带宽。如果想要大规模使用, 那么保证返回结果尽可能小确实是非常重要且非常实用的。
默认情况下,开启的是_source
字段,它包含的是解析后的文档内容,并会在每一次查询后返回。当我们并不是需要查找并解析文档所有的内容时,我们通过限制返回的字段(fields
)可以节省宝贵的服务器CPU时间和磁盘IO。上面讲到的fields
便足以实现这一点。如果我们需要同时返回源文档(document)和一些列(fields),我们可以使用参数_source
过滤,后面将会介绍它的用法。
关于fields的另一个特性并不广为人知,它也可以用在查询元字段中(metadata-fields)。这里特指用它查询_ttl
字段的值,它可以在毫秒级别返回查询结果,而不是查询原文档需要的时间。这确实是一个非常实用的技巧。
有些时候,仅仅查询一些简单的字段是不够的,这时我们可能需要动态地查询一些嵌套字段中的数据。在这种情况下,我们不能使用fields
,否则只会得到下面这样的失败信息:
译者注:这此信息是在Elasticsearch日志中的,一般情况下在控制台看不到的。
{
...,
"_shards": {
"failures": [
{
"index": "index-name",
"shard": 2,
"status": 400,
"reason": "ElasticsearchIllegalArgumentException[field [field_with_nested_data] isn't a leaf field]"
}
]
},...
}
抛出的这个异常是因为fields
只能用于叶子节点的数据(即:这个节点没有子节点)。为了能够加载出非叶子节点,我们需要在查询时使用_source
参数,它可以激活过滤源文档的特性(它可以用来过滤源文档),下面将详细讲解。
源文档过滤可以在查询中控制原始JSON文档中的哪一部分会被返回。我们可以设置包含列或者排除列,通过模式匹配来过滤列名的访问路径即可。请记住,这仅仅可以节省从查询节点到调用客户端的带宽,而不能节省cpu时间和磁盘IO,除非使用fields
的时候。这是因为当使用源文档过滤时,对于每一个查询结果我们仍然需要解析源文档,根据提供的模式去匹配,以确实返回值中应该包含这一列,或者排除这一列。但是在我们的优化计划中,它仍然是一个非常重要的方式,并且它使用非常容易,我们可以从它开启优化的第一步。
在1.0版本之前,有一个更广为人知的查询方式——partial fields,现在它已经过时了,已经被本文的源文档过滤替代。
后面还有两段,但是由于我没有使用过,所以对内容的翻译掌握不好。暂时不翻译了。
未完待续……
译者附:fields
和_source
的使用方式
//fields
{
//其它查询条件
……
"fields": [
"goods_sale_number",
"id"
]
}
//_source
{
//其它查询条件
……
"_source": [
"goods_sale_number",
"id"
]
}
其实没什么区别,只不过两个的机制不同,且只有_source
支持嵌套类型。
希望本文会对你有所帮助。