(一)先了解一下什麼是自定義聚合函數
- 其實就是根據你自己的業務去進行定義你自己想要實現的方法,比如說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 查看一下自己定義的聚合函數是不是註冊成功,如果成功如圖這種。