Docs 菜单

$percentile (aggregation)

$percentile

7.0 版本中的新增功能

返回与指定的各百分位数一一对应的标量值数组。

您可以使用 $percentile 作为 $group 阶段的累加器聚合表达式

$percentile 的语法为:

{
$percentile: {
input: <expression>,
p: [ <expression1>, <expression2>, ... ],
method: <string>
}
}

$percentile接受以下字段:

字段
类型
必要性
说明

input

表达式(expression)

必需

$percentile calculates the percentile values of this data. input must be a field name or an expression that evaluates to a numeric type. If the expression cannot be converted to a numeric type, the $percentile calculation ignores it.

p

表达式(expression)

必需

$percentile calculates a percentile value for each element in p. The elements represent percentages and must evaluate to numeric values in the range 0.0 to 1.0, inclusive.

$percentile returns results in the same order as the elements in p.

method

字符串

必需

The method that mongod uses to calculate the percentile value. The method must be 'approximate'.

您可以在以下位置使用 $percentile

$percentile作为累加器具有以下特征:

  • 为阶段中的所有文档计算单独的结果。

  • 使用 t-digest 算法计算近似的、基于百分位数的指标。

  • 使用近似方法来扩展海量数据。

$percentile作为聚合表达式具有以下特征:

  • 接受数组作为输入

  • 为每个输入文档计算单独的结果

$group 阶段,$percentile 是累加器,计算窗口中所有文档的值。

$project 阶段,$percentile 是一个聚合表达式,用于计算每个文档的值。

$setWindowFields 阶段中,$percentile 像聚合表达式一样返回每个文档的结果,但该结果是通过诸如累加器之类的文档组计算得出的。

$group 阶段中,$percentile 始终使用近似计算方法。

$project 阶段,即使指定了近似方法,$percentile 也可能使用离散计算方法。

$setWindowFields 阶段,工作负载决定了 $percentile 使用的计算方法。

即使在相同的数据集上,计算出的 $percentile 收益的百分位数也可能不同。这是因为算法计算的是近似值。

重复样本可能会导致歧义。如果存在大量重复样本,百分位值可能无法代表实际的样本分布。考虑所有样本都相同的数据集。数据集中的所有值都位于或低于任何百分位数。“第 50 百分位数”的值实际上代表 0 或 100% 的样本。

$percentile returns the minimum value for p = 0.0.

$percentile returns the maximum value for p = 1.0.

If you use $percentile as an aggregation expression in a $project stage, you can use an array as input. The syntax is:

{
$percentile: {
input: [ <expression1, <expression2>, .., <expressionN> ],
p: [ <expression1>, <expression2>, ... ],
method: <string>
}
}

通过窗口函数,您可以计算出相邻文档移动“窗口”的结果。当每份文档通过管道时,$setWindowFields 阶段:

  • 重新计算当前窗口中的文档集

  • 计算集合中所有文档的值

  • 返回该文档的单个值

您可以在 $setWindowFields 阶段使用 $percentile 来计算时间序列或其他相关数据的滚动统计数据。

$setWindowField 阶段使用 $percentile 时,input 值必须是字段名。如果输入数组而不是字段名称,则操作将失败。

以下示例使用 testScores 集合。创建集合:

db.testScores.insertMany( [
{ studentId: "2345", test01: 62, test02: 81, test03: 80 },
{ studentId: "2356", test01: 60, test02: 83, test03: 79 },
{ studentId: "2358", test01: 67, test02: 82, test03: 78 },
{ studentId: "2367", test01: 64, test02: 72, test03: 77 },
{ studentId: "2369", test01: 60, test02: 53, test03: 72 }
] )

Create an accumulator that calculates a single percentile value:

db.testScores.aggregate( [
{
$group: {
_id: null,
test01_percentiles: {
$percentile: {
input: "$test01",
p: [ 0.95 ],
method: 'approximate'
}
},
}
}
] )

输出:

{ _id: null, test01_percentiles: [ 67 ] }

_id 字段值为 null,因此 $group 选择集合中的所有文档。

The percentile accumulator takes its input data from the test01 field.

In this example, the percentiles array, p, has one value so the $percentile operator only calculates one term for the test01 data. The 95th percentile value is 67.

Create an accumulator that calculates multiple percentile values:

db.testScores.aggregate( [
{
$group: {
_id: null,
test01_percentiles: {
$percentile: {
input: "$test01",
p: [ 0.5, 0.75, 0.9, 0.95 ],
method: 'approximate'
}
},
test02_percentiles: {
$percentile: {
input: "$test02",
p: [ 0.5, 0.75, 0.9, 0.95 ],
method: 'approximate'
}
},
test03_percentiles: {
$percentile: {
input: "$test03",
p: [ 0.5, 0.75, 0.9, 0.95 ],
method: 'approximate'
}
},
test03_percent_alt: {
$percentile: {
input: "$test03",
p: [ 0.9, 0.5, 0.75, 0.95 ],
method: 'approximate'
}
},
}
}
] )

输出:

{
_id: null,
test01_percentiles: [ 62, 64, 67, 67 ],
test02_percentiles: [ 81, 82, 83, 83 ],
test03_percentiles: [ 78, 79, 80, 80 ],
test03_percent_alt: [ 80, 78, 79, 80 ]
}

_id 字段值为 null,因此 $group 选择集合中的所有文档。

The percentile accumulator calculates values for three fields, test01, test02, and test03.

The accumulator calculates the 50th, 75th, 90th, and 95th percentile values for each input field.

The percentile values are returned in the same order as the elements of p. The values in test03_percentiles and test03_percent_alt are the same, but their order is different. The order of elements in each result array matches the corresponding order of elements in p.

$project 阶段,$percentile 是一个聚合表达式,用于计算每个文档的值。

您可以在 $project 阶段使用字段名称或数组作为输入。

db.testScores.aggregate( [
{
$project: {
_id: 0,
studentId: 1,
testPercentiles: {
$percentile: {
input: [ "$test01", "$test02", "$test03" ],
p: [ 0.5, 0.95 ],
method: 'approximate'
}
}
}
}
] )

输出:

{ studentId: '2345', testPercentiles: [ 80, 81 ] },
{ studentId: '2356', testPercentiles: [ 79, 83 ] },
{ studentId: '2358', testPercentiles: [ 78, 82 ] },
{ studentId: '2367', testPercentiles: [ 72, 77 ] },
{ studentId: '2369', testPercentiles: [ 60, 72 ] }

$percentile 是聚合表达式时,每个 studentId 都有一个结果。

如需根据本地数据趋势确定百分位值,请使用 $setWindowField 聚合管道阶段的 $percentile

此示例创建了一个筛选分数的窗口:

db.testScores.aggregate( [
{
$setWindowFields: {
sortBy: { test01: 1 },
output: {
test01_95percentile: {
$percentile: {
input: "$test01",
p: [ 0.95 ],
method: 'approximate'
},
window: {
range: [ -3, 3 ]
}
}
}
}
},
{
$project: {
_id: 0,
studentId: 1,
test01_95percentile: 1
}
}
] )

输出:

{ studentId: '2356', test01_95percentile: [ 62 ] },
{ studentId: '2369', test01_95percentile: [ 62 ] },
{ studentId: '2345', test01_95percentile: [ 64 ] },
{ studentId: '2367', test01_95percentile: [ 67 ] },
{ studentId: '2358', test01_95percentile: [ 67 ] }

In this example, the percentile calculation for each document also incorporates data from the three documents before and after it.

The $median operator is a special case of the $percentile operator that uses a fixed value of p: [ 0.5 ].

有关窗口函数的更多信息,请参阅:$setWindowFields