如何使用BigQuery提取JSON对象中的所有键

时间:2016-01-20 02:09:01

标签: json google-bigquery

BigQuery具有在实时交互式查询中解析JSON的功能:只需将JSON编码对象存储为字符串,并使用JSON_EXTRACT_SCALAR等函数实时查询。

但是,我无法找到发现这些对象中所有键(属性)的方法。

我可以使用UDF吗?

5 个答案:

答案 0 :(得分:4)

以下版本修复了一些"问题"在原始答案中如下:
1.只发出第一级键 2.必须手动编译并运行最终查询以根据发现的密钥提取信息

SELECT type, key, value, COUNT(1) AS weight 
FROM JS(
  (SELECT json, type 
     FROM [fh-bigquery:openlibrary.ol_dump_20151231@0] 
     WHERE type = '/type/edition'
  ),
  json, type,                             // Input columns
  "[{name: 'type', type:'string'},        // Output schema
   {name: 'key', type:'string'},
   {name: 'value', type:'string'}]",
   "function(r, emit) {                    // The function
      x = JSON.parse(r.json);
      processKey(x, '');
      function processKey(node, parent) {
        if (parent !== '') {parent += '.'};
        Object.keys(node).map(function(key) {
          value = node[key].toString();
          if (value !== '[object Object]') {
            emit({type:r.type, key:parent + key, value:value});
          } else {
            processKey(node[key], parent + key);
          };
        });         
      };
    }"
  )
GROUP EACH BY type, key, value
ORDER BY weight DESC
LIMIT 1000

结果如下

Row          type   key                 value                         weight     
1   /type/edition   type.key            /type/edition               25140209     
2   /type/edition   last_modified.type  /type/datetime              25140209     
3   /type/edition   created.type        /type/datetime              17092292     
4   /type/edition   languages.0.key     /languages/eng              14514830     
5   /type/edition   notes.type          /type/text                  11681480     
6   /type/edition   revision            2                            8714084     
7   /type/edition   latest_revision     2                            8704217     
8   /type/edition   revision            3                            5041680     
9   /type/edition   latest_revision     3                            5040634     
10  /type/edition   created.value       2008-04-01T03:28:50.625462   3579095     
11  /type/edition   revision            1                            3396868     
12  /type/edition   physical_format     Paperback                    3181270     
13  /type/edition   revision            4                            3053266     
14  /type/edition   latest_revision     4                            3053197     
15  /type/edition   revision            5                            2076094     
16  /type/edition   latest_revision     5                            2076072     
17  /type/edition   publish_country     nyu                          1727347     
18  /type/edition   created.value       2008-04-30T09:38:13.731961   1681227     
19  /type/edition   publish_country     enk                          1627969     
20  /type/edition   publish_places      London                       1613755     
21  /type/edition   physical_format     Hardcover                    1495864     
22  /type/edition   publish_places      New York                     1467779     
23  /type/edition   revision            6                            1437467     
24  /type/edition   latest_revision     6                            1437463     
25  /type/edition   publish_country     xxk                          1407624 

答案 1 :(得分:1)

如何在BigQuery中使用JavaScript UDF提取所有JSON对象键:

$('.ty-profile-field__select-state').val('');
$('.ty-profile-field__select-state option:first').prop('selected', true);
$('.ty-profile-field__select-state option').each(function() { $(this).prop('selected', false); });
$(".ty-profile-field__select-state option:first").prop('selected', true);
$('.ty-profile-field__select-state').find('option:selected').prop('selected', false);
enter code here

分组并计算:

enter image description here

一旦找到了可以使用的所有密钥,就可以在普通的SQL查询中使用JSON_EXTRACT_SCALAR:

现在您知道了密钥,您可以提取所有已知类型的信息:

