如何在自定义架构中使用from_json标准函数(错误:方法值from_json重载,并带有替代方法)?

时间:2019-09-20 23:16:44

标签: scala apache-spark apache-spark-sql

我正在使用AWS Kinesis流中的JSON数据,但是当我尝试使用from_json()标准函数时遇到以下错误:

command-5804948:32: error: overloaded method value from_json with alternatives:
  (e: org.apache.spark.sql.Column,schema: org.apache.spark.sql.Column)org.apache.spark.sql.Column <and>
  (e: org.apache.spark.sql.Column,schema: org.apache.spark.sql.types.DataType)org.apache.spark.sql.Column <and>
  (e: org.apache.spark.sql.Column,schema: org.apache.spark.sql.types.StructType)org.apache.spark.sql.Column
 cannot be applied to (String, org.apache.spark.sql.types.StructType)
    .select(from_json("jsonData", dataSchema).as("devices"))

我尝试了以下两种方法来定义自己的模式:

val dataSchema = new StructType()
        .add("ID", StringType)
        .add("Type", StringType)
        .add("Body", StringType)
        .add("Submitted", StringType)

val dataSchema = StructType(Seq(StructField("ID",StringType,true), StructField("Type",StringType,true), StructField("Body",StringType,true), StructField("Submitted",StringType,true)))

这是我的代码:

import org.apache.spark.sql.types._
import org.apache.spark.sql.functions._
import org.apache.spark.sql.Column
import java.nio.ByteBuffer
import scala.util.Random

val dataSchema = new StructType()
        .add("ID", StringType)
        .add("Type", StringType)
        .add("Body", StringType)
        .add("Submitted", StringType)

// val dataSchema = StructType(Seq(StructField("ID",StringType,true), StructField("Type",StringType,true), StructField("Body",StringType,true), StructField("Submitted",StringType,true)))

val kinesisDF = spark.readStream
    .format("kinesis")
    .option("streamName", "**************************")
    .option("region", "********")
    .option("initialPosition", "TRIM_HORIZON")
    .option("awsAccessKey", "****************")
    .option("awsSecretKey", "************************************")
    .load()

val schemaDF = kinesisDF
    .selectExpr("cast (data as STRING) jsonData")
    .select(from_json("jsonData", dataSchema).as("devices"))
    .select("devices.*")
    .load()

display(schemaDF)

如果您执行以下操作:

val str_data = kinesisDF
    .selectExpr("cast (data as STRING) jsonData")

display(str_data)

您可以看到流数据如下:

{“ ID”:“ 1266ee3d99bc-96f942a6-434c-6442-a762”,“ Type”:“ BT”,“ Body”:“ {\” TN \“:\” ND \“,\” TD \ “:\” JSON:{\\“ vw \\”:\\“ CV \\”} \“,\” LT \“:\” BT \“,\” TI \“:\” 9ff2-4749250dd142- 793ffb20-eb8e-47f7 \“,\” CN \“:\” OD \“,\” CI \“:\” eb \“,\” UI \“:\” abc004 \“,\” AN \“: \“ 1234567 \”,\“ TT \”:\“ 2019-09-15T09:48:25.0395209Z \”,\“ FI \”:\“ N / A \”,\“ HI \”:\“ N / A \“,\” SV \“:6}”,“已提交”:“ 2019-09-15 09:48:26.079”}

{“ ID”:“ c8eb956ee98c-68d668b7-e7a6-9ea2-49a5”,“ Type”:“ MS”,“ Body”:“ {\” MT \“:\” N / A \“,\” EP \“:\” N / A \“,\” RQ \“:\” {\\“ IA] \\”:false,\\“ AN \\”:null,\\“ ACI \\”: \\“ 1266ee3d99bc-96f942a6-434c-6442-a762 \\”,\\“ CI \\”:\\“ ebb \\”,\\“ CG \”:\\“ 8b8a-4ab17555f2fa-da0c8047-b5a6 -4ebe \\“,\\” UI \\“:\\” def211 \\“,\\” UR \\“:\\” EscC \\“,\\” UL \\“:\\” SCC \\“,\\” TI \\“:\\” b9d2-d4f646a15d66-dc519f4a-48c3-4e7b \\“,\\” TN \\“:null,\\” MN \\“:null,\\ “ CTZ \\”:空,\\“ PM \\”:空,\\“ TS \\”:空,\\“ CI \\”:\\“ ebc \\”,\\“ ALDC \\ “:null}”,“已提交”:“ 2019-09-15 09:49:46.901”}

“ Body”键的值是另一个JSON /嵌套JSON,这就是为什么我将其作为StringType放在架构中,以便按原样存储在列中的原因。 运行上面的代码时出现以下错误:

如何解决?

1 个答案:

答案 0 :(得分:2)

那部分错误说明了一切:

  

不能应用于(String,org.apache.spark.sql.types.StructType)

这意味着from_json标准函数有三种不同的选择,并且它们都期望使用Column对象而不是String

您可以使用$语法(或使用col标准函数)简单地对其进行修复,如下所示:

.select(from_json($"jsonData", dataSchema).as("devices"))

请注意将列名$(隐式地)转换为Column对象的列名。