我有2个PCollection<KV<String, String>>
,一个是〜150M,第二个是〜2B。
我想做的是计算两个PCollection
中每个唯一值对的出现次数。
所以我在这两个PCollections上做了一个CoGroupByKey
,问题是CoGbkResult
中的一些(〜5M)非常大(我在Dataflow中收到日志消息说CoGbkResult
具有超过10K的结果),因为在两个集合中每个密钥都可能出现多次,并且这会导致获取这些密钥的工作程序中的运行时间非常长。
理想情况下,我希望CoGroupByKey
返回一个PCollection
,其中包含由密钥共同分组的两个PCollection
的所有值对,因此我无法以某种方式对它们进行计数并行化效果更好。
我一直在阅读有关此问题的信息,但似乎没有适合我的解决方案(大多数解决方案包括使用Combine.WithHotKeyFanout
),因为在合并之前,我需要一个额外的映射步骤,这将永远花费时间,因为CoGbkResult
的大小。
有什么建议可以解决这个问题吗?
答案 0 :(得分:1)
您是否可以重新格式化数据,以便将CoGroupByKey
替换为CombinePerKey
?
CoGroupByKey
和GroupByKey
正在建立所有匹配项的列表,这些列表可能会变得很大,但是您只关心计数正确吗?因此,您可以将CombinePerKey
与CombineFn
一起使用,以对它们的出现进行计数
通过以下方式重新格式化您的PCollections:
pcoll_a = [('abc','123'), ('abc', '456'), ...]
pcoll_b = [('abc','123'), ('xyz', '456'), ...]
变成这样:
pcoll_a = [('abc,123', 'A'), ('abc,456', 'A'), ...]
pcoll_b = [('abc,123', 'B'), ('xyz,456', 'B'), ...]
将这两个PCollection放在一起:
pcoll_combined = [('abc,123', 'A'), ('abc,456', 'A'), ('abc,123', 'B'), ('xyz,456', 'B'), ...]
将此数字与CombinePerKey
一起传递到CombineFn
,该数字将随您的需求加总。像这样:
class CountFn(apache_beam.core.CombineFn):
def _add_inputs(self, elements, accumulator=None):
accumulator = accumulator or self.create_accumulator()
for obj in elements:
if obj == 'A':
accumulator['sum_A'] += 1
if obj == 'B':
accumulator['sum_B'] += 1
return accumulator
def create_accumulator(self):
return {'sum_A': 0, 'sum_B': 0}
def add_input(self, accumulator, element, *args, **kwargs):
return self._add_inputs(elements=[element], accumulator=accumulator)
def add_inputs(self, accumulator, elements, *args, **kwargs):
return self._add_inputs(elements=elements, accumulator=accumulator)
def merge_accumulators(self, accumulators, *args, **kwargs):
return {
'sum_A': sum([i['sum_A'] for i in accumulators]),
'sum_B': sum([i['sum_B'] for i in accumulators])}
def extract_output(self, accumulator, *args, **kwargs):
return accumulator