web-dev-qa-db-fra.com

Comment insérer un flux structuré en flux continu DataFrame vers Hive table/emplacement externe?

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

5
BigD

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 et foreachBatch 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: si foreach 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.

2
Jacek Laskowski

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
0
Viacheslav Rodionov