使用flink实时计算各商品品类的同一天的销售总额,使用滚动窗口,窗口函数使用的增量聚合窗口,自定义AggregateFunction。
刚开始是这样定义的:
private static class MyAggregate implements AggregateFunction<Tuple2<String,Double>, Double, Double> {
double accumulator;
@Override
public Double createAccumulator() {
System.out.println(this.toString()+":"+Thread.currentThread().getId());
return accumulator = 0;
}
@Override
public Double add(Tuple2<String,Double> tuple2, Double accumulator) {
this.accumulator = tuple2.f1 + accumulator;
return this.accumulator;
}
@Override
public Double getResult(Double aDouble) {
return accumulator;
}
@Override
public Double merge(Double aDouble, Double acc1) {
return aDouble + acc1;
}
}
运行的时候发现一个严重的问题,随着时间的推移,每个品类的销售额应该是递增的,结果发现有不增反减的情况。
分析:测试环境一共有13个品类,并行度是8,说明存在多个key被一个算子处理的情况,而对于keyStream来说,每一个key都会有自己单独的状态,每一个key都会调用一次MyAggregate的createAccumulator方法,每次累加都会调用add方法,而自定义的add方法返回的是对象定义的accumulator变量,这样写会被多个key共用状态,必然会出现错误。
正确的方式是去掉类变量:
private static class MyAggregate implements AggregateFunction<Tuple2<String,Double>, Double, Double> {
@Override
public Double createAccumulator() {
System.out.println(this.toString()+":"+Thread.currentThread().getId());
return 0d;
}
@Override
public Double add(Tuple2<String,Double> tuple2, Double accumulator) {
return tuple2.f1 + accumulator;
}
@Override
public Double getResult(Double accumulator) {
return accumulator;
}
@Override
public Double merge(Double aDouble, Double acc1) {
return aDouble + acc1;
}
}