Spark Streaming Scala将不同结构的json组合成一个数据帧

Spark Streaming Scala将不同结构的json组合成一个数据帧,json,scala,apache-spark,Json,Scala,Apache Spark,我正在尝试处理来自Kinesis的Json字符串。Json字符串可以有两种不同的形式。从Kinesis,我创建了一个数据流: val kinesisStream = KinesisUtils.createStream( ssc, appName, "Kinesis_Stream", "kinesis.ap-southeast-1.amazonaws.com", "region", InitialPositionInStream.LATEST, kinesisCheckpointInterva

我正在尝试处理来自Kinesis的Json字符串。Json字符串可以有两种不同的形式。从Kinesis,我创建了一个数据流:

val kinesisStream = KinesisUtils.createStream(
 ssc, appName, "Kinesis_Stream", "kinesis.ap-southeast-1.amazonaws.com",
 "region", InitialPositionInStream.LATEST, kinesisCheckpointInterval, StorageLevel.MEMORY_AND_DISK_2)

 val lines = kinesisStream.map(x => new String(x))

 lines.foreachRDD((rdd, time) =>{

   val sqlContext = SQLContextSingleton.getInstance(rdd.sparkContext)
   import sqlContext.implicits.StringToColumn

   if(rdd.count() > 0){
    // Process jsons here
    // Json strings here would have either one of the formats below
   }
 })
RDD字符串将具有这些json字符串中的任意一个。 收藏:

[
  {
    "data": {
      "ApplicationVersion": "1.0.3 (65)",
      "ProjectId": 30024,
      "TargetId": "4138",
      "Timestamp": 0
    },
    "host": "host1"
  },
  {
    "data": {
      "ApplicationVersion": "1.0.3 (65)",
      "ProjectId": 30025,
      "TargetId": "4139",
      "Timestamp": 0
    },
    "host": "host1"
  }
]
一些Json字符串是单一对象,如下所示:

{
      "ApplicationVersion": "1.0.3 (65)",
      "ProjectId": 30026,
      "TargetId": "4140",
      "Timestamp": 0
}
我希望能够从“data”键提取对象,如果它是第一种类型的Json字符串,并与第二种类型的Json相结合,形成一个RDD/DataFrame,我如何实现这一点

最终,我希望我的数据框架是这样的:

+------------------+---------+--------+---------+
|ApplicationVersion|ProjectId|TargetId|Timestamp|
+------------------+---------+--------+---------+
|        1.0.3 (65)|    30024|    4138|        0|
|        1.0.3 (65)|    30025|    4139|        0|
|        1.0.3 (65)|    30026|    4140|        0|
+------------------+---------+--------+---------+
对不起,Scala和Spark是新手。我一直在查看现有的示例,但不幸的是,还没有找到解决方案


非常感谢。

您可以在选择第一个
数据框中的
列后使用union。*

val spark=SparkSession.builder().master(“local[*]).getOrCreate()
val sc=spark.sparkContext
//假设您将JSON存储在两个单独的字符串'json1'和'json2'中`
val df1=spark.read.json(sc.parallelize(Seq(json1)))
val df2=spark.read.json(sc.parallelize(Seq(json2)))
导入spark.implicits_
df1.select($“data.*”)//仅选择第一个数据帧中的数据列
.union(df2)//合并两个数据帧,因为它们具有相同的结构
.show()
编辑[其他解决方案链接]

编辑完问题后,我了解到在解析JSON文件时需要某种回退机制。使用任何JSON解析库都有很多方法可以做到这一点——Play提供了一个很好的解决方案,我认为它已经解释了如何以优雅的方式解决这个问题

一旦你有了一个
RDD[Data]
其中数据是你的“变量”类型,你可以简单地使用
RDD.toDF()
将它转换成一个
Dataframe

希望对您有所帮助。

此示例使用:


谢谢你的快速回复!抱歉,我忘了提到我使用的是Spark Streaming数据流,我已经更新了我的问题。尽管如此,您的回答仍然很有帮助!如果您能够从数据流中提取字符串,代码应该或多或少可以工作。谢谢!通过使用json4s,这为我指明了正确的方向。这使我能够在转换为DFthanks之前首先处理json字符串,以便快速响应Andrei,我很感激,这非常有用!抱歉,我忘了提到我使用的是Spark Streaming数据流,我已经更新了上面的问题。我明白了。这是一个简单的方法来知道哪一个对象时,不幸的是我已经编辑了答案。这会帮助你实现你想要的,我只是想避免把所有的细节放在这里,因为这实际上是两个独立的问题。我希望它能帮助你:)
import org.json4s._
import org.json4s.jackson.JsonMethods._

implicit val format = DefaultFormats

case class jsonschema ( ApplicationVersion: String, ProjectId: String, TargetId: String, Timestamp:Int )

val string1 = """
[ {
  "data" : {
    "ApplicationVersion" : "1.0.3 (65)",
    "ProjectId" : 30024,
    "TargetId" : "4138",
    "Timestamp" : 0
  },
  "host" : "host1"
}, {
  "data" : {
    "ApplicationVersion" : "1.0.3 (65)",
    "ProjectId" : 30025,
    "TargetId" : "4139",
    "Timestamp" : 0
  },
  "host" : "host1"
} ]

"""

val string2 = """
[ {
  "ApplicationVersion" : "1.0.3 (65)",
  "ProjectId" : 30025,
  "TargetId" : "4140",
  "Timestamp" : 0
}, {
  "ApplicationVersion" : "1.0.3 (65)",
  "ProjectId" : 30025,
  "TargetId" : "4141",
  "Timestamp" : 0
} ]
"""

val json1 = (parse(string1) \ "data").extract[List[jsonschema]]

val json2 = parse(string2).extract[List[jsonschema]]

val jsonRDD = json1.union(json2)

val df = sqlContext.createDataFrame(jsonRDD)

df.show


+------------------+---------+--------+---------+
|ApplicationVersion|ProjectId|TargetId|Timestamp|
+------------------+---------+--------+---------+
|        1.0.3 (65)|    30024|    4138|        0|
|        1.0.3 (65)|    30025|    4139|        0|
|        1.0.3 (65)|    30025|    4140|        0|
|        1.0.3 (65)|    30025|    4141|        0|
+------------------+---------+--------+---------+