如何在Spark Streaming应用中对通过Kafka发送的Hive表执行查询?

时间:2019-02-25 13:07:53

标签: apache-spark apache-spark-sql spark-streaming

我有一个Spark Streaming应用程序,该应用程序从Kafka中读取记录中的Hive表名,例如table1 .. table2 .. table3 .. etc。

我想在配置单元表上执行结构化查询,并将结果流式传输到另一个Kafka主题。

我有这样的

val hqls = rdd
    .filter(record => record.value() != null && record.value().trim.length > 0)
    .foreach(tableName=> publishData(tableName, sparkSession, kafkaProducer))

我的publishData如下

val df = sparkSession.sql("select * from " + tableName)
df.foreach { row =>
  // code to write to kafka
}

执行此操作后,在NullPointerException调用中会收到一个sparkSession.sql,如下所示:

org.apache.spark.SparkException: Job aborted due to stage failure: Task 13 in stage 12.0 failed 8 times, most recent failure: Lost task 13.7 in stage 12.0 (TID 838, cilhdwks0001.sys.cigna.com, executor 1): java.lang.NullPointerException
    at org.apache.spark.sql.SparkSession.sessionState$lzycompute(SparkSession.scala:142)
    at org.apache.spark.sql.SparkSession.sessionState(SparkSession.scala:140)

我在其他帖子中发现,无法在val df = sparkSession.sql(hql)内运行rdd.foreach,但是还没有找到正确的方法。

如果我按照以下方式将代码更改为使用collect,它将起作用。为什么?

val tablenames = rdd
  .filter(tableName => tableName != null && tableName.trim.length > 0)
  .collect() 
tablenames.foreach { tablename => 
  publishData(tablename, sparkSession, kafkaProducer)
}

效率高吗?它将负载正确地分配给集群吗?

1 个答案:

答案 0 :(得分:0)

  

我有一组配置单元名称,这些名称通过kafka到达我的Spark Streaming应用程序。我需要对每个表执行查询

一旦您开始将Hive表流式传输到Kafka,所有Spark看到的(无论是执行Spark SQL还是Spark Streaming或Spark Structured Streaming)都是记录(全部在一起)(可能是单个批处理),或者可能不对应于Hive表。一个处理周期只能看到一张桌子的一半或一张桌子的一半。这是不可预测的。

恕我直言,您必须发送一个标记记录,以便Spark可以将属于单个Hive表的所有记录过滤到数据集。那可能行得通,但我怀疑这是最理想的解决方案。

简而言之,在Spark中,您将处理单个Kafka记录(来自Hive表),除非发送一些额外的元数据,否则Spark不会知道整个Hive表是否在数据集中。

  

.foreach(tableName=> publishData

publishData中执行的任何操作都会在Spark执行器上发生,其中SparkContextSparkSession不可用。您根本无法在执行程序上使用它们(按Spark设计),因此“在sparkSession.sql上出现NullPointerException” 这是预期的。

  

如果我将其更改为(...).collect()(...),它将起作用   效率高,是否可以将负载正确地分配给集群?

Spark应用程序中的任何collect都打破了Spark在群集中的各个节点之间分布大型数据集的前提,因此您可以处理多于一台机器可以处理的事情。任何collect都会将所有分布式数据带到驱动程序的单个JVM中,并可能导致OutOfMemoryErrors(这可能就是您首先考虑使用Apache Spark处理大型数据集的原因)。