我想实现一个class
有一个函数从hbase通过spark读取,像这样:
public abstract class QueryNode implements Serializable{
private static final long serialVersionUID = -2961214832101500548L;
private int id;
private int parent;
protected static Configuration hbaseConf;
protected static Scan scan;
protected static JavaSparkContext sc;
public abstract RDDResult query();
public int getParent() {
return parent;
}
public void setParent(int parent) {
this.parent = parent;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void setScanToConf() {
try {
ClientProtos.Scan proto = ProtobufUtil.toScan(scan);
String scanToString = Base64.encodeBytes(proto.toByteArray());
hbaseConf.set(TableInputFormat.SCAN, scanToString);
} catch (IOException e) {
e.printStackTrace();
}
}}
这是一个父类,我有一些子类实现方法query()
从hbase读取,但如果我设置Configuration
, Scan
和JavaSparkContext
不是静态的,我会得到一些错误:这些类没有序列化。
为什么这些类必须是静态的?我有其他的方法来解决这个问题吗?呢。
您可以尝试为这些字段设置transient
以避免像
由:java.io.NotSerializableException引起:org.apache.spark.streaming.api.java.JavaStreamingContext
你对Java说你不想序列化这些字段:
protected transient Configuration hbaseConf;
protected transient Scan scan;
protected transient JavaSparkContext sc;
您是否在main或任何静态方法中初始化JavaSparkContext
, Configuration
和Scan
?对于静态,您的字段通过所有实例共享。但这取决于你的用例是否应该使用static
。
但是transient
的方式比static
好,因为JavaSparkCOntext
的序列化没有意义,因为这是在驱动程序上创建的。
——编辑讨论后在评论:
java doc for newAPIHadoopRDD
public <K,V,F extends org.apache.hadoop.mapreduce.InputFormat<K,V>> JavaPairRDD<K,V> newAPIHadoopRDD(org.apache.hadoop.conf.Configuration conf,
Class<F> fClass,
Class<K> kClass,
Class<V> vClass)
广播:
conf
-设置数据集的配置。注意:这个将将被放入Broadcast。因此,如果您计划重用此conf to create multiple RDDs
,则需要确保不会修改参看。一个安全的方法是总是为一个新的文件创建一个新的文件抽样 .
广播变量允许程序员在每台机器上缓存一个只读变量,而不是在任务中附带它的副本。
所以基本上我认为在这种情况下,static
是可以的(你创建hbaceConf只有一次),但如果你想避免static
,你可以按照javadoc的建议,总是为新的RDD创建一个新的配置。