Elasticsearch教程之Metrics Aggregations

744 阅读28分钟

聚合框架有助于基于搜索查询提供聚合数据。 它基于称为聚合的简单构建块,可以进行组合以构建复杂的数据摘要。

聚合可以看作是在一组文档上建立分析信息的工作单元。 执行的上下文定义此文档集是什么(例如,在已执行的搜索请求的查询/过滤器的上下文中执行顶级聚合)。

有许多不同类型的聚合,每种聚合都有自己的目的和输出。 为了更好地理解这些类型,通常更容易将它们分为四个主要家族:

  • Bucketing:一组构建bucket的聚合,其中每个bucket都与一个键和一个文档条件相关联。当执行聚合时,将对上下文中每个文档评估所有bucket条件,当一个条件匹配时,将认为文档“落在”相关bucket中。在聚合过程的最后,我们将得到一个bucket列表——每个bucket都有一组“属于”它的文档。
  • Metric:在一组文档上跟踪和计算指标的聚合。
  • Matrix:一类聚合,可在多个字段上进行操作,并根据从请求的文档字段中提取的值生成矩阵结果。此聚合系列尚不支持脚本。
  • Pipeline:聚合,它聚合其他聚合的输出及其相关的度量

接下来是有趣的部分。 由于每个bucket有效地定义了一个文档集(所有属于该bucket的文档),因此可以潜在地在bucket级别关联聚合,并且这些聚合将在该bucket的上下文中执行。 这就是聚合真正的价值所在:聚合可以嵌套!

Bucket聚合可以具有子聚合(bucket或metric)。 子聚合将为其父聚合生成的bucket进行计算。 嵌套聚合的级别/深度没有硬性限制(可以将一个聚合嵌套在“父”聚合下,该父聚合本身是另一个更高级别聚合的子聚合)。

以下代码段捕获了聚合的基本结构:

"aggregations" : {
    "<aggregation_name>" : {
        "<aggregation_type>" : {
            <aggregation_body>
        }
        [,"meta" : {  [<meta_data_body>] } ]?
        [,"aggregations" : { [<sub_aggregation>]+ } ]?
    }
    [,"<aggregation_name_2>" : { ... } ]*
}

JSON中的aggregations对象(也可以使用键aggs)保存要计算的聚合。每个聚合都与用户定义的逻辑名称相关联(例如,如果聚合计算平均价格,那么将其命名为avg price是有意义的)。这些逻辑名称还将用于惟一地标识响应中的聚合。每个聚合都具有特定的类型(以上代码段中的<aggregation_type>),通常是指定的聚合主体内的第一个键。根据聚合的性质,每种类型的聚合定义自己的主体(例如,特定字段上的avg聚合将定义计算平均值的字段)。在聚合类型定义的同一级别上,可以选择定义一组其他聚合,尽管仅当您定义的聚合具有bucket特性时才有意义。例如,如果您在range聚合下定义一组聚合,则将为定义的range bucket计算子聚合。

一些聚合处理从聚合文档中提取的值。通常,这些值将从特定的文档字段中提取,该字段是使用用于聚合的字段键设置的。也可以定义一个脚本来生成值(每个文档)。

当为聚合配置了fieldscript设置时,script将被视为value script。虽然普通脚本是在文档级别评估的(即脚本可以访问与文档关联的所有数据),但值脚本是在值级别评估的。 在这种模式下,从配置的字段中提取值,并且脚本用于对这些值进行“转换”。

Elasticsearch使用映射中的字段类型来确定如何运行聚合和格式化响应。但是有两种情况是Elasticsearch无法计算出这些信息: 未映射的字段(例如,对于跨多个索引的搜索请求,其中只有一些字段具有映射)和纯脚本。对于这些情况,可以使用value_type选项为Elasticsearch提供提示,它接受以下值:string, long (适用于所有整型), double (适用于所有的十进制类型例如floatscaled_float), date, ipboolean.

Metric聚合

这个家族中的聚合基于以某种方式从被聚合的文档中提取的值来计算度量。这些值通常从文档的字段中提取(使用字段数据),但是也可以使用脚本生成。

数值指标聚合是一种特殊类型的指标聚合,可输出数值。一些聚合输出单个数字指标(例如avg),称为单值数字指标聚合,其他聚合则生成多个指标(例如统计数据),并称为多值数字指标聚合。单值和多值数值度量聚合之间的区别在这些聚合充当某些bucket聚合的直接子聚合时发挥了作用(一些bucket聚合使您能够根据每个bucket中的数字指标对返回的bucket进行排序)。

Avg聚合

单值指标聚合,用于计算从聚合文档中提取的数值的平均值。这些值可以从文档中的特定数字字段中提取,也可以由提供的脚本生成。

假设数据由代表学生考试成绩(介于0到100之间)的文档组成,我们先添加一组数据:

PUT /exam/_doc/5
{
  "name": "穆里尼奥",
  "grade": 89
}

我们可以使用以下方法取平均分数:

curl -X POST "localhost:9200/exams/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
{
    "aggs" : {
        "avg_grade" : { "avg" : { "field" : "grade" } }
    }
}
'

以上聚合计算了所有文档的平均成绩。聚合类型是avgfield设置定义了将计算平均值的文档的数字字段。上面将返回以下内容:

{
  "took" : 9,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "avg_grade" : {
      "value" : 88.0
    }
  }
}

聚合的名称(上面的avg_grade)也用作键,通过该键可以从返回的响应中检索聚合结果。

Script

