這幾天有人問關於怎麼把不同的topic的數據寫入到hive的不同的表裏,我寫了一個簡單的demo,大家可以參考一下,
package hive
import java.io.File
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.log4j.{Level, Logger}
import org.apache.spark.sql.{Row, SparkSession}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.dstream.InputDStream
import org.apache.spark.streaming.kafka010.{ConsumerStrategies, KafkaUtils, LocationStrategies}
/**
* spark消費多個topic的數據寫入不同的hive表
*/
object SparkToHive {
def main(args: Array[String]): Unit = {
Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.WARN)
Logger.getLogger("org.apache.kafka.clients.consumer").setLevel(Level.WARN)
val warehouseLocation = new File("hdfs://cluster/hive/warehouse").getAbsolutePath
@transient
val spark = SparkSession
.builder()
.appName("Spark SQL To Hive")
.config("spark.sql.warehouse.dir", warehouseLocation)
.enableHiveSupport()
.getOrCreate()
spark.conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
@transient
val sc = spark.sparkContext
val scc = new StreamingContext(sc, Seconds(1))
val kafkaParams = Map[String, Object](
"auto.offset.reset" -> "latest", //latest,earliest
"value.deserializer" -> classOf[StringDeserializer]
, "key.deserializer" -> classOf[StringDeserializer]
, "bootstrap.servers" -> "10.200.10.24:6667,10.200.10.26:6667,10.200.10.29:6667"
, "group.id" -> "test_jason"
, "enable.auto.commit" -> (true: java.lang.Boolean)
)
var stream: InputDStream[ConsumerRecord[String, String]] = null
val topics = Array("test", "test1","test2")
stream = KafkaUtils.createDirectStream[String, String](
scc,
LocationStrategies.PreferConsistent,
ConsumerStrategies.Subscribe[String, String](topics, kafkaParams)
)
stream.foreachRDD(rdd=>{
if (!rdd.isEmpty()) {
val cache_rdd = rdd.map(_.value()).cache()
// a 表
val a = cache_rdd.filter(_.contains("hello"))
// b 表
val b = cache_rdd.filter(_.contains("jason"))
// 都可以打印結果,下面的代碼就不在寫了,可以參考另一篇博客裏面寫hive的
a.foreach(println)
b.foreach(println)
}
})
scc.start()
scc.awaitTermination()
}
}
代碼沒有寫完整,只要a,b都可以打印出來,下面就和普通的寫入hive表沒什麼區別了,可以參考這個 https://blog.csdn.net/xianpanjia4616/article/details/80958975
這裏還有一個思路,可以不用filter,直接寫一個完整的schema,然後在下面的sql裏面分別查詢出a,b表的數據,註冊兩張臨時表,然後寫到a,b兩個表,這種寫法就不在寫了,實現起來也比較的簡單.
注意:很多人在問,怎麼在worker端使用spark創建df,這裏說明一下,是不能這麼用的,因爲spark是在driver端初始化的,而且不能被序列化,所以不能傳輸到worker上.所以不能在foreach裏面使用.
如果有寫的不對的地方,歡迎大家指正,如果有什麼疑問,可以加QQ羣:340297350,更多的Flink和spark的乾貨可以加入下面的星球