【数据蒋堂】第28期:迭代聚合语法

我们讨论过的常规聚合运算如SUM/COUNT和非常规聚合运算如maxp/top,都是事先设计好的聚合函数。但如果我们想实现一个以前没有定义过的运算怎么办?是否可以用已有的语法和函数组合出来?比如想做连乘运算,显然这也算是一种聚合。

要设计这样的语法方案,我们来看看这些聚合结果值是如何被程序计算出来的。

SUM:先设置一个初始值0,然后遍历集合的每个成员,每次将成员值加到初始值上,直到成员被遍历完。
COUNT:设置初始值0,遍历集合成员,每次碰到非空成员将初始值加1,直到遍历完。
AVERAGE:这个不能边遍历边计算了,不过AVERAGE=SUM/COUNT,算是个导出函数,不用考察了。
MAX:设置初始值为无穷小,遍历集合成员,每碰比初始值更大的成员值则替换初值值,直到遍历完。
MIN:和MAX一样,只是初始值和比较方向是反的。

我们发现,这些基本聚合运算的实现方案都有相同的过程:先设置一个初始值,然后遍历集合成员,让当前成员和初始值计算得到一个新的初始值,再进入下一轮循环,直到遍历完整个集成,那个初始值就变成我们需要聚合值了。

这样,我们可以设计一个实现迭代计算的聚合函数:

A.iterate( x, a )

以a为初始值遍历集合A,每次用当前初始值和当前遍历员计算表达式x,得到的结果替换当前初始值,直到遍历完成,返回最后的x值。

这里有个问题,在x中用什么标识符或符号来表示当前初始值和当前成员。当前成员可以用我们以前讨论过的~符号,当前初始值要再找个符号,我们用两个~来表示。

这样,前面那些聚合运算就都可以用这个迭代函数来表示:

A.SUM() = A.iterate( ~~+~, 0 )
A.COUNT() = A.iterate( ~+if(~~,1,0),0 )
A.MAX() = A.iterate( if(~>~~,~,~~), -inf )
A.MIN() = A.iterate( if( ~<~~,~,~~), inf )

连乘当然也很简单了:A.iterate( ~~*~, 1 )

我们提到过的非常规聚合也可以,比如返回单值的maxp可以写成

A.maxp(F) = A.iterate( if (~==null || ~.F>>~~.F,~,~~), null )       这是F表示字段名

但返回集合的情况要麻烦一些:

A.maxp(F) = A.iterate( if(~==null || ~.F>~~.F,~,if(~.F==~~.F,~~|~,~~)), null )       |表示集合的并运算
A.top( n ) = A.iterate( merge(~~,~).to(n), [inf]*n )        merge函数指归并排序运算,to(n)选出集合的前n个成员
A.distinct() = A.iterate( if(~~.contain(~),~,~~|~), [] )         contain函数判断集合是否包含某成员

不过,不是所有的聚合运算都容易用iterate来描述,毕竟聚合运算的定义太宽泛了,比如中位数就不合适用itertate描述。另外,象first/last这种聚合运算不需要遍历,也没必要用iterate描述。

迭代聚合语法不仅能够帮助我们写出一些新的聚合运算,而且它本身就是一种遍历方法。能用迭代语法写出来的聚合运算,都可以一边遍历一边计算,遍历完了就得到聚合值,目标集合只需要遍历一次。

我们知道,计算机不能直接针对外存计算,当数据量很大而不能全部加载进内存时,迭代聚合算法可以只需要较小的内存(能够放下聚合值)就可以完成大数据量的聚合。这对于实现分组后的聚合运算很有意义。

分组子集的总体数据规模和原集是一样大的,基于拆分后的子集再做聚合运算就意味着要遍历两次,对于纯内存运算还不是大问题,但如果数据量大到内存放不下时,就会发生外存倒换的现象,这样效率是非常低的。iterate作为一种聚合运算当然可以用在分组之后,分组后进行能够被iterate描述的聚合运算时,就不需要对原数据遍历两次了,可以一边分组一边聚合,只需要较小的内存(能保存下结果集)就可以完成。

这大概也是SQL没有提供分组子集的原因之一,在发明SQL的那个年代内存很小,绝大多数原始数据都不可能放入内存,先产生分组子集后再聚合的运算效率难以容忍,而分组后直接聚合,且都是可以用iterate描述的聚合,虽然仍然可能发生外存倒换(结果集也装不下内存时)的现象,但问题的严重程度要小很多。

原文发布时间为:2017-10-30
本文作者: 蒋步星
本文来自合作伙伴“数据蒋堂”,了解相关信息可以关注“数据蒋堂”微信公众号

时间: 2024-12-22 21:13:53

【数据蒋堂】第28期:迭代聚合语法的相关文章

开源大数据周刊-第28期

阿里云E-Mapreduce动态 E-Mapreduce产品即将发布的版本信息如下: 1.5.2版本 增加预定制配置,如试用型/入门配置/高计算配置/高存储配置等 1.6.0版本 交互式查询(支持Hive.Spark) 资讯 干货报告丨医疗大数据的行业应用研究 报告从医疗大数据的概念.政策财政支持.发展背景以及现状,到相关具体的应用场景进行了详细介绍,该领域具有广阔的前景. 大数据的价值:找到别人的"集体智慧" 作者为数据咨询师车品觉,文章主要内容:①大数据行业正在发生三大颠覆性变化:

【数据蒋堂】第19期:从SQL语法看集合化

SQL作为最常用的结构化数据计算语言,虽然在做一些细致处理时不太方便,但用于描述基本运算还是比Java等高级语言要简单许多.这是因为SQL是一种集合化的语言,而Java等语言不是.我们下面从SQL的语法上看集合化语言的一些特征,为了方便讨论,我们就用Java作为参照语言,其它高级语言是类似的. 集合运算能力 结构化数据经常是批量(以集合形式)出现的,为了方便地计算这类数据,程序设计语言有必要提供足够的集合运算能力. Java等高级语言则没有直接提供集合运算类库,虽然也有数组(相当于集合)数据类型

【数据蒋堂】第21期:常规遍历语法

遍历可以说是最基本的集合运算了,比如求和.计数.寻找最大最小值等聚合运算,按条件过滤集合.根据集合成员生成另一个新集合,也都是遍历运算.集合化语法要求我们能用很短的语句(经常就只有一句,而不是若干语句构成的一段程序)来描述大部分遍历运算,这样我们需要考查遍历运算中可能出现的各种常见情况,并设计出合理自洽的语法规则. 我们从简单到复杂来考查遍历运算中的可能情况,并讨论SQL语法在这方面的表现. 1. 直接针对集合成员运算 比如计算集合成员的合计. 这是最简单的情况,采用普通的函数语法风格就可以,将

【数据蒋堂】第27期:非常规聚合

标准SQL中提供了五种最常用的聚合运算:SUM/COUNT/AVG/MIN/MAX.观察这几个运算,我们发现它们都可以看成是一个以集合为参数返回单值的函数,我们就先把这个共同点理解为聚合运算的定义,把集合变成单值,多个值变成一个值,也就是发生了"聚合",所以叫聚合运算. 那么很显然,有集合的时候就可以应用聚合运算了,所以SUM/COUNT这些运算可以针对一个数据表(记录集合)实施. 分组运算的结果是一批分组子集,那么每个子集上也可以应用聚合运算,这也就是SQL的分组运算了.其实针对全集

【数据蒋堂】第20期:从SQL语法看离散性

所谓离散性,是指集合的成员可以游离在集合之外存在并参与运算,游离成员还可以再组成新的集合.从离散性的解释上可以知道,离散性是针对集合而言的一种能力,离开集合概念单独谈离散性就没有意义了. 离散性是个很简单的特性,几乎所有支持结构(对象)的高级语言都天然支持,比如我们用Java时都可以把数组成员取出来单独计算,也可以再次组成新的数组进行集合运算(不过Java几乎没有提供集合运算类库). 但是SQL的离散性却很差. SQL体系中有记录的概念,但并没有显式的记录数据类型.单条记录被SQL作为只有一条记

【数据蒋堂】第18期:SQL用作大数据计算语法好吗?

当前的大数据平台在处理结构化数据时大都仍然以提供SQL语法为主流.兼容SQL的好处是很明显的,SQL的应用非常广泛,会SQL的程序员很多,如果继续采用SQL则可以避免许多学习成本.支持SQL的前端软件也很多,使用SQL的大数据平台很容易融入这个现成的生态圈中.大数据平台打算替代的传统数据库也是SQL语法的,这样兼容性会很好,移植成本相对较低. 但继续使用SQL也有缺点,最大的问题就是难以获得大数据计算最需要的高性能. 我们在前面的文章中提到过,SQL中缺乏一些必要的数据类型和运算定义,这使得某些

【数据蒋堂】第31期:JOIN简化 - 维度对齐

那么问题来了,这显然是个有业务意义的JOIN,它算是前面所说的哪一类呢? 这个JOIN涉及了表Orders和子查询A与B,仔细观察会发现,子查询带有GROUP BY id的子句,显然,其结果集将以id为主键.这样,JOIN涉及的三个表(子查询也算作是个临时表)的主键是相同的,它们是一对一的同维表,仍然在前述的范围内. 但是,这个同维表JOIN却不能用上一期说的写法简化,子查询A,B都不能省略不写. 可以简化书写的原因在于:我们假定事先知道数据结构中这些表之关联关系.用技术术语的说法,就是知道数据

【数据蒋堂】第30期:JOIN简化 - 消除关联

我们将等值JOIN分成三种情况来分别讨论,分情况相当于加强了条件,我们可以充分利用每种情况下的特征. 1. 外键属性化 先看个例子,设有如下两个表: employee表和delpartment表的主键都是其中的id字段,employee表的department字段是指向department表的外键,department表的manager字段又是指向employee表的外键.这是很常规的表结构设计. 现在我们想问一下:哪些美国籍员工有一个中国籍经理? 用SQL写出来是这样的: SELECT A.*

数据蒋堂 | 常规遍历语法

遍历可以说是最基本的集合运算了,比如求和.计数.寻找最大最小值等聚合运算,按条件过滤集合.根据集合成员生成另一个新集合,也都是遍历运算.集合化语法要求我们能用很短的语句(经常就只有一句,而不是若干语句构成的一段程序)来描述大部分遍历运算,这样我们需要考查遍历运算中可能出现的各种常见情况,并设计出合理自治的语法规则. 我们从简单到复杂来考查遍历运算中的可能情况,并讨论SQL语法在这方面的表现. 比如计算集合成员的合计. 这是最简单的情况,采用普通的函数语法风格就可以,将待遍历的集合作为参数获得返回