基于脚本计算平均分数:

curl -X POST "localhost:9200/exams/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
{
    "aggs" : {
        "avg_grade" : {
            "avg" : {
                "script" : {
                    "source" : "doc.grade.value"
                }
            }
        }
    }
}
'

这将把脚本参数解释为内联脚本,使用简单的脚本语言,没有脚本参数。要使用存储的脚本,请使用以下语法:

curl -X POST "localhost:9200/exams/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
{
    "aggs" : {
        "avg_grade" : {
            "avg" : {
                "script" : {
                    "id": "my_script",
                    "params": {
                        "field": "grade"
                    }
                }
            }
        }
    }
}
'

Value Script

结果证明,这次考试远远超出了学生的水平,需要对分数进行修正。我们可以使用值脚本来得到新的平均值

curl -X POST "localhost:9200/exams/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
{
    "aggs" : {
        "avg_corrected_grade" : {
            "avg" : {
                "field" : "grade",
                "script" : {
                    "lang": "painless",
                    "source": "_value * params.correction",
                    "params" : {
                        "correction" : 1.2
                    }
                }
            }
        }
    }
}
'

{
  "took" : 201,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "avg_corrected_grade" : {
      "value" : 105.6
    }
  }
}

Missing value

missing参数定义应如何处理缺少值的文档。 默认情况下,它们将被忽略,但也可以将它们视为具有值。

curl -X POST "localhost:9200/exams/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
{
    "aggs" : {
        "grade_avg" : {
            "avg" : {
                "field" : "grade",
                "missing": 10 
            }
        }
    }
}
'

在grade字段中没有值的文档将与值为10的文档处于相同的bucket。

Weighted Avg Aggregation

一种单值度量聚合,计算从聚合文档中提取的数值的加权平均值。这些值可以从文档中的特定数字字段中提取。

在计算常规平均值时,每个数据点具有相等的“权重”,它对最终值的贡献相等。另一方面,加权平均数对每个数据点的权重不同。每个数据点对最终值的贡献量是从文档中提取的,或由脚本提供的。

公式中的加权平均值为∑(值*权重)/ ∑(权重).可以将常规平均值视为每个平均值的隐式权重为1的加权平均值。

参数名 描述 是否必须 默认值
value 提供值的字段或脚本的配置 必须
weight 提供权重的字段或脚本的配置 必须
format 数字响应格式化程序 可选
value_type 关于纯脚本或未映射字段的值的提示 可选

valueweight对象具有每个字段特定的配置

参数名 描述 是否必须 默认值
field 应该从中提取值的字段 必须
missing 如果字段完全丢失,则使用一个值 可选
参数名 描述 是否必须 默认值
field 应该提取权值的字段 必须
missing 如果字段完全丢失,则使用的权重 可选

示例

如果我们的文档有一个“分数”字段,该字段包含0-100的数字分数,而“加权”字段中包含一个任意的数字加权,则可以使用以下方法计算加权平均值:

curl -X POST "localhost:9200/exams/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "size": 0,
    "aggs" : {
        "weighted_grade": {
            "weighted_avg": {
                "value": {
                    "field": "grade"
                },
                "weight": {
                    "field": "weight",
                    "missing":10
                }
            }
        }
    }
}
'

{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 5,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "weighted_grade" : {
      "value" : 87.80952380952381
    }
  }
}

虽然每个字段允许多个值,但是只允许一个权重。如果聚合遇到一个文档有多个权值(例如,权值字段是一个多值字段),它将抛出一个异常。如果遇到这种情况,则需要为权重字段指定一个脚本,并使用该脚本将多个值组合为一个要使用的值。

该单个权重将独立应用于从值字段中提取的每个值。

此示例说明如何使用单个权重对具有多个值的单个文档进行平均:

curl -X POST "localhost:9200/exams/_doc?refresh&pretty" -H 'Content-Type: application/json' -d'
{
    "grade": [1, 2, 3],
    "weight": 2
}
'



{
  "_index" : "exam",
  "_type" : "_doc",
  "_id" : "K8rfFHEBntSjw-Ls52Di",
  "_version" : 1,
  "result" : "created",
  "forced_refresh" : true,
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 7,
  "_primary_term" : 1
}

上述操作在exam文档中新增了一个用于三个分数的记录,注意,由于id字段未指定,其返回的_id表明,系统会默认给我们分配一个随机的id串。然后计算数据的加权平均值:

curl -X POST "localhost:9200/exams/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "size": 0,
    "aggs" : {
        "weighted_grade": {
            "weighted_avg": {
                "value": {
                    "field": "grade"
                },
                "weight": {
                    "field": "weight"
                }
            }
        }
    }
}
'

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "weighted_grade" : {
      "value" : 2.0
    }
  }
}

这三个值(1、2和3)将作为独立值包含,权重均为2,聚合将返回2.0作为结果,这与我们手工计算时所期望的结果相匹配:((1*2) + (2*2) + (3*2)) / (2+2+2) == 2

Script

值和权重都可以从脚本而不是字段中派生。 作为一个简单的示例,以下内容将使用脚本在文档的等级和权重中添加一个:

curl -X POST "localhost:9200/exams/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "size": 0,
    "aggs" : {
        "weighted_grade": {
            "weighted_avg": {
                "value": {
                    "script": "doc.grade.value + 1"
                },
                "weight": {
                    "script": "doc.weight.value + 1"
                }
            }
        }
    }
}
'

{
  "took" : 298,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "weighted_grade" : {
      "value" : 2.0
    }
  }
}

