【问题标题】:How to parse a JSON containing string property representing JSON如何解析包含表示 JSON 的字符串属性的 JSON
【发布时间】:2019-04-05 16:25:18
【问题描述】:

我有许多结构如下的 JSON。

{
    "p1":"v1",
    "p2":"v2",
    "p3":"v3",
    "modules": "{ \"nest11\":\"n1v1\", \"nest12\":\"n1v2\", \"nest13\": { \"nest21\": \"n2v1\" }  }"
}

如何解析成这个?

v1、v2、v3、n1v1、n1v2、n2v1

提取“v1,v2,v3”不是问题,而是如何访问“n1v1,n1v2,n2v1”使用Spark Data Frame API

【问题讨论】:

    标签: apache-spark apache-spark-sql databricks azure-databricks


    【解决方案1】:

    一种方法是使用官方databricks网站中的DataFrameFlattener隐式类found

    首先,您需要为 modules 列定义 JSON 架构,然后将数据框展平,如下所示。这里我假设文件test_json.txt 会有下一个内容:

    {
        "p1":"v1",
        "p2":"v2",
        "p3":"v3",
        "modules": "{ \"nest11\":\"n1v1\", \"nest12\":\"n1v2\", \"nest13\": { \"nest21\": \"n2v1\" }  }"
    }
    

    代码如下:

    import org.apache.spark.sql.functions.col
    import org.apache.spark.sql.{Column, DataFrame}
    import org.apache.spark.sql.types.{DataType, StructType, StringType}
    
    implicit class DataFrameFlattener(df: DataFrame) {
      def flattenSchema: DataFrame = {
        df.select(flatten(Nil, df.schema): _*)
      }
    
      protected def flatten(path: Seq[String], schema: DataType): Seq[Column] = schema match {
        case s: StructType => s.fields.flatMap(f => flatten(path :+ f.name, f.dataType))
        case other => col(path.map(n => s"`$n`").mkString(".")).as(path.mkString(".")) :: Nil
      }
    }
    
    val schema = (new StructType)
      .add("nest11", StringType)
      .add("nest12", StringType)
      .add("nest13", (new StructType).add("nest21", StringType, false))
    
    val df = spark.read
      .option("multiLine", true).option("mode", "PERMISSIVE")
      .json("C:\\temp\\test_json.txt")
    
    df.withColumn("modules", from_json($"modules", schema))
      .select($"*")
      .flattenSchema
    

    这应该是输出:

    +--------------+--------------+---------------------+---+---+---+
    |modules.nest11|modules.nest12|modules.nest13.nest21|p1 |p2 |p3 |
    +--------------+--------------+---------------------+---+---+---+
    |n1v1          |n1v2          |n2v1                 |v1 |v2 |v3 |
    +--------------+--------------+---------------------+---+---+---+
    

    如果您需要进一步说明,请告诉我。

    【讨论】:

    • 非常感谢。这正是我想要的!
    【解决方案2】:

    您需要做的就是将 JSON 字符串解析为实际的 javascript 对象

    const originalJSON = {
      "p1":"v1",
      "p2":"v2",
      "p3":"v3",
      "modules": "{ \"nest11\":\"n1v1\", \"nest12\":\"n1v2\", \"nest13\": { \"nest21\": \"n2v1\" }  }"
    }
    const { modules, ...rest } = originalJSON
    const result = {
      ...rest,
      modules: JSON.parse(modules)
    }
    console.log(result)
    console.log(result.modules.nest11)
    

    【讨论】:

    • 你可以在 Databricks 笔记本中使用 JavaScript 吗?
    • 对不起,我不熟悉那是什么
    • 大家好,一般解析没问题,用Spark Data Frame API怎么做?
    • N1v1 也可以通过这种方式访问​​,不,我不知道那是什么,您能详细说明您想要实现的目标吗?
    【解决方案3】:

    当您检索“模块”元素时,您实际上是在检索一个字符串。您必须将此字符串实例化为新的 JSON 对象。我不知道您使用的是什么语言,但您通常会执行以下操作:

    String modules_str = orginalJSON.get("modules");
    JSON modulesJSON = new JSON(modules_str);
    String nest11_str = modulesJSON.get("nest11");
    

    【讨论】:

    • 这个想法是将双重编码的 JSON 作为字符串存储在父 JSON 结构中。除了编码器/解码器之外,不知道它是否被编码为 JSON。既然您知道它是 JSON,您可以通过如上所示重新实例化它来将其转换回 JSON(即删除退出字符“\”)结构。
    • 一般解析没问题,用Spark Data Frame API怎么做?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-22
    • 2015-09-09
    • 1970-01-01
    • 2019-04-03
    • 1970-01-01
    相关资源
    最近更新 更多