Spark 2.2+Java8:含List元素的Tuple2元组编码器实现问题
解决Spark 2.2中Tuple2<Foo, List>的编码器问题
嗨,这个场景我之前在做Spark Java开发时碰到过,确实一对一的Tuple编码器很好搞,但带集合的Tuple2得稍微调整下思路,给你两个实用的方案:
方案一:直接构造Tuple2编码器(利用Encoders.collection)
Spark的Encoders类提供了collection方法,可以为集合类型生成编码器,我们可以把它和Encoders.tuple结合起来,直接构造目标类型的编码器:
// 先构造List<Bar>的编码器 Encoder<List<Bar>> barListEncoder = Encoders.collection(List.class, Encoders.bean(Bar.class)); // 再构造Tuple2<Foo, List<Bar>>的编码器 Encoder<Tuple2<Foo, List<Bar>>> fooBarListEncoder = Encoders.tuple( Encoders.bean(Foo.class), barListEncoder );
小提示
如果碰到List接口的兼容问题,可以换成具体的实现类,比如ArrayList.class:
Encoder<ArrayList<Bar>> barArrayListEncoder = Encoders.collection(ArrayList.class, Encoders.bean(Bar.class));
方案二:自定义POJO替代Tuple2(更推荐)
Tuple2的字段名是_1、_2,后续做数据操作(比如select、filter)时可读性很差,而且扩展字段也不方便。更稳妥的方式是定义一个包含Foo和ListEncoders.bean生成编码器:
第一步:定义POJO类
import java.io.Serializable; import java.util.List; public class FooWithBars implements Serializable { // 必须要有无参构造函数,Spark Bean编码器要求 public FooWithBars() {} // 带参构造函数(可选,方便实例化) public FooWithBars(Foo foo, List<Bar> bars) { this.foo = foo; this.bars = bars; } // 所有字段的getter和setter必须齐全 private Foo foo; private List<Bar> bars; public Foo getFoo() { return foo; } public void setFoo(Foo foo) { this.foo = foo; } public List<Bar> getBars() { return bars; } public void setBars(List<Bar> bars) { this.bars = bars; } }
第二步:生成编码器
Encoder<FooWithBars> fooWithBarsEncoder = Encoders.bean(FooWithBars.class);
关键注意事项
- 不管用哪种方案,
Foo和Bar类都必须满足:有无参构造函数、所有字段都有对应的getter和setter、实现Serializable接口,否则Spark的Bean编码器会抛出异常。 - 方案二的POJO方式在长期维护中更友好,尤其是团队协作时,明确的字段名比Tuple的
_1、_2好理解太多。
内容的提问来源于stack exchange,提问作者HansGruber
相关产品推荐
相关产品推荐

