在UDAF的每个更新步骤上创建一个新的累加器

时间:2018-01-01 06:49:22

标签: java apache-spark apache-spark-sql

我正在根据UDAF example实施UDAF。 update阶段看起来像这样:

    public void update(MutableAggregationBuffer buffer, Row input) {
    if (!input.isNullAt(0)) {
        String inputKey = input.getString(0);
        Map<String, Long> inputValues = input.<String, Long>getJavaMap(1);
        Map<String, Map<String, Long>> newData = new HashMap<>();

        if (!buffer.isNullAt(0)) {
            Map<String, Map<String, Long>> currData = buffer.<String, Map<String, Long>>getJavaMap(0);
            newData.putAll(currData);
        }
        newData.put(inputKey, inputValues);
        buffer.update(0, newData);
    }
}

您可以看到,在每一步创建一个新的HashMap(newData),并将前一个缓冲区中的数据复制到其中。它看起来很糟糕,不得不创建新的地图并复制所有元素。所以我试过(在我的情况下,我有一个略有不同类型的地图):

bufferJavaMap = buffer.<String, Integer>getJavaMap(0);
bufferJavaMap.put("aaaa", 1);
buffer.update(0, bufferJavaMap);

我收到以下错误:

java.lang.UnsupportedOperationException
   at java.util.AbstractMap.put(AbstractMap.java:209)
   at dns.MergeMapUDAF.update(MergeMapUDAF.java:84)

是否可以更新现有地图?更新此地图的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

  

是否可以更新现有地图?

这是不可能的,但问题比你的问题更复杂。 Spark在getupdate上制作了完整的结构副本,因此即使删除显式副本也无法解决问题。

如果需要性能,则应避免将UserDefinedAggregateFunction与非原子类型一起使用。