0

我正在尝试做一些看起来相对简单但遇到一些困难的事情。

我有一堆文本,每一行都是一个值。我分析每一行文本,创建适当的密钥,然后发出 KV 对。然后我使用GroupByKey变换。最后,我想输出现在按键分组的所有文本(如果我可以为每个键获取一个文本文件,则加分,但我不确定这是否可能)。

这是管道的apply样子:

    public PCollection<String> apply(PCollection<String> generator) {

        // Returns individuals lines of text as <String,String> KV pairs
        PCollection<KV<String,String>> generatedTextKV = generator.apply(
                ParDo.of(new GeneratorByLineFn()));

        // Groups the <String,String> KV pairs by value
        PCollection<KV<String, Iterable<String>>> groupedText = generatedTextKV.apply(
            GroupByKey.<String, String>create());

        // Hopefully returns output where all of each key's values are together
        PCollection<String> results = groupedText.apply(ParDo.of(new FormatOutputFn()));

        return results;
    }

不幸的是,我无法FormatOutputFn()按要求工作。

迭代Iterable<String>并输出每个值并不能保证键值分组(如果我对此有误,请纠正我,然后我的问题就解决了)。然后我尝试使用StringBuilder(),它适用于小型数据集,但不出所料地java.lang.OutOfMemoryError: Java heap space在较大数据的日志中生成错误。我也尝试了Flatten.FlattenIterables转换,但这也不起作用,因为 K,V 对中的值不是 a PCollection,而只是一个常规Iterable

我已经看过这个关于通过 common key 分析的问题,但是从答案来看,我并不完全清楚我应该如何处理我的情况。我想我必须使用Combine.PerKey,但我不确定如何使用它。我还假设必须有一种预烘焙的方式来做到这一点,但我在文档中找不到这种预烘焙的方式。我确定我只是没有找对地方。

而且,如上所述,如果有一种方法可以获取文本文件输出,其中文本文件的名称是键并且值都在文件中,那将是惊人的。但我不认为 Dataflow 可以做到这一点(还没有?)。

感谢您的阅读。

4

1 回答 1

3

Dataflow 目前不支持任何对 PCollection 进行排序的概念。您是正确的,不能保证“结果”具有排序,包括键分组。我们希望在某个时候为 PCollections 添加排序属性,但具体的时间表尚不清楚。

由于底层实现细节,某些跑步者在某些情况下可能看起来有顺序。例如,如果 FormatOutputFn 与 Write 步骤融合,那么您很可能会看到分组,因为每个都KV<K, Iterable<V>>被处理成多个<K,V>s,这些 s 在处理下一个之前写入文件KV<K, Iterable<V>>。但同样,这只是 Dataflow 如何选择优化这种特殊情况的产物,不应普遍依赖。

正如您已经发现的那样,如果单个元素可以放入内存,您可以让 FormatOutputFn 将每个元素转换KV<K, Iterable<V>>为包含多个换行符的单个字符串。

鉴于这里不是这种情况,我能想到的最佳解决方案是手动编写文件——因此 FormatOutputFn 获取每个文件KV<K, Iterable<V>>并使用标准 GCS 库打开一个名为 K 的文件并将其写入Iterable<V>。坏消息是这有点棘手,因为您需要了解我们的容错语义如何重试元素。但好消息是,我们目前正在开发库以帮助简化这些类型的自定义接收器。

至于零长度文件,这里有一个很棒的答案:为什么在运行管道时将零字节文件写入 GCS?

于 2015-03-20T04:28:53.450 回答