Une requête sur l’intégration de flux structurés spark avec la table Hive.
J'ai essayé de faire quelques exemples de streaming structuré par étincelles.
voici mon exemple
val spark =SparkSession.builder().appName("StatsAnalyzer")
.enableHiveSupport()
.config("Hive.exec.dynamic.partition", "true")
.config("Hive.exec.dynamic.partition.mode", "nonstrict")
.config("spark.sql.streaming.checkpointLocation", "hdfs://pp/apps/Hive/warehouse/ab.db")
.getOrCreate()
// Register the dataframe as a Hive table
val userSchema = new StructType().add("name", "string").add("age", "integer")
val csvDF = spark.readStream.option("sep", ",").schema(userSchema).csv("file:///home/su/testdelta")
csvDF.createOrReplaceTempView("updates")
val query= spark.sql("insert into table_abcd select * from updates")
query.writeStream.start()
Comme vous pouvez le voir dans la dernière étape en écrivant data-frame dans l'emplacement hdfs, les données ne sont pas insérées dans le répertoire passionnant (mon répertoire existant contient d'anciennes données partitionnées par "age").
Je reçois
spark.sql.AnalysisException: les requêtes avec source de streaming doivent être exécutées avec writeStream start ()
Pouvez-vous m'aider à comprendre pourquoi je ne parviens pas à insérer des données dans un répertoire existant situé dans l'emplacement hdfs? ou y a-t-il une autre manière que je puisse faire "insérer dans" l'opération sur la table de ruche?
À la recherche d'une solution
Spark Structured Streaming ne prend pas en charge l'écriture du résultat d'une requête de diffusion en continu sur une table Hive.
scala> println(spark.version)
2.4.0
val sq = spark.readStream.format("rate").load
scala> :type sq
org.Apache.spark.sql.DataFrame
scala> assert(sq.isStreaming)
scala> sq.writeStream.format("Hive").start
org.Apache.spark.sql.AnalysisException: Hive data source can only be used with tables, you can not write files of Hive data source directly.;
at org.Apache.spark.sql.streaming.DataStreamWriter.start(DataStreamWriter.scala:246)
... 49 elided
Si un système cible (ou évier) n'est pas pris en charge, vous pouvez utiliser les opérations foreach et foreachBatch (mettant en évidence le mien):
Les opérations
foreach
etforeachBatch
vous permettent d’appliquer des opérations arbitraires et une logique d’écriture sur le résultat d’une requête de transmission en continu. Leurs cas d'utilisation sont légèrement différents: siforeach
autorise une logique d'écriture personnalisée pour chaque ligne,foreachBatch
permet des opérations arbitraires et une logique personnalisée pour la sortie de chaque micro-lot.
Je pense que foreachBatch
est votre meilleur pari.
import org.Apache.spark.sql.DataFrame
sq.writeStream.foreachBatch { case (ds: DataFrame, batchId: Long) =>
// do whatever you want with your input DataFrame
// incl. writing to Hive
// I simply decided to print out the rows to the console
ds.show
}.start
Il existe également Apache Hive Warehouse Connector avec lequel je n’ai jamais travaillé mais qui semble pouvoir vous être utile.
Juste au cas où quelqu'un essaierait le code de Jacek Laskowski, il sait qu'il ne compile pas vraiment dans Spark 2.4.0 (consultez my Gist testé sur AWS EMR 5.20.0 et Vanilla Spark). Donc, je suppose que c'était son idée de la façon dont cela devrait fonctionner dans une future version de Spark . Le vrai code est le suivant:
scala> import org.Apache.spark.sql.Dataset
import org.Apache.spark.sql.Dataset
scala> sq.writeStream.foreachBatch((batchDs: Dataset[_], batchId: Long) => batchDs.show).start
res0: org.Apache.spark.sql.streaming.StreamingQuery =
org.Apache.spark.sql.execution.streaming.StreamingQueryWrapper@5ebc0bf5