当前位置:   article > 正文

MongoDB聚合运算符:$percentile

MongoDB聚合运算符:$percentile


$percentile聚合运算符返回与指定百分位值相对应的标量值数组。 $percentile可以用作 $group阶段的累加器或聚合表达式。

语法

{
   $percentile: {
      input: <expression>,
      p: [ <expression1>, <expression2>, ... ],
      method: <string>
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

参数字段说明

字段类型是否必须说明
input表达式$percentile计算input数据的百分位值。input必须是字段或数值表达式,如果表达式无法转换为数值类型将被忽略
p表达式$percentile计算p中每个元素的百分位值,这些元素表示百分比,并且计算结果必须为0.01.0(含)范围内的数值。$percentile返回结果的顺序与p中元素的顺序相同
method字符串mongod用于计算百分位值的方法,值必须是"approximate"

使用

  • $percentile可以在$group$setWindowFields作为累加器使用,在$project阶段可以作为聚合表达式使用。
  • $percentile做为累加器使用时,具有下面的特性:
    • 在结算阶段,所有的文档只有一个结果。
    • 使用 t-digest 算法计算基于百分位数的近似指标。
    • 使用近似方法来扩展大量数据。
  • $percentile做为表达式使用时,具有下面的特性:
    • 接受数组作为输入
    • 为每个输入文档计算单独的结果

操作类型

  • $group阶段,$percentile是一个累加器,用于计算窗口中所有文档的值。
  • $project阶段,$percentile是一个聚合表达式,用于计算每个文档的值。
  • $setWindowFields阶段,$percentile会像聚合表达式一样返回每个文档的结果,但其结果会像累加器一样在文档组中计算。

计算时的注意事项

  • $group阶段,$percentile总是使用近似计算方法。
  • $project阶段,即使指定了近似计算方法,$percentile也可能使用离散计算方法。
  • $setWindowFields阶段,计算量决定了$percentile使用的计算方法。
  • 因为算法计算的是近似值,所以即使在相同的数据集上,$percentile返回的计算百分位数也可能不同。
  • 重复样本会导致模糊性。如果存在大量重复样本,百分位数值可能无法代表实际的样本分布,如果一个所有样本都相同的数据集,数据集中的所有值都位于或低于任何一个百分位数,50%的百分位数值实际上代表0100%的样本。
  • p = 0.0时,$percentile返回最小值。
  • p = 1.0时,$percentile返回最大值。*

input为数组

如果在$project阶段使用$percentile作为聚合表达式,则可以使用数组作为输入。语法是:

{
   $percentile: {
      input: [ <expression1, <expression2>, .., <expressionN> ],
      p: [ <expression1>, <expression2>, ... ],
      method: <string>
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

窗口功能

通过窗口函数可以计算出相邻文档移动 "窗口 "的结果。。当每个文档通过管道时,当每个文件通过管道时,$setWindowFields 阶段就会:

  • 重新计算当前窗口中的文档集合
  • 计算集合中所有文档的值
  • 返回该文档的单个值

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

$setWindowField阶段使用$percentile时,输入值必须是字段名称,否则操作将失败。

举例

使用下面的脚本创建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 }
] )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

作为累加器计算单个值

下面的聚合,使用$percentile创建一个累加器,计算单个百分位值:

db.testScores.aggregate( [
   {
      $group: {
         _id: null,
         test01_percentiles: {
            $percentile: {
               input: "$test01",
               p: [ 0.95 ],
               method: 'approximate'
            }
         },
      }
   }
] )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

聚合结果:

{ _id: null, test01_percentiles: [ 67 ] }
  • 1

在本例中:

  • _id字段值为空,所以$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'
             }
          },
       }
    }
] )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

聚合结果:

{
    _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 ]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在本例中:

  • _id字段值为null,因此$group选中了集合中的所有文档。
  • 百分位数累加器计算三个字段test01test02test03的值。
  • 累加器计算每个输入字段的第50、75、90 和 95个百分位值。
  • 百分位数值的返回顺序与p的元素相同。test03_percentilestest03_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'
            }
         }
      }
   }
] )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

聚合结果:

{ 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 ] }
  • 1
  • 2
  • 3
  • 4
  • 5

$percentile为聚合表达式时,每个StudentId都会有一个结果。

$setWindowFields阶段使用$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
      }
   }
] )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

聚合结果为:

{ 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 ] }
  • 1
  • 2
  • 3
  • 4
  • 5

在本例中,每个文档的百分位数计算也包含了前后三个文档的数据。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/655285
推荐阅读
相关标签
  

闽ICP备14008679号