这似乎是一件相当简单的事情,你会认为Spark开发人员会以这种方式构建,但我找不到。我见过或尝试的选项是:
写入Parquet文件并创建外部配置单元表,但我想插入现有的Hive内部表。我知道我可以简单地使用另一个火花作业添加这些数据来定期添加这些数据,但这并不理想
编写我尝试过的自定义ForeachWriter
但收效甚微:
val ds1 = spark.readStream.format("kafka").option("kafka.bootstrap.servers", hostPort).option("subscribe", "test").load()
val lines = ds1.selectExpr("CAST(value AS STRING)").as[String]
val words = lines.flatMap(_.split(" "))
import org.apache.spark.sql.ForeachWriter
val writer = new ForeachWriter[String] {
import org.apache.spark.sql.SparkSession
override def open(partitionId: Long, version: Long) = true
override def process(value: String) = {
val sparksess = SparkSession.builder.master("local[*]").enableHiveSupport().getOrCreate()
import sparksess.implicits._
val valData = List(value).toDF
valData.write.mode("append").insertInto("stream_test")
sparksess.close
}
override def close(errorOrNull: Throwable) = {}
}
val q = words.writeStream.queryName("words-app").foreach(writer)
val query = q.start()
注意:在Open方法中创建Sparksession并在close方法中关闭会话似乎很明显但是这些不能用于多次迭代然后失败
注意:上面的工作甚至超过了第一次迭代,但是抛出的Spark错误让我觉得这个解决方案无法扩展:
18/03/15 11:10:52 ERROR cluster.YarnScheduler: Lost executor 2 on hadoop08.il.nds.com: Container marked as failed: container_1519892135449_0122_01_000003 on host: hadoop08.il.nds.com. Exit status: 50. Diagnostics: Exception from container-launch.
Container id: container_1519892135449_0122_01_000003
Exit code: 50
Stack trace: ExitCodeException exitCode=50:
at org.apache.hadoop.util.Shell.runCommand(Shell.java:601)
at org.apache.hadoop.util.Shell.run(Shell.java:504)
at org.apache.hadoop.util.Shell$ShellCommandExecutor.execute(Shell.java:786)
at org.apache.hadoop.yarn.server.nodemanager.DefaultContainerExecutor.launchContainer(DefaultContainerExecutor.java:213)
at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:302)
at org.apache.hadoop.yarn.server.nodemanager.containermanager.launcher.ContainerLaunch.call(ContainerLaunch.java:82)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Container exited with a non-zero exit code 50
注意:有一个类似的问题here: 但答案并没有说明它是如何进行流媒体上下文并且没有得到答案
任何人都可以帮助修复此代码,以便它可以更好地扩展而不会出错吗?
回写Kafka接收器然后让Kafka使用KafkaConnect写入Hive,就像它说here: 但是,我想避免这种额外的复杂性。
写入JDBCSink - 这将是我的下一次尝试,但似乎它不应该是Spark内的Hive所必需的!
我已经读过DataBricks正在开发类似的内容 - 请参阅here:
但目前尚不清楚何时以及是否将作为标准Spark GA版本的一部分发布。
特别是Spark开发人员提供的有关实现将数据流写入现有Hive表的最佳方法的任何帮助都将非常受欢迎。
修改:
我编写了一个扩展ForeachWriter的JDBC Sink并且它可以工作,但它很慢,因为它必须打开和关闭每一行的连接!我想尝试创建一个可以重用和释放连接的连接池,但是认为使用ForeachWriter是不可能的,并且我必须编写自己的自定义JDBC接收器来执行此操作并且它很复杂here
我正在计划2个选项之一1.为了简单起见,在Spark发布内置解决方案之前,将数据写入可通过hive外部表访问的镶木地板文件,并定期写入作业以将数据移动到托管表。 2.使用较旧的Spark Streaming DStream,它似乎能够使用ForeachRDD来懒惰地创建可以重用的单例会话但是我认为我会失去结构化流的“一次性”特性,并且必须完全重写我的代码。功能内置于结构化流中。