SemDB 示例教程
数据变换:分组规约

我们接续上一个教程的结果继续操作。

分组规约是一种特殊的表格变换,能够将表格内的行进行分组并利用规约函数将每一组内的结果转化为综合性信息。 为了展示分组规约变换的效果,我们先定义两个自定义函数:

  // group function
  function (param) {
    if (param <= 3) return 0
    if (param <= 6) return 1
    return 2
  }

  // sum function
  function (params) {
    var sum = 0
    for (var i = 0; i < params.length; ++i)
      sum += params[i][0]
    return sum
  }

有了这两个函数,我们就可以定义一个分组规约变换:

{
  "select": ["group(id) AS group", "A", "B"],
  "from": ["dir.a"],
  "map": ["group"],
  "reduce": ["sum(A) as sumA", "sum(B) as sumB"]
}

在这个例子中,我们首先将id通过自定义函数 group 转化为分组序号,然后再通过分组规约步骤, 分别计算每一组内 A 和 B 属性的和。

我们稍微详细的看一下上面的例子。事实上,分组规约是一个在常规查询语句之后的可选步骤, 在 map 部分指定分组所用的属性,并在 reduce 部分指定每个组别内执行的规约函数。

分组时,我们可以指定多个属性,这样所有指定的属性会协同进行分组操作:

{
  "select": ["group(id) AS group1", "group(A) AS group2", "B"],
  "from": ["dir.a"],
  "map": ["group1", "group2"],
  "reduce": ["sum(B) as sumB"]
}

结果如下:

我们可以看到由于指定了两个分组属性,因此一共被分成了 8 个组。

此外,规约函数也可以有多个输入输出,如下例所展示:

// stat function
function (params) {
  var sumA = 0, sumB = 0
  for (var i = 0; i < params.length; ++i) {
    sumA += params[i][0]
    sumB += params[i][1]
  }
  return [sumA, sumB]
}

那么我们考虑下面的分组规约视图:

{
  "select": ["group(id) AS group", "A", "B"],
  "from": ["dir.a"],
  "map": ["group"],
  "reduce": ["stat(A, B) as sumA, sumB"]
}

最终结果和第一个分组规约例子的结果相同。

© 2025