$percentile (聚合)
定义
语法
$percentile
的语法如下
{ $percentile: { input: <expression>, p: [ <expression1>, <expression2>, ... ], method: <string> } }
命令字段
$percentile
以下字段
字段 | 类型 | 必需性 | 描述 |
---|---|---|---|
input | 表达式 | 必需 | $percentile 计算此数据的百分位数。 input 必须是字段名或计算结果为数值类型的表达式。如果表达式无法转换为数值类型,则 $percentile 计算会忽略它。 |
p | 表达式 | 必需 |
|
method | 字符串 | 必需 | mongod 计算百分位数所使用的方法。方法必须是 'approximate' 。 |
行为
您可以在
$group
阶段作为累加器使用$setWindowFields
阶段作为累加器使用$project
阶段作为聚合表达式使用
$percentile
作为累加器具有以下特性:
计算阶段中所有文档的单个结果。
使用t-digest算法来计算基于百分比的近似度量。
使用近似方法扩展到大量数据。
$percentile
作为聚合表达式具有以下特性:
接受数组作为输入
为每个输入文档计算单独的结果
操作类型
在$group
阶段中,$percentile
是一个累加器,为窗口中的所有文档计算一个值。
在$project
阶段中,$percentile
是一个聚合表达式,为每个文档计算值。
在 $setWindowFields
阶段中,$percentile
返回类似于聚合表达式的每个文档的结果,但结果是在文档组上计算的,就像累加器。
计算注意事项
在 $group
阶段中,$percentile
总是使用近似计算方法。
在 $project
阶段中,$percentile
即使指定了近似方法,也可能使用离散计算方法。
在 $setWindowFields
阶段中,工作负载决定了 $percentile
使用的计算方法。
返回的计算的百分位数可能会变化,即使在相同的数据集上。这是因为算法计算近似值。
重复样本可能导致歧义。如果有大量重复的样本,百分位数可能不会代表实际的样本分布。考虑一个所有样本都相同的数据集。数据集中的所有值都处于或低于任何百分位数。实际的“50百分位数”值将代表0或100的样本百分比。
$percentile
返回 p = 0.0
的最小值。
$percentile
返回 p = 1.0
的最大值。
数组输入
如果您将 $percentile
作为聚合表达式在 $project
阶段中使用,您可以使用数组作为输入。语法是
{ $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 } ] )
计算作为累加器的单个值
创建一个累加器,计算单个百分比值
db.testScores.aggregate( [ { $group: { _id: null, test01_percentiles: { $percentile: { input: "$test01", p: [ 0.95 ], method: 'approximate' } }, } } ] )
输出
{ _id: null, test01_percentiles: [ 67 ] }
_id
字段值为 null
,因此 $group
选择集合中的所有文档。
percentile
累加器从 test01
字段获取输入数据。
在这个例子中,百分位数数组 p
只有一个值,所以 $percentile
操作符只为 test01
数据计算一个项。第95个百分位数的值是 67
。
作为累加器计算多个值
创建一个计算多个百分位数值的累加器
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
选择集合中的所有文档。
percentile
累加器为三个字段 test01
、test02
和 test03
计算值。
累加器计算每个输入字段的第50个、第75个、第90个和第95个百分位数值。
百分位数值以与 p
元素相同的顺序返回。在 test03_percentiles
和 test03_percent_alt
中的值相同,但它们的顺序不同。每个结果数组中元素的顺序与 p
中对应元素的顺序相匹配。
在 $project
阶段中使用 $percentile
在$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
要将百分位数值基于本地数据趋势,请在 $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 ] }
在此示例中,每个文档的百分位数计算还结合了其前后三份文档的数据。
了解更多
操作符 $median
是操作符 $percentile
的一个特例,使用固定的值 p: [ 0.5 ]
。
有关窗口函数的更多信息,请参阅: $setWindowFields
.