(一)先了解一下什么是自定义聚合函数
- 其实就是根据你自己的业务去进行定义你自己想要实现的方法,比如说Mysql中的sum() 方法,就是求某个字段的累加之和,那么你就可以自己实现自己的 比如说 add() 自定义聚合函数方法
(二)如何开发自定义聚合函数
- 首先需要实现Presto提供的Plugin接口,然后把要实现的聚合函数所在的类添加到集合中
package com.tapdb.analytics.presto.udaf;
import com.google.common.collect.ImmutableSet;
import io.prestosql.spi.Plugin;
import java.util.Set;
public class TapdbAnalyticsPlugin implements Plugin {
@Override
public Set<Class<?>> getFunctions() {
return ImmutableSet.<Class<?>>builder()
.add(DateHistogramAggregation.class)
.add(ArraySumAggregation.class)
.add(ArrayConstructScalar.class)
.add(RetentionAggregation.class)
.add(DecodeBitSetAggregation.class)
.build();
}
}
- 然后把你想要处理的字段根据其类型传入input()方法的参数中进行处理,这里需要注意如何把你处理好的结果集传给下一个combine()方法,需要通过SliceState进行作为桥梁,当然这个也可以自己进行自定义,output()方法是把最后的结果集进行构造然后,通过Presto提供的API进行构建返回结果。
package com.tapdb.analytics.presto.udaf;
import io.airlift.slice.Slice;
import io.airlift.slice.Slices;
import io.prestosql.spi.block.BlockBuilder;
import io.prestosql.spi.function.*;
import io.prestosql.spi.type.StandardTypes;
@AggregationFunction("tapdb_bitset_decode")
public class DecodeBitSetAggregation {
@InputFunction
public static void input(@AggregationState SliceState state,
@SqlType(StandardTypes.BIGINT) long mask,
@SqlType(StandardTypes.BIGINT) long value) {
if (state.getSlice() == null) {
long capacity = 30 * Long.BYTES;
Slice slice = Slices.allocate((int) capacity);
state.setSlice(slice);
}
Slice slice = state.getSlice();
long retainValue = mask <= 0 ? value ^ mask : value & mask;
int tmpIndex = 0;
for (int i = 29; i >= 0; i--) {
int offset = Long.BYTES * tmpIndex;
slice.setLong(offset, Long.lowestOneBit(retainValue) == 1 ? 1L : 0L);
retainValue = retainValue >> 1;
tmpIndex++;
}
}
@CombineFunction
public static void combine(@AggregationState SliceState state, @AggregationState SliceState otherState) {
Slice otherSlice = otherState.getSlice();
Slice slice = state.getSlice();
if (otherSlice == null) {
return;
}
if (slice == null) {
state.setSlice(otherSlice);
return;
}
int indexNum = slice.length() / Long.BYTES;
for (int i = 0; i < indexNum; ++i) {
int offset = i * Long.BYTES;
slice.setLong(offset, slice.getLong(offset) + otherSlice.getLong(offset) > 0 ? 1L : 0L);
}
}
@OutputFunction("array(bigint)")
public static void output(@AggregationState SliceState state, BlockBuilder out) {
Slice slice = state.getSlice();
if (slice == null) {
out.appendNull();
return;
}
int byteArrayNum = slice.length() / Long.BYTES;
BlockBuilder blockBuilder = out.beginBlockEntry();
for (int i = 0; i < byteArrayNum; ++i) {
int offset = i * Long.BYTES;
long value = slice.getLong(offset);
blockBuilder.writeLong(value).closeEntry();
}
out.closeEntry();
}
}
- 就是把这个项目打包成一个jar包,然后放到Presto集群所有机器下面的plugin目录下(这里需要自己随便创建一个目录,然后放到自己创建的目录下),然后就是重启集群,使用show functions 查看一下自己定义的聚合函数是不是注册成功,如果成功如图这种。