Missing values

missing参数定义应如何处理缺少值的文档。 值和权重的默认行为不同:

默认情况下,如果缺少value字段,则忽略该文档,并将聚合移至下一个文档。 如果缺少权重字段,则假定其权重为1(如正常平均值)。

这两个默认值都可以用缺少的参数覆盖:

curl -X POST "localhost:9200/exams/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "size": 0,
    "aggs" : {
        "weighted_grade": {
            "weighted_avg": {
                "value": {
                    "field": "grade",
                    "missing": 2
                },
                "weight": {
                    "field": "weight",
                    "missing": 3
                }
            }
        }
    }
}
'

Cardinality聚合

单值指标聚合,用于计算不同值的近似计数。 值可以从文档中的特定字段中提取,也可以由脚本生成。

举个例子,我们首先创建一个索引

PUT /books
{
  "mappings": {
      "properties": {
        "name":{"type": "text"},
        "author":{"type":"keyword"},
        "dateStr":{"type":"date"}
      }
  }
}

然后添加一些测试数据

PUT /books2/_doc/2
{
  "name": "母猪的产后护理",
  "author": "赵迪迪",
  "dateStr": "2020-03-26"
}

PUT /books2/_doc/1
{
  "name": "关于养猪的那些事儿",
  "author": "梁散散",
  "dateStr": "2020-03-26"
}

此时,如果需要获取以作者为分类的,统计其著作的数量:

POST /books2/_search?size=0&pretty
{
    "aggs" : {
        "author_count" : {
            "cardinality" : {
                "field" : "author"  // 字段类型不能是普通的text类型,否则无法执行聚合操作
            }
        }
    }
}


{
  "took" : 374,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "author_count" : {
      "value" : 2
    }
  }
}

精度控制

此聚合还支持precision_threshold选项,precision_threshold选项允许以内存为代价来换取准确性,并定义一个唯一的计数,在该计数以下,期望计数接近准确。 超过此值,计数可能会变得更加模糊。 支持的最大值为40000,超过此阈值的阈值将与阈值40000产生相同的效果。默认值为3000:

POST /books2/_search?size=0&pretty
{
    "aggs" : {
        "author_count" : {
            "cardinality" : {
                "field" : "author",
                "precision_threshold": 100 
            }
        }
    }
}

计数式近似值

计算精确计数需要将值加载到哈希集中并返回其大小。 当处理高基数集和/或较大的值时,这不会扩展,因为所需的内存使用情况以及在节点之间传递每个分片集的需求会占用过多的群集资源。

此基数聚合基于HyperLogLog ++算法,该算法基于具有一些有趣属性的值的哈希值进行计数:

  • 可配置的精度,该精度决定了如何以内存换取精度,
  • 低基数集的精度很高,
  • 固定的内存使用量:无论是否有成百上千的唯一值,内存使用量仅取决于配置的精度。

对于c的精度阈值,我们使用的实现大约需要c * 8个字节。

下表显示了阈值前后误差如何变化:

预计算哈希

在具有高基数的字符串字段上,将字段值的哈希存储在索引中然后在此字段上运行基数聚合可能会更快。 这可以通过从客户端提供哈希值来完成,也可以让Elasticsearch使用mapper-murmur3插件为您计算哈希值

Script

基数度量标准支持脚本编写,但是由于哈希值需要实时计算,因此性能会受到明显影响。

Missing value

缺少参数定义了应该如何处理缺少值的文档。默认情况下,它们将被忽略,但也可以将它们视为具有值。

Extended Stats 聚合

一种多值度量标准聚合,可根据从聚合文档中提取的数值计算统计信息。这些值可以从文档中的特定数字字段提取,也可以由提供的脚本生成。

extended_stats聚合是stats聚合的扩展版本,其中添加了其他指标,例如sum_of_squaresvariancestd_deviationstd_deviation_bounds

curl -X GET "localhost:9200/exams/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "size": 0,
    "aggs" : {
        "grades_stats" : { "extended_stats" : { "field" : "grade" } }
    }
}
'

{
  "took" : 9,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "grades_stats" : {
      "count" : 3,
      "min" : 1.0,
      "max" : 3.0,
      "avg" : 2.0,
      "sum" : 6.0,
      "sum_of_squares" : 14.0,
      "variance" : 0.6666666666666666,
      "std_deviation" : 0.816496580927726,
      "std_deviation_bounds" : {
        "upper" : 3.632993161855452,
        "lower" : 0.36700683814454793
      }
    }
  }
}

上面的汇总计算了所有文档的成绩统计。 聚合类型为extended_stats,并且字段设置定义将在其上计算统计信息的文档的数字字段。 聚合的名称(上面的grades_stats)还用作可以从返回的响应中检索聚合结果的键。

标准偏差界限

默认情况下,extended_stats指标将返回一个名为std_deviation_bounds的对象,该对象提供一个与平均值相差正负两个标准差的间隔。 这是可视化数据差异的有用方法。 如果要使用其他边界,例如三个标准差,则可以在请求中设置sigma

curl -X GET "localhost:9200/exams/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "size": 0,
    "aggs" : {
        "grades_stats" : {
            "extended_stats" : {
                "field" : "grade",
                "sigma" : 3 
            }
        }
    }
}
'

