是否可以计算每个键在 JSON 列中出现的次数?
Posted
技术标签:
【中文标题】是否可以计算每个键在 JSON 列中出现的次数?【英文标题】:Is it possible to count the number of times each key has occurred in a column of JSON? 【发布时间】:2016-10-12 00:31:42 【问题描述】:我有一个 BigQuery 表,其中有一列包含 JSON。
我想输出每个键在列中出现的次数的计数,然后按计数降序排序。与所有键关联的值是1
。
每个对象有一个已知/有限数量的键,但我宁愿不依赖它,以防看到的最大对象发生变化。
总体上存在已知/有限数量的键,但我不想依赖在列表更改时枚举/更新列表。
例如输入:三行一列名为“json”
[
"json": "'A': 1",
"json": "'B': 1",
"json": "'B': 1, 'C': 1"
]
例如输出:三行两列,分别命名为“key”和“count”
[
"key": "B", "count": 2,
"key": "A", "count": 1,
"key": "C", "count": 1
]
考虑到我不想依赖每个对象和整体上有限数量的键,最简单的方法是什么?
【问题讨论】:
请编辑您的问题以显示您遇到问题的代码的Minimal, Complete, and Verifiable example,然后我们可以尝试帮助解决具体问题。你也可以阅读How to Ask。至少提供一些简单的示例来显示您的输入数据和预期结果。那将是我认为的最低限度 (我有相对粗糙的工作代码,它依赖于每个对象的有限数量的键和有限数量的键,但是如果没有这些限制,我想不出一种方法) 澄清 - 您的输入示例代表三行或者是一行 输入和输出都是三行,虽然这个数字匹配是巧合 【参考方案1】:BigQuery 标准 SQL 如下
见Enabling Standard SQL和User-Defined Functions
CREATE TEMPORARY FUNCTION parseJson(y STRING)
RETURNS ARRAY<STRING>
LANGUAGE js AS """
var z = new Array();
processKey(JSON.parse(y), '');
function processKey(node, parent)
Object.keys(node).map(function(key)
value = node[key].toString();
if (value !== '[object Object]')
z.push(key)
else
if (parent !== '' && parent.substr(parent.length-1) !== '.') parent += '.';
processKey(node[key], parent + key);
;
);
;
return z
""";
WITH theTable AS (
SELECT '"json":"A":"1"' AS json UNION ALL
SELECT '"json":"B":"1"' AS json UNION ALL
SELECT '"json":"B":"1","C":"1"' AS json
)
SELECT key, COUNT(1) AS `count`
FROM theTable, UNNEST(parseJson(json)) AS key
GROUP BY key
ORDER BY 2 DESC
输出:
key count
B 2
A 1
C 1
注意:parseJson UDF 足够通用,可以处理任何 json,因此您可以例如尝试使用以下输入的上述代码,它仍然可以工作:
WITH theTable AS (
SELECT '"json":"A":"1"' AS json UNION ALL
SELECT '"json":"B":"1"' AS json UNION ALL
SELECT '"json":"B":"1","C":"1"' AS json UNION ALL
SELECT '"A":"1"' AS json UNION ALL
SELECT '"B":"1"' AS json UNION ALL
SELECT '"B":"1","C":"1"' AS json
)
输出:
key count
B 4
A 2
C 2
为 BigQuery Legacy SQL 添加了版本
为了简单起见,在这里展示和进一步测试 - 我在这里使用的是旧版 SQL UDF 的 inline version
。旧版 SQL 中的 Inline version
不受官方支持 - 因此,如果它适用于您 - 您需要稍微改造一下 - 有关 BigQuery 旧版 SQL 中 UDF 的详细信息,请参阅 BigQuery User-Defined Functions
SELECT key, COUNT(1) as cnt
FROM JS((
SELECT json FROM
(SELECT '"json":"A":"1"' AS json),
(SELECT '"json":"B":"1"' AS json),
(SELECT '"json":"B":"1","C":"1"' AS json),
(SELECT '"A":"1"' AS json),
(SELECT '"B":"1"' AS json),
(SELECT '"B":"1","C":"1"' AS json)
),
json, // Input columns
"[name: 'parent', type:'string', // Output schema
name: 'key', type:'string',
name: 'value', type:'string']",
"function(r, emit) // The function
processKey(JSON.parse(r.json), '');
function processKey(node, parent)
Object.keys(node).map(function(key)
value = node[key].toString();
if (value !== '[object Object]')
emit(parent:parent, key:key, value:value);
else
if (parent !== '' && parent.substr(parent.length-1) !== '.') parent += '.';
processKey(node[key], parent + key);
;
);
;
"
)
GROUP BY key
ORDER BY cnt DESC
【讨论】:
谢谢!不幸的是,这是针对尚不支持标准 SQL 的 Mode Analytics 仪表板。如果一周内没有旧版 SQL 解决方案,我会接受您的回答。 @AndreyFedorov - 刚刚为 bigquery legacy sql 添加了版本 您可以通过将#StandardSQL
放在查询的第一行(取决于仪表板在将文本发送到 BigQuery 之前是否修改文本)来将标准 SQL 与仪表板一起使用。【参考方案2】:
如果您禁用旧版 SQL,则可以使用新的 bigquery REGEX_EXTRACT_ALL 函数,这似乎正是您要查找的内容:https://cloud.google.com/bigquery/sql-reference/functions-and-operators#regexp_extract_all
【讨论】:
至于让查询进入模式,我建议在 bigquery 中将非传统 sql 作为视图。模式应该能够毫无问题地查询视图。以上是关于是否可以计算每个键在 JSON 列中出现的次数?的主要内容,如果未能解决你的问题,请参考以下文章
计算 json 对象中键的出现次数 - IMPALA/HIVE