我使用Java中的Spark Streaming构建了一个原型应用程序,它使用HyperLogLog从模拟的点击流中估算不同的用户。
让我简要勾勒出我的解决方案。首先,我使用KafkaUtils创建一个流:
JavaPairReceiverInputDStream<String, String> directKafkaStream = KafkaUtils.createStream(streamingContext, ZOOKEEPER_ADDRESS, ZOOKEEPER_GROUP, topics);
从那里我创建了一个只包含必填字段的流,fullvisitorid:
JavaDStream<String> fullvisitorids = directKafkaStream.map(line -> line._2().split(",")[0]);
要维护全局状态(我的HyperLogLog-Object),我发现的唯一方法是udpateStateByKey或mapWithState方法。两者似乎都需要键值对......但在我的用例中我不需要键。
所以我决定使用“虚拟钥匙”:
fullvisitorids.mapToPair(value -> new Tuple2<String, String>("key", value));
但现在我的问题:
a)Spark如何使用updateStateByKey或mapWithState在只有一个密钥的流上并行化转换?或者它如何在集群上划分RDD?
b)对于我的问题,是否有一个比添加一个根本没有任何功能的虚拟键更好的解决方案?
答案 0 :(得分:1)
a)如果您使用具有单个值的哈希分区程序,则不会并行化流。定义您自己的分区程序或不使用单个密钥。
b)解决方案是不使用updateStateByKey
,它不适用于全局状态。您应该只使用全局单个HLL对象,例如来自Algebird(here is a Gist that demonstrates how this might look)。