用于在Dataflow中分组的自定义键

时间:2019-03-29 08:52:32

标签: google-cloud-dataflow apache-beam

我希望能够通过自定义键使用分组,但是到目前为止,这是我的尝试,

我们将自定义类用于KV对象的键,因为我们希望GroupBy具有更复杂的条件,而不是使用String等进行简单的键匹配。

```

    PCollection<KV<Multikey, Iterable<SomeObject>> pc2 = 
    pc.apply(GroupByKey.<Multikey, SomeObject>create());

```

使用equals方法表达匹配条件。

```
    class Multikey implements Serializable{

        List<String> keys = new ArrayList<>();  //multiple key

        ......
        @Override
        public boolean equals(Object k){
            ...join conditions
        }
    }

```

但是我得到一个错误。

java.lang.IllegalStateException: the keyCoder of a GroupByKey must be deterministic
    at org.apache.beam.sdk.transforms.GroupByKey.expand(GroupByKey.java:193)
    at org.apache.beam.sdk.transforms.GroupByKey.expand(GroupByKey.java:107)
    at org.apache.beam.sdk.Pipeline.applyInternal(Pipeline.java:537)
    at org.apache.beam.sdk.Pipeline.applyTransform(Pipeline.java:471)
    at org.apache.beam.sdk.values.PCollection.apply(PCollection.java:357)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:282)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.beam.sdk.coders.Coder$NonDeterministicException: org.apache.beam.sdk.coders.SerializableCoder@18b411b5 is not deterministic because:
    Java Serialization may be non-deterministic.
    at org.apache.beam.sdk.coders.SerializableCoder.verifyDeterministic(SerializableCoder.java:205)
    at org.apache.beam.sdk.transforms.GroupByKey.expand(GroupByKey.java:191)

似乎“键”的序列化顺序是错误的,因此我实现了自定义序列化器或尝试了各种编码器,但是没有用。

2 个答案:

答案 0 :(得分:1)

请注意GroupByKey documentation

  

不通过常规Java Object.equals(java.lang.Object)比较K类型的两个键是否相等,而是首先使用输入PCollection的键的Coder编码每个键,然后进行比较编码的字节。这承认了有效的并行评估。请注意,这要求键的编码器是确定性的(请参阅Coder.verifyDeterministic())。如果关键编码器不确定,则在管道构建时将引发异常。

一种可能的方法:根据您提到的复杂的条件逻辑,使用一个输出KV的pardo,使用唯一键作为字符串输出值。

另一种方法是使用自定义对象类型作为键,而不是字符串,就像您到目前为止已经尝试过的那样。您将需要实现一个CustomCoder,它相当于代表相同密钥的两个对象的字节大小。

这是specifying coders上的Apache Beam文档。

这是一篇博客文章,其中包含一些自定义编码器examples as well

此外,Re:异常本身。请参阅verifyDeterministic文档,以查看description of a deterministic coder。您很可能违反了此约束。

答案 1 :(得分:0)

谢谢。我读了文件。

我将解释为什么要使用自定义键。

那是因为我们要表达“或”之类的析取语,而不是常规组合。

    class Multikey implements Serializable
        List <String> keys = new ArrayList <> ();

........

        @Override
        public boolean equals (Object k) {
            if (k instanceof Multikey) {
                List <String> ky = new ArrayList <String> (((Multikey) k) .keys);
                // Representation of disjunction
                ky.retainAll (keys);
                return! ky.isEmpty ();

            } else {
                return false;
            }
    }

我阅读了文档,但是似乎GroupBy的密钥需要是一个确定性值。 在分组中难于表达分离吗?