web-dev-qa-db-ja.com

Spark構造化ストリーミングkafkaスキーマなしでJSONを変換(スキーマを推測)

Sparkを読みました構造化ストリーミングは、KafkaメッセージをJSONとして読み取るためのスキーマ推論をサポートしていません。 Spark Streamingと同じスキーマを取得する方法はありますか?

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

これを行う1つの可能な方法を次に示します。

  1. ストリーミングを開始する前に、Kafkaから少量のデータを取得します

  2. 小さなバッチからスキーマを推測する

  3. 抽出されたスキーマを使用してデータのストリーミングを開始します。

以下の擬似コードは、このアプローチを示しています。

ステップ1:

Kafkaから小さな(2つのレコード)バッチを抽出し、

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()

ステップ2:小さなバッチをファイルに書き込む:

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

このコマンドは、小さなバッチをhdfsディレクトリ/ batchに書き込みます。作成するファイルの名前はpart-xyz *です。したがって、最初にhadoop FileSystemコマンドを使用してファイルの名前を変更する必要があります(org.Apache.hadoop.fs._およびorg.Apache.hadoop.conf.Configurationを参照してください。ここに例を示します https://stackoverflow.com/a/41990859 )次に、ファイルをjsonとして読み取ります。

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

ここで、batchName.txtはファイルの新しい名前で、smallBatchSchemaには小さなバッチから推測されたスキーマが含まれています。

最後に、次のようにデータをストリーミングできます(ステップ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.*")

お役に立てれば!

8
D.M.

isこのコンストラクトを使用すると可能です:

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

どうすればいいの?まあ、spark.read.json( "..")。schemaは必要な推論されたスキーマを正確に返すので、この返されたスキーマをspark.readStreamの必須スキーマパラメーターの引数として使用できます。

私がしたことは、スキーマを推論するための入力として、1行のsample-jsonを指定して、メモリを不必要に消費しないようにすることでした。データが変更された場合は、sample-jsonを更新するだけです。

(StructTypesとStructFieldsを手作業で構築するのは、..で苦労しました。)したがって、私はすべての賛成票に満足しています:-)

5
Aydin K.

それは不可能。 Spark Streamingは、spark.sql.streaming.schemaInferenceに設定true

デフォルトでは、ファイルベースのソースからの構造化ストリーミングでは、Spark=に依存して自動的に推論するのではなく、スキーマを指定する必要があります。この制限により、ストリーミングクエリに一貫したスキーマアドホックユースケースでは、spark.sql.streaming.schemaInferenceをtrueに設定することにより、スキーマの推論を再度有効にできます。

ただし、KafkaメッセージおよびDataFrameReader.jsonは、ストリーミングとしてDatasetsを引数としてサポートしていません。

スキーマを手動で指定する必要があります JSON形式のレコードをKafka Structured Streamingを使用して読み取る方法?

2
user9245550

Arnon's 次のステップへの解決策を講じる(sparkの新しいバージョンでは非推奨であり、型キャストのためだけにデータフレーム全体を反復する必要があるため)

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

とにかく、今のところ、それはまだ実験的です。

2
user3027497

JSONを手動で入力する必要があるスキーマなしでDataFrameに変換することは可能です。

最近、Kafkaを介して非常に長いネストされたJSONパケットを受信し、スキーマを手動で入力するのは面倒でエラーが発生しやすい状況になりました。

データの小さなサンプルといくつかの策略を使用して、次のようにスキーマをSpark2 +に提供できます。

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.*")

これで、Direct Streamingの場合と同じように、このvalを使って何でもできます。一時ビューを作成し、SQLクエリを実行します。

1
maverik