私は 構造化ストリーミングアプローチ DataFrame/DatasetAPIに基づくSpark-Streamingを使用してKafkaからデータのストリームをロードしようとしています。
私が使う:
Spark Kafka DataSourceは基礎となるスキーマを定義しました:
|key|value|topic|partition|offset|timestamp|timestampType|
私のデータはjson形式で提供され、value列に格納されます。値の列から基になるスキーマを抽出し、受信したデータフレームをvalueに格納されている列に更新する方法を探していますか?以下のアプローチを試しましたが、機能しません。
val columns = Array("column1", "column2") // column names
val rawKafkaDF = sparkSession.sqlContext.readStream
.format("kafka")
.option("kafka.bootstrap.servers","localhost:9092")
.option("subscribe",topic)
.load()
val columnsToSelect = columns.map( x => new Column("value." + x))
val kafkaDF = rawKafkaDF.select(columnsToSelect:_*)
// some analytics using stream dataframe kafkaDF
val query = kafkaDF.writeStream.format("console").start()
query.awaitTermination()
ここで例外が発生していますorg.Apache.spark.sql.AnalysisException: Can't extract value from value#337;
ストリームの作成時に、内部の値が不明であるため...
何か提案はありますか?
Sparkの観点からはvalue
は単なるバイトシーケンスです。シリアル化の形式や内容についての知識はありません。フィールドを抽出できるようにするには、最初に解析する必要があります。
データがJSON文字列としてシリアル化される場合、2つのオプションがあります。 cast
value
からStringType
まで、from_json
を使用して、スキーマを提供できます。
import org.Apache.spark.sql.types._
import org.Apache.spark.sql.functions.from_json
val schema: StructType = StructType(Seq(
StructField("column1", ???),
StructField("column2", ???)
))
rawKafkaDF.select(from_json($"value".cast(StringType), schema))
またはcast
からStringType
、get_json_object
を使用してパスでフィールドを抽出します。
import org.Apache.spark.sql.functions.get_json_object
val columns: Seq[String] = ???
val exprs = columns.map(c => get_json_object($"value", s"$$.$c"))
rawKafkaDF.select(exprs: _*)
後でcast
を目的のタイプに変更します。