{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "grades_stats" : {
      "count" : 3,
      "min" : 1.0,
      "max" : 3.0,
      "avg" : 2.0,
      "sum" : 6.0,
      "sum_of_squares" : 14.0,
      "variance" : 0.6666666666666666,
      "std_deviation" : 0.816496580927726,
      "std_deviation_bounds" : {
        "upper" : 4.449489742783178,
        "lower" : -0.4494897427831779
      }
    }
  }
}

sigma控制应显示多少平均值的标准偏差.sigma可以是任何非负的双精度浮点数,这意味着您可以请求非整数值,比如1.5。值0是有效的,但它只会返回上界和下界的平均值。

Script

基于脚本计算分数统计:

curl -X GET "localhost:9200/exams/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "size": 0,
    "aggs" : {
        "grades_stats" : {
            "extended_stats" : {
                "script" : {
                    "source" : "doc[\u0027grade\u0027].value",
                    "lang" : "painless"
                 }
             }
         }
    }
}
'

Value Script

事实证明,该考试远远超出了学生的水平,因此需要进行成绩更正。 我们可以使用值脚本来获取新的统计信息:

curl -X GET "localhost:9200/exams/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "size": 0,
    "aggs" : {
        "grades_stats" : {
            "extended_stats" : {
                "field" : "grade",
                "script" : {
                    "lang" : "painless",
                    "source": "_value * params.correction",
                    "params" : {
                        "correction" : 1.2
                    }
                }
            }
        }
    }
}
'

{
  "took" : 66,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "grades_stats" : {
      "count" : 1,
      "min" : 1.0,
      "max" : 1.0,
      "avg" : 1.0,
      "sum" : 1.0,
      "sum_of_squares" : 1.0,
      "variance" : 0.0,
      "std_deviation" : 0.0,
      "std_deviation_bounds" : {
        "upper" : 1.0,
        "lower" : 1.0
      }
    }
  }
}

Missing value

missing参数定义应如何处理缺少值的文档。 默认情况下,它们将被忽略,但也可以将它们视为具有值。

curl -X GET "localhost:9200/exams/_search?pretty" -H 'Content-Type: application/json' -d'
{
    "size": 0,
    "aggs" : {
        "grades_stats" : {
            "extended_stats" : {
                "field" : "grade",
                "missing": 0 
            }
        }
    }
}
'

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "grades_stats" : {
      "count" : 3,
      "min" : 1.0,
      "max" : 3.0,
      "avg" : 2.0,
      "sum" : 6.0,
      "sum_of_squares" : 14.0,
      "variance" : 0.6666666666666666,
      "std_deviation" : 0.816496580927726,
      "std_deviation_bounds" : {
        "upper" : 3.632993161855452,
        "lower" : 0.36700683814454793
      }
    }
  }
}

Geo Bounds 聚合

一种度量标准聚合,用于计算包含一个字段的所有geo_point值的边界框。

PUT /museums
{
    "mappings": {
        "properties": {
            "location": {
                "type": "geo_point"
            }
        }
    }
}

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "museums"
}

放数据进去

POST /museums/_bulk?refresh
{"index":{"_id":1}}
{"location": "52.374081,4.912350", "name": "NEMO Science Museum"}
{"index":{"_id":2}}
{"location": "52.369219,4.901618", "name": "Museum Het Rembrandthuis"}
{"index":{"_id":3}}
{"location": "52.371667,4.914722", "name": "Nederlands Scheepvaartmuseum"}
{"index":{"_id":4}}
{"location": "51.222900,4.405200", "name": "Letterenhuis"}
{"index":{"_id":5}}
{"location": "48.861111,2.336389", "name": "Musée du Louvre"}
{"index":{"_id":6}}
{"location": "48.860000,2.327000", "name": "Musée d'Orsay"}


{
  "took" : 331,
  "errors" : false,
  "items" : [
    {
      "index" : {
        "_index" : "museums",
        "_type" : "_doc",
        "_id" : "1",
        "_version" : 1,
        "result" : "created",
        "forced_refresh" : true,
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 0,
        "_primary_term" : 1,
        "status" : 201
      }
    },
    {
      "index" : {
        "_index" : "museums",
        "_type" : "_doc",
        "_id" : "2",
        "_version" : 1,
        "result" : "created",
        "forced_refresh" : true,
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 1,
        "_primary_term" : 1,
        "status" : 201
      }
    },
    {
      "index" : {
        "_index" : "museums",
        "_type" : "_doc",
        "_id" : "3",
        "_version" : 1,
        "result" : "created",
        "forced_refresh" : true,
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 2,
        "_primary_term" : 1,
        "status" : 201
      }
    },
    {
      "index" : {
        "_index" : "museums",
        "_type" : "_doc",
        "_id" : "4",
        "_version" : 1,
        "result" : "created",
        "forced_refresh" : true,
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 3,
        "_primary_term" : 1,
        "status" : 201
      }
    },
    {
      "index" : {
        "_index" : "museums",
        "_type" : "_doc",
        "_id" : "5",
        "_version" : 1,
        "result" : "created",
        "forced_refresh" : true,
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 4,
        "_primary_term" : 1,
        "status" : 201
      }
    },
    {
      "index" : {
        "_index" : "museums",
        "_type" : "_doc",
        "_id" : "6",
        "_version" : 1,
        "result" : "created",
        "forced_refresh" : true,
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 5,
        "_primary_term" : 1,
        "status" : 201
      }
    }
  ]
}

geo_bounds聚合指定用于获取边界的字段 wrap_longitude是一个可选参数,用于指定是否应允许边界框与国际日期线重叠。 默认值是true.

