BigQuery:创建JSON数据类型的列

时间:2016-06-06 14:55:06

标签: google-bigquery

我正在尝试使用以下架构将json加载到BigQuery中:

{
key_a:value_a,
key_b:{
   key_c:value_c,
   key_d:value_d
  }
key_e:{
   key_f:value_f,
   key_g:value_g
  }
}

key_e下的键是动态的,即在一个响应中key_e将包含key_f和key_g,而对于另一个响应,它将包含key_h和key_i。可以随时创建新密钥,因此我无法为所有可能的密钥创建具有可空字段的记录。

相反,我想创建一个具有JSON数据类型的列,然后可以使用JSON_EXTRACT()函数查询该列。我已经尝试将key_e作为具有STRING数据类型的列加载,但是value_e被分析为JSON,因此失败。

如果没有JSON数据类型,如何将一部分JSON加载到单个BigQuery列中?

3 个答案:

答案 0 :(得分:10)

将你的JSON作为BigQuery中的单个字符串列是definitelly的一个选项。如果您拥有大量数据,最终会导致查询价格过高,因为所有数据都会在一列中结束,实际查询逻辑会变得非常混乱。

如果你有轻微改变你的"设计" - 我建议考虑下面一个 - 在这里你可以采用重复模式

表架构:

[
  { "name": "key_a",
    "type": "STRING" },
  { "name": "key_b",
    "type": "RECORD",
    "mode": "REPEATED",
    "fields": [
      { "name": "key",
        "type": "STRING"},
      { "name": "value",
        "type": "STRING"}
    ]
  },
  { "name": "key_e",
    "type": "RECORD",
    "mode": "REPEATED",
    "fields": [
      { "name": "key",
        "type": "STRING"},
      { "name": "value",
        "type": "STRING"}
    ]
  }
]

要加载的JSON示例

{"key_a": "value_a1", "key_b": [{"key": "key_c", "value": "value_c"}, {"key": "key_d", "value": "value_d"}], "key_e": [{"key": "key_f", "value": "value_f"}, {"key": "key_g", "value": "value_g"}]}
{"key_a": "value_a2", "key_b": [{"key": "key_x", "value": "value_x"}, {"key": "key_y", "value": "value_y"}], "key_e": [{"key": "key_h", "value": "value_h"}, {"key": "key_i", "value": "value_i"}]}

请注意:它应该是换行符分隔的JSON,因此每行必须在一行

答案 1 :(得分:3)

你不能用BigQuery直接做这个,但你可以让它在两个过程中工作:

(1)将您的JSON数据导入为具有单个字符串列的CSV文件。

(2)转换每一行以将“any-type”字段打包成字符串。编写一个UDF,它接受一个字符串并发出你想要的最后一列。将此查询的输出附加到目标表。

示例

我将从一些JSON开始:

{"a": 0, "b": "zero", "c": { "woodchuck": "a"}}
{"a": 1, "b": "one", "c": { "chipmunk": "b"}}
{"a": 2, "b": "two", "c": { "squirrel": "c"}}
{"a": 3, "b": "three", "c": { "chinchilla": "d"}}
{"a": 4, "b": "four", "c": { "capybara": "e"}}
{"a": 5, "b": "five", "c": { "housemouse": "f"}}
{"a": 6, "b": "six", "c": { "molerat": "g"}}
{"a": 7, "b": "seven", "c": { "marmot": "h"}}
{"a": 8, "b": "eight", "c": { "badger": "i"}}

将其作为带有单个STRING列的CSV导入BigQuery(我称之为'blob')。我不得不将分隔符设置为任意且不太可能的东西(刺 - 'þ')或它超过默认','。

验证您的表格是否正确导入。您应该看到简单的单列架构,预览看起来就像源文件一样。

接下来,我们编写一个查询,将其转换为您想要的形状。对于此示例,我们想要以下架构:

a (INTEGER)
b (STRING)
c (STRING -- packed JSON)

我们可以使用UDF执行此操作:

// Map a JSON string column ('blob') => { a (integer), b (string), c (json-string) }
bigquery.defineFunction(
  'extractAndRepack',                // Name of the function exported to SQL
  ['blob'],                          // Names of input columns
  [{'name': 'a', 'type': 'integer'}, // Output schema
   {'name': 'b', 'type': 'string'},
   {'name': 'c', 'type': 'string'}],
  function (row, emit) {
    var parsed = JSON.parse(row.blob);
    var repacked = JSON.stringify(parsed.c);
    emit({a: parsed.a, b: parsed.b, c: repacked});
  }
);

以及相应的查询:

SELECT a, b, c FROM extractAndRepack(JsonAnyKey.raw)

现在您只需要运行查询(选择所需的目标表),您就可以使用自己喜欢的形式获取数据。

Row a   b       c    
1   0   zero    {"woodchuck":"a"}    
2   1   one     {"chipmunk":"b"}     
3   2   two     {"squirrel":"c"}     
4   3   three   {"chinchilla":"d"}   
5   4   four    {"capybara":"e"}     
6   5   five    {"housemouse":"f"}   
7   6   six     {"molerat":"g"}  
8   7   seven   {"marmot":"h"}   
9   8   eight   {"badger":"i"}   

答案 2 :(得分:2)

一种方法是将此文件加载为CSV而不是JSON(并引用值或消除中间的换行符),然后它将成为BigQuery中的单个STRING列。

P.S。你是正确的,拥有原生JSON数据类型会使这个场景更自然,BigQuery团队非常清楚它。