Bigquery:从 json 数组中提取数据

Posted

技术标签:

【中文标题】Bigquery:从 json 数组中提取数据【英文标题】:Bigquery: Extract data from an array of json 【发布时间】:2020-02-16 13:33:46 【问题描述】:

(这是this question 的扩展,但我的声誉太低,无法就该主题发表评论或提出更多问题...)

我们致力于 bigquery,因此在导入包或使用其他语言方面受到限制。而且,根据上面的链接,js 是一个解决方案,但不是我在这里寻找的。我是用js实现的,对我们的需求来说太慢了。

假设我们的列之一是如下所示的字符串(json 数组):["location":[22.99902,66.000],"t":1,"location":[55.32168,140.556],"t":2,"location":[85.0002,20.0055],"t":3]

我想从列中提取 "t":2 的 json

地点:

某些列没有元素“t”:2 有些列有多个元素 "t":2 每个字符串中json元素的数量可以改变 元素“t”:2 并不总是在第二个位置。

我不太了解正则表达式。我们用这种模式尝试了 regexp_extract:r'(\.*?\"t\":2.*?\)')),但这不起作用。它提取“t”:2 之前的所有内容,包括“t”:2 的 json。我们只想要元素 "t":2 的 json。

您能否建议一种可行的正则表达式模式?

编辑:

我偏爱能获得 1 场比赛的解决方案。假设我有这个字符串: ["location":[22.99902,66.000],"t":1,"location":[55.32168,140.556],"t":2,"location":[55.33,141.785],"t":2], 我宁愿只收到 1 个答案,第一个。

在那种情况下,也许正则表达式不太合适,但我真的不确定?

【问题讨论】:

当你说你想要 "t":2 的 json 时,你的意思是最近的 内的所有内容吗?如"location":[22.99902,66.000] 等? @RoboMop 是的 【参考方案1】:

这个怎么样:

(?<=\)(?=.*?\"t\"\s*:\s*2).*?(?=\)

如所见here

【讨论】:

上面的例子看起来效果很好。出于某种奇怪的原因,在我的数据上效果不佳,这有点复杂。工作正在进行中。我赞成您的问题,但声誉低下……还有一个问题:您可以通过什么方式返回找到的第一个实例?不只是他们所有人?谢谢【参考方案2】:

还有另一种解决方案,但它不是基于正则表达式的(正如我最初提出的那样)。所以这不应该算作我自己问题的最终答案,但它可能是有用的。 它基于数组中字符串的拆分,然后在数组中选择满足我需要的元素。

步骤:

    将字符串转换为更适合拆分的字符串(使用“|”作为分隔符):replace(replace(replace(my_field,',','|'),'[',''),']','') 使用split() 拆分它,这会产生一个字符串数组(每个字符串都是一个json 元素) 找到相关元素 ("t":2) - 就我而言,第一个已经足够好了,所以我将查询限制为 1:array( select data from unnest(split(replace(replace(replace(my_field,',','|'),'[',''),']',''),'|')) as data where data like '%"t":2%' limit 1) 使用 array_to_string() 将其转换为可用字符串,并在该字符串上使用 json_extract 从我需要的元素中提取相关信息(例如,位置坐标 x)。

所以把它们放在一起:round(safe_cast(json_extract(array_to_string(array( select data from unnest(split(replace(replace(replace(my_field,',','|'),'[',''),']',''),'|')) as data where data like '%"t":2%' limit 1),''),'$.location[0]') as float64),3) loc_x

【讨论】:

【参考方案3】:

2020 年 5 月 1 日更新

一个新函数 JSON_EXTRACT_ARRAY 刚刚添加到 JSON 列表中 职能。此函数允许您将 JSON 文档的内容提取为 一个字符串数组。

所以在下面你可以用内置函数 JSON_EXTRACT_ARRAY 替换 json2array UDF 的使用,如下例所示

#standardSQL
SELECT id,  
  (
    SELECT x
    FROM UNNEST(JSON_EXTRACT_ARRAY(json, '$')) x
    WHERE JSON_EXTRACT_SCALAR(x, '$.t') = '2'
  ) extracted
FROM `project.dataset.table`  

==============

以下是 BigQuery 标准 SQL

#standardSQL
CREATE TEMP FUNCTION json2array(json STRING)
RETURNS ARRAY<STRING>
LANGUAGE js AS """
  return JSON.parse(json).map(x=>JSON.stringify(x));
"""; 
SELECT id,  
  (
    SELECT x
    FROM UNNEST(json2array(JSON_EXTRACT(json, '$'))) x
    WHERE JSON_EXTRACT_SCALAR(x, '$.t') = '2'
  ) extracted
FROM `project.dataset.table`  

你可以像下面的例子一样使用虚拟数据测试,玩上面的例子

#standardSQL
CREATE TEMP FUNCTION json2array(json STRING)
RETURNS ARRAY<STRING>
LANGUAGE js AS """
  return JSON.parse(json).map(x=>JSON.stringify(x));
"""; 
WITH `project.dataset.table` AS (
  SELECT 1 id, '["location":[22.99902,66.000],"t":1,"location":[55.32168,140.556],"t":2,"location":[85.0002,20.0055],"t":3]' json UNION ALL
  SELECT 2, '["location":[22.99902,66.000],"t":11,"location":[85.0002,20.0055],"t":13]'
)
SELECT id,  
  (
    SELECT x
    FROM UNNEST(json2array(JSON_EXTRACT(json, '$'))) x
    WHERE JSON_EXTRACT_SCALAR(x, '$.t') = '2'
  ) extracted
FROM `project.dataset.table`

有输出

Row id  extracted    
1   1   "location":[55.32168,140.556],"t":2    
2   2   null     

以上假设在 json 列中具有"t":2 的元素不超过一个。如果可以有多个 - 您应该添加 ARRAY 如下

SELECT id,  
  ARRAY(
    SELECT x
    FROM UNNEST(json2array(JSON_EXTRACT(json, '$'))) x
    WHERE JSON_EXTRACT_SCALAR(x, '$.t') = '2'
  ) extracted
FROM `project.dataset.table`

【讨论】:

这是一个可行的解决方案,但正如我在问题中所说,我正试图从 js 中转移,因为它需要太多时间,这就是我正在寻找正则表达式的原因【参考方案4】:

尽管如此,您已经发布了解决您的问题的工作。我相信这个答案将是有益的。您提到选择的答案之一超出了您的需要,我在下面编写了查询以重现您的案例并实现目标输出。

  WITH
  data AS (
  SELECT
    " [ \"location\":[22.99902,66.000]\"t\":1,\"location\":[55.32168,140.556],\"t\":2,\"location\":[85.0002,20.0055],\"t\":3] " AS string_j
  UNION ALL
  SELECT
    " [ \"location\":[22.99902,66.000]\"t\":1,\"location\":[55.32168,140.556],\"t\":3,\"location\":[85.0002,20.0055],\"t\":3] " AS string_j
  UNION ALL
  SELECT
    " [ \"location\":[22.99902,66.000]\"t\":1,\"location\":[55.32168,140.556],\"t\":3,\"location\":[85.0002,20.0055],\"t\":3] " AS string_j
  UNION ALL
  SELECT
    " [ \"location\":[22.99902,66.000]\"t\":1,\"location\":[55.32168,140.556],\"t\":3,\"location\":[85.0002,20.0055],\"t\":3] " AS string_j ),
  refined_data AS (
  SELECT
    REGEXP_EXTRACT(string_j, r"\\"\w*\"\:\[\d*\.\d*\,\d*\.\d*\]\,\"t\"\:2\") AS desired_field
  FROM
    data )
  SELECT
  *
  FROM
  refined_data
  WHERE
  desired_field IS NOT NULL

请注意,我使用了临时表中描述的虚拟对象,填充在 WITH 方法中。如下:

后记,在 refined_data 表中,我使用 REGEXP_EXTRACT 从列中提取所需的字符串。请注意,对于没有匹配表达式的行,输出为 null。因此,refined_data 表如下:

如您所见,现在只需要一个简单的 WHERE 过滤器即可获得所需的输出,这是在最后一次选择中完成的。

另外你可以看到我提供的正则表达式的信息here。

【讨论】:

以上是关于Bigquery:从 json 数组中提取数据的主要内容,如果未能解决你的问题,请参考以下文章

从 BigQuery 中的 JSON 数组中提取多个值

Google BigQuery SQL:从 JSON(列表和数组)中提取数据到列中

如何从 BigQuery 中的 JSON 字符串中提取数组

Bigquery:是不是有一种 json 路径方法可以仅从具有动态键的 json 数组中提取值?

从 Google Ads BigQuery 数据传输中提取/取消嵌套数组

选择/提取 JSON 元素时的高效 BigQuery