POST /museums/_search?size=0
{
    "query" : {
        "match" : { "name" : "musée" }
    },
    "aggs" : {
        "viewport" : {
            "geo_bounds" : {
                "field" : "location", 
                "wrap_longitude" : true 
            }
        }
    }
}

{
  "took" : 75,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "viewport" : {
      "bounds" : {
        "top_left" : {
          "lat" : 48.86111099738628,
          "lon" : 2.3269999679178
        },
        "bottom_right" : {
          "lat" : 48.85999997612089,
          "lon" : 2.3363889567553997
        }
      }
    }
  }
}

上面的汇总展示了如何针对具有商店业务类型的所有文档计算位置字段的边界框.

Geo Centroid 聚合

一种度量聚合,它根据Geo-point字段的所有坐标值计算加权质心。 geo_centroid聚合指定用于计算质心的字段。

建索引

PUT /museums1
{
    "mappings": {
        "properties": {
            "location": {
                "type": "geo_point"
            }
        }
    }
}

放数据

POST /museums1/_bulk?refresh
{"index":{"_id":1}}
{"location": "52.374081,4.912350", "city": "莫斯科", "name": "莫斯科博物馆"}
{"index":{"_id":2}}
{"location": "52.369219,4.901618", "city": "伦敦", "name": "大英文明博物馆"}
{"index":{"_id":3}}
{"location": "52.371667,4.914722", "city": "伦敦", "name": "太空博物馆"}
{"index":{"_id":4}}
{"location": "51.222900,4.405200", "city": "伦敦", "name": "科技博物馆"}
{"index":{"_id":5}}
{"location": "48.861111,2.336389", "city": "巴黎", "name": "巴黎博物馆"}
{"index":{"_id":6}}
{"location": "48.860000,2.327000", "city": "伦敦", "name": "伦敦艺术中心博物馆"}

POST /museums1/_search?size=0
{
    "aggs" : {
        "centroid" : {
            "geo_centroid" : {
                "field" : "location" 
            }
        }
    }
}


{
  "took" : 34,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 6,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "centroid" : {
      "location" : {
        "lat" : 51.00982965203002,
        "lon" : 3.9662131341174245
      },
      "count" : 6
    }
  }
}

geo_centroid聚合作为子聚合合并到其他存储桶聚合时,会更有趣。例如

curl -X POST "localhost:9200/museums1/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
{
    "aggs" : {
        "cities" : {
            "terms" : { "field" : "city.keyword" },
            "aggs" : {
                "centroid" : {
                    "geo_centroid" : { "field" : "location" }
                }
            }
        }
    }
}
'


{
  "took" : 21,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 6,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "cities" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "伦敦",
          "doc_count" : 4,
          "centroid" : {
            "location" : {
              "lat" : 51.20594648178667,
              "lon" : 4.137134968768805
            },
            "count" : 4
          }
        },
        {
          "key" : "巴黎",
          "doc_count" : 1,
          "centroid" : {
            "location" : {
              "lat" : 48.86111099738628,
              "lon" : 2.3363889567553997
            },
            "count" : 1
          }
        },
        {
          "key" : "莫斯科",
          "doc_count" : 1,
          "centroid" : {
            "location" : {
              "lat" : 52.374080987647176,
              "lon" : 4.912349972873926
            },
            "count" : 1
          }
        }
      ]
    }
  }
}

上面的示例使用geo centroid作为术语bucket聚合的子聚合,用于查找每个城市中博物馆的中心位置。

Max聚合

一种单值度量聚合,它跟踪并返回从聚合文档中提取的数值的最大值。这些值可以从文档中的特定数字字段提取,也可以由提供的脚本生成。

计算所有文档的最高分;

POST /exam/_search?size=0&pretty
{
    "aggs" : {
        "max_grade" : { "max" : { "field" : "grade" } }
    }
}

{
  "took" : 67,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 6,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "max_grade" : {
      "value" : 98.0
    }
  }
}

可以看到,聚合的名称(上面的max_grade)也用作从返回的响应中检索聚合结果的键。

Script

max聚合还可以计算脚本的最大值。下面的例子计算了最高分:

POST /exam/_search
{
    "aggs" : {
        "max_grade" : {
            "max" : {
                "script" : {
                    "source" : "doc.grade.value"
                }
            }
        }
    }
}


{
  "took" : 8,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 6,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "exam",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "name" : "John Doe",
          "grade" : 98
        }
      },
      {
        "_index" : "exam",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "name" : "张艺兴",
          "grade" : 85
        }
      },
      {
        "_index" : "exam",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "name" : "赵明义",
          "grade" : 89
        }
      },
      {
        "_index" : "exam",
        "_type" : "_doc",
        "_id" : "4",
        "_score" : 1.0,
        "_source" : {
          "name" : "李柳柳",
          "grade" : 79
        }
      },
      {
        "_index" : "exam",
        "_type" : "_doc",
        "_id" : "5",
        "_score" : 1.0,
        "_source" : {
          "name" : "穆里尼奥",
          "grade" : 89,
          "weight" : 2
        }
      },
      {
        "_index" : "exam",
        "_type" : "_doc",
        "_id" : "K8rfFHEBntSjw-Ls52Di",
        "_score" : 1.0,
        "_source" : {
          "grade" : [
            1,
            2,
            3
          ],
          "weight" : 2
        }
      }
    ]
  },
  "aggregations" : {
    "max_grade" : {
      "value" : 98.0
    }
  }
}

Missing value

缺少参数定义了应该如何处理缺少值的文档。默认情况下,它们将被忽略,但也可以将它们视为具有值。

