Scala 如何将数据帧与特定路径上的JSON编码行连接起来?

Scala 如何将数据帧与特定路径上的JSON编码行连接起来?,scala,apache-spark,apache-spark-sql,Scala,Apache Spark,Apache Spark Sql,我希望加入2个数据帧(都包含大量JSON),但都是在一个特定的路径下。我希望我可以在相同的操作中完成这项工作,而不必在连接后将其转换为RDD,我认为这可以通过Spark SQL优雅地完成 这两个对象的内容都是动态的,所以我事先不知道整个结构,但每个对象的顶层路径是恒定的 对象1文档 { "object1": { "element1" "element1value" ... } } 对象2文件 { "object2": { "ele

我希望加入2个数据帧(都包含大量JSON),但都是在一个特定的路径下。我希望我可以在相同的操作中完成这项工作,而不必在连接后将其转换为RDD,我认为这可以通过Spark SQL优雅地完成

这两个对象的内容都是动态的,所以我事先不知道整个结构,但每个对象的顶层路径是恒定的

对象1文档

{
   "object1": {
        "element1" "element1value"
        ...
   }

}
对象2文件

{

   "object2": {

    "element1" "element1value"
    ...
   }

}
预期结果

{
   "object1Parent": {
        "element1" "element1value"
        ...
   },
   "object2Parent": {

       "object2": {

        "element1" "element1value"
        ...
       }
   }

}
联合行动

SQL: "SELECT * FROM object1 r JOIN object2 s ON r.element1 = s.element2"
两个对象的内容都是动态的,所以我事先不知道整个结构

这似乎是一个反对Spark SQL(RDDAPI更是如此)的论点,因为正是这个优化器使Spark SQL如此强大,而且它必须有关于模式的信息才能将优化应用于结构化查询

然而,根据要求,这不一定是正确的

但每种方法的顶层路径都是恒定的

如果
object1
后面总是跟着
element1
object2
,并且在
join
中使用它们,那就足够了

您只需“解构”不透明的JSON格式,并使其像行一样。使用标准功能,例如

来自_json(e:Column,schema:Column):Column

from_json(e:Column,schema:DataType):Column

将包含JSON字符串的列解析为具有指定架构的StringType为keys type、StructType或StructType的ArrayType的MapType。如果是不可解析的字符串,则返回null

这个
schema
参数可以处理模式的动态部分,该参数在运行时可能会更改。它可以作为Spark应用程序的一部分创建(当输入参数为
schema:DataType
时),也可以作为数据框的一部分与输入数据一起创建(当
schema:Column
时)

您还可以使用
get\u json\u object
json\u tuple
标准函数

从Spark 2.4.0开始,您还可以使用json的模式来推断早期函数的DDL格式列的模式

有很多选择,不是吗

(伪)代码 让我们假设以下两个数据集具有JSON编码的行

val object1 = Seq("""
{
  "object1": {
    "element1": "element1value",
    "object1_only": 1
  }
}
""").toDF("json")

val object2 = Seq("""
{
  "object2": {
    "element1": "element1value",
    "object2_only": 2
  }
}
""").toDF("json")
您可以使用
get\u json\u object
标准函数提取要加入的字段

val obj1_el1 = object1
  .select(get_json_object($"json", "$.object1.element1"))
scala> obj1_el1.show
+-----------------------------------------+
|get_json_object(json, $.object1.element1)|
+-----------------------------------------+
|                            element1value|
+-----------------------------------------+
连接的数据集将如下所示:

val o1 = object1
  .withColumn("join_column", get_json_object($"json", "$.object1.element1"))
val o2 = object2
  .withColumn("join_column", get_json_object($"json", "$.object2.element1"))
val s = o1.join(o2, Seq("join_column"))

请看这里并获得启发:谢谢,但从我所看到的情况来看,该示例在不转换结构的情况下读取和写入JSON。使用结构可以很容易地更改元素的名称,但我看不出如何在不重新处理数据帧的情况下更改JSON路径结构本身。您可以选择JSON并以JSON形式写入,可能是我太快了。