请查看以下用scala编写的火花流代码:
object HBase {
var hbaseTable = ""
val hConf = new HBaseConfiguration()
hConf.set("hbase.zookeeper.quorum", "zookeeperhost")
def init(input: (String)) {
hbaseTable = input
}
def display() {
print(hbaseTable)
}
def insertHbase(row: (String)) {
val hTable = new HTable(hConf,hbaseTable)
}
}
object mainHbase {
def main(args : Array[String]) {
if (args.length < 5) {
System.err.println("Usage: MetricAggregatorHBase <zkQuorum> <group> <topics> <numThreads> <hbaseTable>")
System.exit(1)
}
val Array(zkQuorum, group, topics, numThreads, hbaseTable) = args
HBase.init(hbaseTable)
HBase.display()
val sparkConf = new SparkConf().setAppName("mainHbase")
val ssc = new StreamingContext(sparkConf, Seconds(10))
ssc.checkpoint("checkpoint")
val topicpMap = topics.split(",").map((_, numThreads.toInt)).toMap
val lines = KafkaUtils.createStream(ssc, zkQuorum, group, topicpMap).map(_._2)
val storeStg = lines.foreachRDD(rdd => rdd.foreach(HBase.insertHbase))
lines.print()
ssc.start()
}
}
我正在尝试通过调用hbaseTable
方法初始化对象HBase
中的参数HBase.init
。它正确设置参数。我通过在下一行调用HBase.display
方法确认了这一点。
但是,当调用HBase.insertHbase
中的foreachRDD
方法时,会抛出hbaseTable
未设置的抛出错误。
更新例外:
java.lang.IllegalArgumentException: Table qualifier must not be empty
org.apache.hadoop.hbase.TableName.isLegalTableQualifierName(TableName.java:179)
org.apache.hadoop.hbase.TableName.isLegalTableQualifierName(TableName.java:149)
org.apache.hadoop.hbase.TableName.<init>(TableName.java:303)
org.apache.hadoop.hbase.TableName.createTableNameIfNecessary(TableName.java:339)
org.apache.hadoop.hbase.TableName.valueOf(TableName.java:426)
org.apache.hadoop.hbase.client.HTable.<init>(HTable.java:156)
您能否告诉我如何使此代码正常工作。
答案 0 :(得分:2)
“这个代码在哪里运行” - 这是我们需要问的问题,以便了解正在发生的事情。
HBase
是一个Scala对象 - 根据定义,它是一个单例构造,在JVM中使用'only once'语义进行初始化。
在初始化点,在此Spark应用程序的驱动程序中执行HBase.init(hbaseTable)
,使用驱动程序的VM中的给定值初始化此对象。
但是当我们执行:rdd.foreach(HBase.insertHbase)
时,闭包在每个执行器上执行,该执行器承载给定RDD的分区。此时,对每个执行程序在每个VM上初始化对象HBase
。我们可以看到,此时此对象上没有初始化。
有两种选择:
我们可以向HBase
对象添加一些“isInitialized”检查,并在每次调用foreach
时添加-now条件调用以初始化。
另一种选择是使用
rdd.foreachPartitition{partition =>
HBase.initialize(...)
partition.foreach(elem => HBase.insert(elem))
}
此构造将按每个分区中的元素数量分摊任何初始化。也可以将它与初始化检查结合起来,以防止不必要的引导工作。