首页 > 解决方案 > 为什么 schema_of_json 失败?

问题描述

为什么第二次转型失败?

df
  .withColumn("schemaDetected", schema_of_json(lit("""{"Zipcode":704,"ZipCodeType":"STANDARD","City":"PARC PARQUE","State":"PR"}""")))
  .show(false)
//shows: struct<City:string,State:string,ZipCodeType:string,Zipcode:bigint>

df
  .withColumn("literal", lit("""{"Zipcode":704,"ZipCodeType":"STANDARD","City":"PARC PARQUE","State":"PR"}"""))
  .withColumn("schemaDetected", schema_of_json(col("literal")))
  .show(false)
// it fails:
// cannot resolve 'schema_of_json(`literal`)' due to data type mismatch: The input json should be a string literal and not null; however, got `literal`.;;

我需要获取一个列架构,但它只接受包含在方法中的“点亮”,当我添加一个列时它会失败。为什么?

标签: apache-spark

解决方案


第二个转换失败,因为当您将包含 json 字符串的列从数据帧传递给schema_of_json函数时,Spark 无法确定该列的每一行 json 字符串将评估为相同的模式

要理解为什么对所有行使用相同的模式很重要,您必须承认创建schema_of_json函数的主要用例是为函数推断模式from_json

from_json将 json 字符串转换为struct,基本上是几个新列。当然,数据框中的所有行都应该具有相同的列。因此,您必须确保from_json在数据框上使用时,将相同的模式传递给所有行。

正如您在票证SPARK-24642中看到的那样,在原点,您应该能够传递一个不是literalto的列。但是,它意味着合并每一行的推断模式。例如,如果您有以下数据框:schema_of_json

+------------------+
| json_string      |
+------------------+
| {"a": 1}         |
| {"b": 2}         |
| {"a": 3, "c": 4} |
+------------------+

并且您想将返回的模式传递schema_of_jsonfrom_json函数,您必须推断模式STRUCT<a INT, b INT, c INT>才能为所有行提供一致的模式。为此,您需要转换schema_of_json为一个聚合函数,该函数将通过迭代参数列的所有值或进行模式推断来构建模式(例如当您阅读 CSV 时)。这被认为不值得

因此,您不能将数据框列作为参数传递,而只能传递literal, 您可以使用litSPARK-24709中实现的函数

schema_of_json后来在 Spark 3.1 中升级(参见SPARK-31044)以能够采用可折叠列,这意味着可以在查询执行之前静态评估的列。这种可折叠列的一个例子是regexp_replace(lit("""{"test":1}""", "1", "2")),它不是直接的 aliteral而是 a 的转换literal

因此,回到您的案例,当您从lit(...). 由于 Spark 看不到列的内容,因此无法确定该列的值是否相同。但 Spark 必须确保这些值生成的模式相同,因此必须确保输入值相同。所以它会抛出一个错误,基本上是说“我不能确定对于所有行,该列中包含的 json 字符串都是相同的”


推荐阅读