Min 聚合

一种单值度量聚合,它跟踪并返回从聚合文档中提取的数值中的最小值。这些值可以从文档中的特定数字字段提取,也可以由提供的脚本生成。

POST /exam/_search?size=0&pretty
{
    "aggs" : {
        "min_grade" : { "min" : { "field" : "grade" } }
    }
}

其他操作通Max聚合

Percentiles聚合

一种多值度量聚合,计算从聚合文档中提取的数值上的一个或多个百分比。这些值可以由提供的脚本生成,也可以从文档中的特定数字或直方图字段中提取。

百分比表示观察值的某个百分比出现的位置。例如,第95百分位是大于95%观测值的值。

百分位数通常用于查找异常值。 在正态分布中,第0.13和第99.87个百分位数代表与平均值的三个标准差。 任何超出三个标准偏差的数据通常被视为异常。

当检索到一定范围的百分位数时,它们可以用于估计数据分布并确定数据是否偏斜,双峰等。

假设您的数据包含网站加载时间。 平均和中位数加载时间对管理员来说并不太有用。 最大值可能很有趣,但是很容易因单个缓慢的响应而产生偏差。

让我们看看表示成绩分布的百分比范围, 默认情况下,百分位数度量将生成一个百分位数范围:[1、5、25、50、75、95、99]。:

GET exam/_search
{
  "size": 0,
  "aggs": {
    "grade_outlier": {
      "percentiles": {
        "field": "grade",
        "percents": [
          1,
          5,
          25,
          50,
          75,
          95,
          99
        ]
      }
    }
  }
}


{
  "took" : 99,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 6,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "grade_outlier" : {
      "values" : {
        "1.0" : 1.0,
        "5.0" : 1.0,
        "25.0" : 2.5,
        "50.0" : 82.0,
        "75.0" : 89.0,
        "95.0" : 98.0,
        "99.0" : 98.0
      }
    }
  }
}

如您所见,聚合将为默认范围内的每个百分比返回一个计算值.通常,管理员只对极端百分位数的异常值感兴趣。我们可以指定我们感兴趣的百分比(请求的百分比必须是0-100之间的值,包括0-100):

GET exam/_search
{
  "size": 0,
  "aggs": {
    "grade_outlier": {
      "percentiles": {
        "field": "grade",
        "percents": [
          95,
          99
        ]
      }
    }
  }
}

keyed Response

默认情况下,键控标志设置为true,该键将唯一的字符串键与每个存储桶相关联,并以散列而不是数组的形式返回范围。 将keyed标志设置为false将禁用此行为:


GET exam/_search
{
  "size": 0,
  "aggs": {
    "grade_outlier": {
      "percentiles": {
        "field": "grade",
        "keyed": false
      }
    }
  }
}

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 6,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "grade_outlier" : {
      "values" : [
        {
          "key" : 1.0,
          "value" : 1.0
        },
        {
          "key" : 5.0,
          "value" : 1.0
        },
        {
          "key" : 25.0,
          "value" : 2.5
        },
        {
          "key" : 50.0,
          "value" : 82.0
        },
        {
          "key" : 75.0,
          "value" : 89.0
        },
        {
          "key" : 95.0,
          "value" : 98.0
        },
        {
          "key" : 99.0,
          "value" : 98.0
        }
      ]
    }
  }
}

Script

百分比指标支持脚本编制。例如,如果分数是10进制的,而不是100分制的,那么我们可以使用一个脚本动态地转换它们

GET exam/_search
{
  "size": 0,
  "aggs": {
    "grade_outlier": {
      "percentiles" : {
                "script" : {
                    "lang": "painless",
                    "source": "doc['grade'].value / params.timeUnit", 
                    "params" : {
                        "timeUnit" : 10   
                    }
                }
            }
 
    }
  }
}

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 6,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "grade_outlier" : {
      "values" : {
        "1.0" : 0.0,
        "5.0" : 0.0,
        "25.0" : 7.0,
        "50.0" : 8.0,
        "75.0" : 8.0,
        "95.0" : 9.0,
        "99.0" : 9.0
      }
    }
  }
}

有许多不同的算法可以计算百分位数。 简单的实现只是将所有值存储在一个排序数组中。 要找到第50个百分位数,您只需找到my_array [count(my_array)* 0.5]的值即可。

显然,这个简单的实现并不会随着数据集中值的数量线性增长而缩放排序后的数组。为了计算一个Elasticsearch集群中可能有数十亿个值的百分比,需要计算近似的百分比。

百分位数度量标准使用的算法称为TDigest。

使用此指标时,需要牢记一些准则:

  • 精度与q(1-q)成正比。 这意味着极端百分位数(例如99%)比不那么极端百分位数(例如中位数)更准确
  • 对于较小的一组值,百分位数非常准确(如果数据足够小,则可能为100%准确)。
  • 随着桶中值数量的增长,算法开始逼近百分位数。它实际上是用精度来换取内存的节省。不准确的确切级别很难概括,因为它取决于您的数据分布和被聚合的数据量

下表显示了一个均匀分布的相对误差,它取决于收集值的数量和请求的百分位数:

它说明了对于极端百分位数来说,精度是如何的好。对于大量的值,误差减小的原因是大数定律使得值的分布越来越均匀,t-digest树可以更好地对其进行汇总。对于偏态分布就不一样了。

压缩

近似算法必须在内存使用和估计精度之间取得平衡。可以使用压缩参数来控制这种平衡

