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 数组中提取数据的主要内容,如果未能解决你的问题,请参考以下文章
Google BigQuery SQL:从 JSON(列表和数组)中提取数据到列中
Bigquery:是不是有一种 json 路径方法可以仅从具有动态键的 json 数组中提取值?