Spark-Sql,检查嵌套键是否出现在json字符串中并取值

Spark-Sql, check if nested keys appear in json string and take the values

我有一个 table 三列, source_word target_word json_col

source_word    target_word     json_col
source_1       target_1        {"source_1":{"method1":[{"w":"target_1"},{"w":"target_3"}]}}
source_2       target_2        {"source_2":{"method2":[{"w":"target_2"},{"w":"target_4"}]}}

如您所见,json_col 包含一个嵌套的 dict/json,其中第一个键是 source_word 列 source_1 中的单词,然后是方法名称例如method1, method2, ..., methodn,最后它有一个带有<w, target_word>模式的字典列表(w只是一个文字,表示这是一个词)。我有兴趣检查 json_col 是否包含源词 source_1 作为关键字,然后是 method1 并且关键字 target1method1 中。我如何在 spark SQL?

中执行此操作

这是我的作品sql:

select 
   source_word, target_word
from
   table
where
    contains(cast(json_extract(json_col, concat('$["', source_word, '"]["method1"]')) as array(json)), 
json_parse(concat('{"w":"', target_word, '"}')))

这就是我在 Spark 中想到的 SQL:

select 
   source_word, target_word
from
   table
where
   instr(json_col, concat('{"', source_word, '":{"method1"')) > 0
   and instr(json_col, concat('{"w":"', target_word, '"}')) > 0

但后来我意识到这个 sql 中的缺陷,其中 instr 的条件可能都成立,但我正在寻找的 target_word 并非来自 method1.

理想情况下,它应该从 method1 中获取值,比如 [{"w":"target_1"},{"w":"target_3"}] 并查看 {"w":"target_1"} 是否在其中。

有人能给我指出正确的方向吗?谢谢!

IIUC,可以用get_json_object + from_json to convert all target-values of w under method1 to an array of strings and then use array_contains过滤行:

df = spark.createDataFrame([
   ("source_1", "target_1", """{"source_1":{"method1":[{"w":"target_1"},{"w":"target_3"}]}}"""),
   ("source_2", "target_2", """{"source_2":{"method2":[{"w":"target_2"},{"w":"target_4"}]}}""")
], ["source_word", "target_word", "json_col"])

df.createOrReplaceTempView("table")

spark.sql("""
  SELECT
    source_word, target_word
  FROM
    table
  WHERE
    array_contains(
      from_json(get_json_object(json_col, concat("$['",source_word,"'].method1[*].w")), 'array<string>'),
      target_word
    )
""").show()
+-----------+-----------+
|source_word|target_word|
+-----------+-----------+
|   source_1|   target_1|
+-----------+-----------+

我们执行以下操作的地方:

  1. 使用concat("$['",source_word,"'].method1[*].w") 创建 JSONPath。例如,我们将为第 1 行设置 $['source_1'].method1[*].w注意对于Spark,我们在使用括号的时候必须用单引号'source_word括起来带有 JSONPath 的子表达式(参见 ),双引号 " 将不起作用。
  2. 使用 get_json_object(json_col, ..) 检索字符串,如 ["target_1","target_3"] 用于第 1 行或 NULL 用于第 2 行
  3. 使用from_json(.., 'array<string>')将上面的转换为字符串数组
  4. array_contains(.., target_word)判断数组中是否存在target_word

顺便说一句。您还可以将上面的 from_json + array_contains 替换为 instr 函数以搜索 target_word,如您的代码所示。