GET exam/_search
{
  "size": 0,
  "aggs": {
    "grade_outlier": {
       "percentiles" : {
                "field" : "grade",
                "tdigest": {
                  "compression" : 200 
                }
            }
    }
  }
}

TDigest算法使用一定数量的“节点”来近似百分比,可用的节点越多,精确度(和大内存占用)与数据量的比例就越高。compression参数将最大节点数限制为20 *compression

因此,通过增加压缩值,可以以增加内存为代价来提高百分位数的准确性。较大的压缩值也会使算法变慢,因为底层树数据结构的大小会增长,从而导致更昂贵的操作。默认的压缩值是100。

一个“节点”大约使用32字节的内存,所以在最坏的情况下(大量的数据按顺序到达),默认设置将产生一个大约64KB大小的TDigest。实际上,数据往往更随机,TDigest使用的内存更少。

HDR Histogram (High Dynamic Range Histogram)

是另一种实现,它在计算延迟测量的百分比时很有用,因为它比t-digest实现更快,但需要牺牲更大的内存占用。此实现维护一个固定的最坏情况百分比错误(指定为多个有效数字)。这意味着,如果在设置为3个有效数字的直方图中以1微秒至1小时(3,600,000,000微秒)的值记录数据,则对于1毫秒和3.6秒(或更佳)的值,它将保持1微秒的值分辨率 )以获取最大跟踪值(1小时)。

GET exam/_search
{
  "size": 0,
  "aggs": {
    "grade_outlier": {
       "percentiles" : {
                "field" : "grade",
                "percents" : [95, 99, 99.9],
                "hdr": { 
                  "number_of_significant_value_digits" : 3 
                }
            }
    }
  }
  
  {
  "took" : 139,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 6,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "grade_outlier" : {
      "values" : {
        "95.0" : 98.0615234375,
        "99.0" : 98.0615234375,
        "99.9" : 98.0615234375
      }
    }
  }
}

HDRHistogram只支持正的值,如果传递的是负的值,就会出错。如果值的范围未知,则使用HDRHistogram也不是一个好主意,因为这可能导致高内存使用量。

Missing value

missing参数定义应如何处理缺少值的文档。 默认情况下,它们将被忽略,但也可以将它们视为具有值。

Percentile Ranks 聚合

一种多值度量聚合,它计算从聚合文档中提取的数值的一个或多个百分比级别。这些值可以由提供的脚本生成,也可以从文档中的特定数字或直方图字段中提取。

百分数等级显示低于特定值的观察值的百分比。 例如,如果某个值大于或等于观察值的95%,则它被称为第95个百分位等级。

假设您的数据由网站加载时间组成。您可能有一个服务协议,95%的页面加载在500毫秒内完成,99%的页面加载在600毫秒内完成。

GET exam/_search
{
  "size": 0,
  "aggs": {
     "grade_ranks" : {
            "percentile_ranks" : {
                "field" : "grade", 
                "values" : [95, 98]
            }
        }
  }
}

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 6,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "grade_ranks" : {
      "values" : {
        "95.0" : 100.0,
        "98.0" : 100.0
      }
    }
  }
}

其他内容同上一节中的介绍

Stats 聚合

一种多值度量聚合,用于计算从聚合文档中提取的数值上的统计信息。这些值可以从文档中的特定数字字段提取,也可以由提供的脚本生成。

返回的统计信息包括:最小值,最大值,总和,计数和平均值。

POST /exams/_search?size=0&pretty
{
    "aggs" : {
        "grades_stats" : { "stats" : { "field" : "grade" } }
    }
}

{
  "took" : 18,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "grades_stats" : {
      "count" : 3,
      "min" : 1.0,
      "max" : 3.0,
      "avg" : 2.0,
      "sum" : 6.0
    }
  }
}

上面的汇总计算了所有文档的成绩统计。 聚合类型为统计信息,并且字段设置定义了计算统计信息所依据的文档的数字字段。聚合的名称(上面的grades_stats)还用作可以从返回的响应中检索聚合结果的键。

Script

curl -X POST "localhost:9200/exams/_search?size=0&pretty" -H 'Content-Type: application/json' -d'
{
    "aggs" : {
        "grades_stats" : {
             "stats" : {
                 "script" : {
                     "lang": "painless",
                     "source": "doc[\u0027grade\u0027].value"
                 }
             }
         }
    }
}
'

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "grades_stats" : {
      "count" : 1,
      "min" : 1.0,
      "max" : 1.0,
      "avg" : 1.0,
      "sum" : 1.0
    }
  }
}

String Stats聚合

多值指标聚合,用于计算从聚合文档中提取的字符串值的统计信息。 这些值可以从文档中的特定关键字字段检索,也可以由提供的脚本生成。

字符串统计信息聚合返回以下结果:

  • count: 计算非空字段的数量。
  • min_length: 最短项的长度。
  • max_length: 最长项的长度。
  • avg_length: 所有项的平均长度。
  • entropy: 计算了由集合所收集的所有项的香农熵值。香农熵量化了场中包含的信息量。它是一种非常有用的度量方法,用于测量数据集的广泛属性,如多样性、相似性、随机性等。
POST /books/_search?size=0&pretty
{
    "aggs" : {
        "message_stats" : { "string_stats" : { "field" : "author.keyword" } }
    }
}

上面的聚合计算所有文档中作者字段的字符串统计信息。聚合类型是string_stats,而字段参数定义了将对其进行统计的文档的字段。以上将返回以下内容:

