web-dev-qa-db-fra.com

Spark streaming structuré kafka convertir JSON sans schéma (inférer le schéma)

J'ai lu Spark Le streaming structuré ne prend pas en charge l'inférence de schéma pour lire les messages Kafka en JSON. Existe-t-il un moyen de récupérer le schéma de la même manière que Spark Le streaming fait:

val dataFrame = spark.read.json(rdd.map(_.value()))
dataFrame.printschema 
10
Arnon Rodman

Voici une façon possible de procéder:

  1. Avant de commencer à diffuser, obtenez un petit lot de données de Kafka

  2. Déduire le schéma du petit lot

  3. Commencez à diffuser les données en utilisant le schéma extrait.

Le pseudo-code ci-dessous illustre cette approche.

Étape 1:

Extraire un petit lot (deux enregistrements) de Kafka,

val smallBatch = spark.read.format("kafka")
                           .option("kafka.bootstrap.servers", "node:9092")
                           .option("subscribe", "topicName")
                           .option("startingOffsets", "earliest")
                           .option("endingOffsets", """{"topicName":{"0":2}}""")
                           .load()
                           .selectExpr("CAST(value AS STRING) as STRING").as[String].toDF()

Étape 2: Écrivez le petit lot dans un fichier:

smallBatch.write.mode("overwrite").format("text").save("/batch")

Cette commande écrit le petit lot dans le répertoire hdfs/batch. Le nom du fichier qu'il crée est part-xyz *. Vous devez donc d'abord renommer le fichier à l'aide des commandes hadoop FileSystem (voir org.Apache.hadoop.fs._ et org.Apache.hadoop.conf.Configuration, voici un exemple https://stackoverflow.com/a/41990859 ) puis lisez le fichier en tant que json:

val smallBatchSchema = spark.read.json("/batch/batchName.txt").schema

Ici, batchName.txt est le nouveau nom du fichier et smallBatchSchema contient le schéma déduit du petit lot.

Enfin, vous pouvez diffuser les données comme suit (étape 3):

val inputDf = spark.readStream.format("kafka")
                             .option("kafka.bootstrap.servers", "node:9092")
                             .option("subscribe", "topicName")
                             .option("startingOffsets", "earliest")
                             .load()

val dataDf = inputDf.selectExpr("CAST(value AS STRING) as json")
                    .select( from_json($"json", schema=smallBatchSchema).as("data"))
                    .select("data.*")

J'espère que cela t'aides!

8
D.M.

Il est possible en utilisant cette construction:

myStream = spark.readStream.schema(spark.read.json("my_sample_json_file_as_schema.json").schema).json("my_json_file")..

Comment se peut-il? Eh bien, comme le schéma spark.read.json (".."). Renvoie exactement un schéma inféré voulu, vous pouvez utiliser ce schéma renvoyé comme argument pour le paramètre de schéma obligatoire de spark.readStream

Ce que j'ai fait était de spécifier un échantillon-json à une ligne comme entrée pour déduire les trucs du schéma afin qu'il n'occupe pas de mémoire inutile. Si vos données changent, mettez simplement à jour votre sample-json.

Il m'a fallu un certain temps pour comprendre (la construction de StructTypes et StructFields à la main était pénible dans le ..), donc je serai heureux pour tous les votes positifs :-)

5
Aydin K.

Ce n'est pas possible. Spark Streaming prend en charge l'inférence de schéma limitée dans le développement avec spark.sql.streaming.schemaInference défini sur true:

Par défaut, le streaming structuré à partir de sources basées sur des fichiers vous oblige à spécifier le schéma, plutôt que de compter sur Spark pour le déduire automatiquement. Cette restriction garantit qu'un schéma cohérent sera utilisé pour la requête de streaming, même en cas d'échecs. Pour les cas d'utilisation ad hoc, vous pouvez réactiver l'inférence de schéma en définissant spark.sql.streaming.schemaInference sur true.

mais il ne peut pas être utilisé pour extraire JSON de Kafka et DataFrameReader.json ne prend pas en charge le streaming Datasets comme arguments.

Vous devez fournir le schéma manuellement Comment lire les enregistrements au format JSON à partir de Kafka en utilisant le streaming structuré?

2
user9245550

Prendre Arnon's la solution à l'étape suivante (car elle est déconseillée dans les versions plus récentes de spark, et nécessiterait d'itérer la trame de données entière juste pour un casting de type)

spark.read.json(df.as[String])

Quoi qu'il en soit, pour l'instant, c'est encore expérimental.

2
user3027497

Il est possible de convertir JSON en un DataFrame sans avoir à taper manuellement le schéma, si c'est ce que vous vouliez demander.

Récemment, je suis tombé sur une situation où je recevais des paquets JSON imbriqués massivement longs via Kafka, et taper manuellement le schéma aurait été à la fois lourd et sujet aux erreurs.

Avec un petit échantillon des données et quelques astuces, vous pouvez fournir le schéma à Spark2 + comme suit:

val jsonstr = """ copy paste a representative sample of data here"""
val jsondf = spark.read.json(Seq(jsonstr).toDS) //jsondf.schema has the nested json structure we need

val event = spark.readStream.format..option...load() //configure your source

val eventWithSchema = event.select($"value" cast "string" as "json").select(from_json($"json", jsondf.schema) as "data").select("data.*")

Maintenant, vous pouvez faire ce que vous voulez avec ce val comme vous le feriez avec Direct Streaming. Créez une vue temporaire, exécutez des requêtes SQL, peu importe.

1
maverik