SELECT type, key
FROM (
  SELECT * FROM
  js(
    (SELECT json, type FROM [fh-bigquery:openlibrary.ol_dump_20151231]
    ),
    // Input columns.
    json, type,
    // Output schema.
    "[{name: 'key', type:'string'},
     {name: 'type', type:'string'}]",
     // The function.
     "function(r, emit) { 
      x=JSON.parse(r.json)
      Object.keys(x).forEach(function(entry) {
        emit({key:entry, type:r.type,});
      });     
    }"
  )
)
LIMIT 100

(根据https://openlibrary.org/developers/dumps从Open Library数据转储reddit conversation获取的样本数据)

答案 2 :(得分:1)

这里使用Standard SQL

CREATE TEMP FUNCTION jsonObjectKeys(input STRING)
RETURNS Array<String>
LANGUAGE js AS """
  return Object.keys(JSON.parse(input));
""";
WITH keys AS (
  SELECT
    jsonObjectKeys(myColumn) AS keys
  FROM
    myProject.myTable
  WHERE myColumn IS NOT NULL
)
SELECT
  DISTINCT k
FROM keys
CROSS JOIN UNNEST(keys.keys) AS k
ORDER BY k

答案 3 :(得分:0)

这就是我提出的(特别是对于StandardSQL)..不确定在列表中累积是否是最好的方法...另外..我简化了我的情况,我只关心键。

create-react-app

答案 4 :(得分:0)

上述答案在当前 (2021) 版本中效果不佳,如果 JSON 字段为空或 JSON 具有空条目,则失败,不能很好地聚合(我们正在尝试获取结构,而不是内容) 等。

所以,这是基于 Felipe Hoffaanswer 的改进版本。

它是完全递归的;检查 nullArray 类型;抑制数组索引(如 []);标记为确定性的,因此它会被缓存;并对结果进行分组、排序和计数。

示例输出:

key type    n
""  null    213
avatar  string  1046
blinking    boolean 1046
created_at  string  1046
deprecated_fields   Array   1046
display_name    string  1046
fields  Array   1046
fields.[]   Object  31
fields.[].name  string  31
fields.[].value string  31
fields.[].verified_at   null    27
fields.[].verified_at   string  4
friends_count   number  1046

注意:

  1. 空字符串键表示该字段本身实际上为空
  2. deprecated_fields 键是 JSON 中所有示例都为 ..., deprecated_fields: [], ... 的键
  3. null 作为字符串 "null" 返回,与其他类型一样(不是 SQL null)

可以改进检测不同类型的数字(int、bigint、float、decimal)、日期、存储为字符串的数字等。但是呃,这对我的目的来说已经足够了,而且需要更多的处理。

只需更改最后几行中的 your-* 位:

CREATE TEMP FUNCTION jsonParsed(input STRING)
RETURNS Array<Struct<key STRING, type STRING>>
DETERMINISTIC LANGUAGE js AS 
"""
function processKey(node, parent) {
    var ary = [];
    if (parent !== '') {
        parent += '.';
    }
    if (node == null) {
        ary.push({
            key: parent,
            type: 'null'
        })
    } else {
        Object.keys(node).map(function(key) {
            var v = node[key];
            if (node.constructor.name == "Array") {
                keytouse = '[]'
            } else {
                keytouse = key
            }
            if ((v == null) || (typeof(v) !== 'object')) {
                if (v == null) { typetouse = 'null';} else {typetouse = typeof(v);}
                ary.push({
                    key: parent + keytouse,
                    type: typetouse
                });
            } else {
                ary.push({
                    key: parent + keytouse,
                    type: v.constructor.name
                });
                ary = [].concat(ary, processKey(v, parent + keytouse));
            }
        });
    }
    return ary;
}
return processKey(JSON.parse(input), '');
""";

with keys as (SELECT jsonParsed(your-json-field) as keys  FROM `your-project-id.your-database-id.your-table-id`)
select key, type, count(*) as n from keys k cross join unnest(k.keys) as kk group by key, type order by key asc;