{
  "took" : 152,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "message_stats" : {
      "count" : 4,
      "min_length" : 3,
      "max_length" : 3,
      "avg_length" : 3.0,
      "entropy" : 2.2516291673878226
    }
  }
}

字符分布

香农熵值的计算是基于每个字符在聚合收集的所有术语中出现的概率。 要查看所有字符的概率分布,我们可以添加show_distribution(默认值:false)参数。

POST /books/_search?size=0&pretty
{
    "aggs" : {
        "message_stats" : { "string_stats" : { "field" : "author.keyword", "show_distribution": true  } }
    }
}

{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 4,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "message_stats" : {
      "count" : 4,
      "min_length" : 3,
      "max_length" : 3,
      "avg_length" : 3.0,
      "entropy" : 2.2516291673878226,
      "distribution" : {
        "依" : 0.3333333333333333,
        "梁" : 0.16666666666666666,
        "赵" : 0.16666666666666666,
        "军" : 0.16666666666666666,
        "伟" : 0.16666666666666666
      }
    }
  }
}

Sum 聚合

一个单值度量聚合,它汇总从聚合文档中提取的数值。这些值可以从文档中的特定数字字段提取,也可以由提供的脚本生成。

POST /exam/_search?size=0&pretty
{
   "aggs" : {
        "sum_grade" : { "sum" : { "field" : "grade" } }
    }
}

Top Hits聚合

top_hits指标聚合器跟踪要聚合的最相关文档。 该聚合器旨在用作子聚合器,以便可以按存储分区汇总最匹配的文档。 top_hits聚合器可以有效地用于通过存储桶聚合器按某些字段对结果集进行分组。 一个或多个存储桶聚合器确定将结果集切成哪些属性。

选项

  • from:要获取的第一个结果的偏移量。
  • size:每个bucket要返回的最大匹配命中数。默认情况下,返回前三个匹配的结果。
  • sort:热门匹配项应如何排序。 默认情况下,命中按主要查询的分数排序。

支持的功能

top_hits聚合返回常规搜索命中,因为可以支持许多每次命中功能:

  • Highlighting
  • Explain
  • Named filters and queries
  • Source filtering
  • Stored fields
  • Script fields
  • Doc value fields
  • Include versions
  • Include Sequence Numbers and Primary Terms

新建索引

PUT /sales
{
    "mappings": {
        "properties" : {
            "tags" : { "type" : "keyword" },
            "comments" : { 
                "type" : "nested",
                "properties" : {
                    "username" : { "type" : "keyword" },
                    "comment" : { "type" : "text" }
                }
            }
        }
    }
}

放数据

PUT /sales/_doc/1?refresh
{
    "tags": ["book", "auto"],
    "comments": [
        {"username": "赵四", "comment": "这本书系统的介绍了如何养猪,实用"},
        {"username": "张三", "comment": "太棒了,妈妈再也不担心我吃肉了"},
        {"username": "王二", "comment": "恕我直言,这书很垃圾"}
    ]
}

{
  "took" : 21,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.8713851,
    "hits" : [
      {
        "_index" : "sales",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.8713851,
        "_source" : {
          "tags" : [
            "book",
            "auto"
          ],
          "comments" : [
            {
              "username" : "赵四",
              "comment" : "这本书系统的介绍了如何养猪,实用"
            },
            {
              "username" : "张三",
              "comment" : "太棒了,妈妈再也不担心我吃肉了"
            },
            {
              "username" : "王二",
              "comment" : "恕我直言,这书很垃圾"
            }
          ]
        }
      }
    ]
  },
  "aggregations" : {
    "by_sale" : {
      "doc_count" : 3,
      "by_user" : {
        "doc_count_error_upper_bound" : 0,
        "sum_other_doc_count" : 2,
        "buckets" : [
          {
            "key" : "张三",
            "doc_count" : 1,
            "by_nested" : {
              "hits" : {
                "total" : {
                  "value" : 1,
                  "relation" : "eq"
                },
                "max_score" : 0.8713851,
                "hits" : [
                  {
                    "_index" : "sales",
                    "_type" : "_doc",
                    "_id" : "1",
                    "_nested" : {
                      "field" : "comments",
                      "offset" : 1
                    },
                    "_score" : 0.8713851,
                    "_source" : {
                      "username" : "张三",
                      "comment" : "太棒了,妈妈再也不担心我吃肉了"
                    }
                  }
                ]
              }
            }
          }
        ]
      }
    }
  }
}

Value Count聚合

一个单值度量聚合,它计算从聚合文档中提取的值的数量。这些值可以从文档中的特定字段提取,也可以由提供的脚本生成。通常,此聚合器将与其他单值聚合一起使用。例如,在计算avg时,我们可能会对计算平均值的数量感兴趣。

POST /books2/_search?size=0&pretty
{
    "aggs" : {
       "author_count" : { "value_count" : { "field" : "author" } }
    }
}

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "types_count" : {
      "value" : 2
    }
  }
}

Median Absolute Deviation 聚合

这种单值聚合近似于其搜索结果的中值绝对偏差。

中位数绝对偏差是变异性的量度。 这是一个可靠的统计信息,这意味着它对于描述可能具有异常值或未正常分布的数据很有用。 对于此类数据,它比标准偏差更具描述性。

计算为每个数据点与整个样本的中值的偏差的中值。也就是说,对于随机变量X,中值绝对偏差为中值(| median(X)-Xi |)

上述内容为指标聚合的相关内容