批量数据的聚合以及groupby实现

大家一定对sql非常熟悉,关系型数据库自不必说,现在越来越多的大数据系统也都支持sql,比如hive,odps ,presto,phoenix(hbase),galaxy 以及cep(esper)等都支持sql,或者类sql语言。sql语言更接近自然语言,让人非常容易理解,上手也比较方便,可以有效降低系统的入门门槛。很多大数据系统都用antlr来实现sql,antlr帮助我们实现sql语法解析和编译、抽象语法树啊一些复杂的概念,在antlr的帮助下,简单了很多。

sql可以帮助我们实现sum,avg,max,min,count等简单的聚合计算,还可以依靠parsiihttps://github.com/scireum/parsii)这种表达式解析工具实现更复杂的表达式条件过滤功能。

sql看起来是对静态数据集的一种计算操作,比如select sum(field1) from tablex,是对表tablex的某一个字段进行加和操作,数据库的表相对来讲是一个静态的数据集。但其实sql还支持流数据的计算,对静态数据集和对流数据计算本质上并没有什么区别,都是单条记录,单个事件,或者tuple之类的数据单元分别计算后再聚合的结果。

不同系统的sql被antlr编译解析完成的执行计划也完全不同,hive是mr job,galaxy是storm topology等,那么假设我们现在有一批窗口数据,或者说有限数据集,如何完成这些数据按照字段分组聚合的功能?

有时候我们会在storm中完成一些聚合操作(非trident),那就需要你自己实现groupby之类的逻辑,当然我们也可以选择Esper或者siddhi这种开源cep引擎,你只需要写写sql就可以实现你的逻辑,但是一般cep 引擎比较消耗内存和cpu,而我们仅仅需要一些基础聚合功能,用它显得不划算。

那么现在我们就自己实现一个简单的分组聚合引擎:
1、首先定义一个Javabean,用来描述一种类型的事件或者叫record,包含事件的schema和一些标签数据

import java.io.Serializable;
import java.util.Map;


public class EventBase implements Serializable{

	private long timestamp;
	private Map<String, String> tags;

	public EventBase(){
	}
	public long getTimestamp() {
		return timestamp;
	}
	public void setTimestamp(long timestamp) {
		this.timestamp = timestamp;
	}
	public Map<String, String> getTags() {
		return tags;
	}
	public void setTags(Map<String, String> tags) {
		this.tags = tags;
	}
	
	public String toString(){
		StringBuffer sb = new StringBuffer();
		sb.append("prefix:");
		sb.append(", timestamp:");
		sb.append(timestamp);
		sb.append(", humanReadableDate:");
		sb.append(timestamp);
		sb.append(", tags: ");
		if(tags != null){
			for(Map.Entry<String, String> entry : tags.entrySet()){
				sb.append(entry.toString());
				sb.append(",");
			}
		}
		sb.append(", encodedRowkey:");
		return sb.toString();
	}


}

 
用户可以继承该事件,实现自己的事件的定义,比如:

public class TestEvent extends EventBase {
    private int numHosts;
    private Long numClusters;

    public int getNumHosts() {
        return numHosts;
    }

    public void setNumHosts(int numHosts) {
        this.numHosts = numHosts;
    }

    public Long getNumClusters() {
        return numClusters;
    }

    public void setNumClusters(Long numClusters) {
        this.numClusters = numClusters;
    }
    public String toString(){
        StringBuffer sb = new StringBuffer();
        sb.append(super.toString());
        return sb.toString();
    }
}

 

2、弄一个聚合接口,然后实现它
public interface Aggregator {
	public void process(EventBase event) throws Exception;
}

 3、定义聚合类型,目前先支持sum,avg,max,min,count这5种类型

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public enum AggregateType {
	count("^(count)$"),
	sum("^sum\\((.*)\\)$"),
	avg("^avg\\((.*)\\)$"),
	max("^max\\((.*)\\)$"),
	min("^min\\((.*)\\)$");
	
	private Pattern pattern;
	private AggregateType(String patternString){
		this.pattern = Pattern.compile(patternString);
	}

	public AggregateTypeMatcher matcher(String function){
		Matcher m = pattern.matcher(function);

		if(m.find()){
			return new AggregateTypeMatcher(this, true, m.group(1));
		}else{
			return new AggregateTypeMatcher(this, 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值