web-dev-qa-db-ja.com

構造化ストリーミングを使用してKafkaからJSON形式でレコードを読み取る方法は?

私は 構造化ストリーミングアプローチ DataFrame/DatasetAPIに基づくSpark-Streamingを使用してKafkaからデータのストリームをロードしようとしています。

私が使う:

  • Spark 2.10
  • カフカ0.10
  • spark-sql-kafka-0-10

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;ストリームの作成時に、内部の値が不明であるため...

何か提案はありますか?

12
Stefan Repcek

Sparkの観点からはvalueは単なるバイトシーケンスです。シリアル化の形式や内容についての知識はありません。フィールドを抽出できるようにするには、最初に解析する必要があります。

データがJSON文字列としてシリアル化される場合、2つのオプションがあります。 castvalueから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からStringTypeget_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を目的のタイプに変更します。

10
user6910411