【问题标题】:Spark-Sql, check if nested keys appear in json string and take the valuesSpark-Sql,检查嵌套键是否出现在 json 字符串中并取值
【发布时间】:2021-02-19 01:04:54
【问题描述】:

我有一个包含三列的表格,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 中执行此操作?

这是我的工作 presto 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

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

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

【问题讨论】:

  • 嗯,我想知道为什么要投反对票?这可能对其他人没有用。

标签: sql pyspark apache-spark-sql presto


【解决方案1】:

IIUC,您可以使用get_json_object + from_jsonmethod1w 的所有目标值转换为字符串数组,然后使用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 的子表达式的括号表示法时(参见 link),双-quote " 不起作用。
  2. 使用get_json_object(json_col, ..) 检索字符串,例如["target_1","target_3"] 用于Row-1 或NULL 用于Row-2
  3. 使用from_json(.., 'array&lt;string&gt;') 将上述内容转换为字符串数组
  4. 使用array_contains(.., target_word)判断数组中是否存在target_word

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 2016-03-02
    • 2016-04-08
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多