用于BigQuerySink的bigquery.TableSchema的JSON表模式

时间:2016-03-21 09:43:38

标签: python google-cloud-dataflow

我有一个以JSON格式定义的非平凡的表模式(涉及嵌套和重复的字段)(具有名称,类型,模式属性)并存储在文件中。它已成功用于使用bq load命令填充bigquery表。

但是当我尝试使用Dataflow Python SDK和BigQuerySink做同样的事情时,schema参数必须是以逗号分隔的'name':'type'元素列表或bigquery.TableSchema对象

有没有方便的方法可以将我的JSON架构设置为bigquery.TableSchema,还是必须将其转换为name:value列表?

6 个答案:

答案 0 :(得分:6)

目前您无法直接指定JSON架构。您必须将模式指定为包含以逗号分隔的字段列表或bigquery.TableSchema对象的字符串。

如果架构很复杂并且包含嵌套和/或重复的字段,我们建议您构建一个bigquery.TableSchema对象。

以下是具有嵌套和重复字段的示例bigquery.TableSchema对象。

from apitools.clients import bigquery

table_schema = bigquery.TableSchema()

# ‘string’ field
field_schema = bigquery.TableFieldSchema()
field_schema.name = 'fullName'
field_schema.type = 'string'
field_schema.mode = 'required'
table_schema.fields.append(field_schema)

# ‘integer’ field
field_schema = bigquery.TableFieldSchema()
field_schema.name = 'age'
field_schema.type = 'integer'
field_schema.mode = 'nullable'
table_schema.fields.append(field_schema)

# nested field
field_schema = bigquery.TableFieldSchema()
field_schema.name = 'phoneNumber'
field_schema.type = 'record'
field_schema.mode = 'nullable'

area_code = bigquery.TableFieldSchema()
area_code.name = 'areaCode'
area_code.type = 'integer'
area_code.mode = 'nullable'
field_schema.fields.append(area_code)

number = bigquery.TableFieldSchema()
number.name = 'number'
number.type = 'integer'
number.mode = 'nullable'
field_schema.fields.append(number)
table_schema.fields.append(field_schema)

# repeated field
field_schema = bigquery.TableFieldSchema()
field_schema.name = 'children'
field_schema.type = 'string'
field_schema.mode = 'repeated'
table_schema.fields.append(field_schema)

答案 1 :(得分:3)

我遇到了同样的问题。在我的情况下,我已经在bigquery中加载了一些json,并自动生成了一个模式。

所以我能够通过命令获得自动生成的模式:

bq show --format prettyjson my-gcp-project:my-bq-table |jq .schema > my-bq-table.json

然后可以使用此代码段将模式转换为bigquery.TableSchema

from apache_beam.io.gcp.internal.clients import bigquery


def _get_field_schema(**kwargs):
    field_schema = bigquery.TableFieldSchema()
    field_schema.name = kwargs['name']
    field_schema.type = kwargs.get('type', 'STRING')
    field_schema.mode = kwargs.get('mode', 'NULLABLE')
    fields = kwargs.get('fields')
    if fields:
        for field in fields:
            field_schema.fields.append(_get_field_schema(**field))
    return field_schema


def _inject_fields(fields, table_schema):
    for field in fields:
        table_schema.fields.append(_get_field_schema(**field))


def parse_bq_json_schema(schema):
    table_schema = bigquery.TableSchema()
    _inject_fields(schema['fields'], table_schema)
    return table_schema

它将与bigquery json架构规范一起使用,如果您像我一样懒,如果您对默认情况下可为空字符串的字段感到满意,则可以避免指定typemode

答案 2 :(得分:2)

BigQuery 库中有一个内置的转换器函数:

from google.cloud import bigquery
...
client = bigquery.Client()
client.schema_from_json('path/to/schema.json`)

答案 3 :(得分:1)

上述由Andrea Pierleoni发布的代码片段适用于google-cloud-bigquery python客户端的旧版本,例如,恰好通过0.25.0安装的google-cloud-bigquery的{​​{1}}版本。

但是,BigQuery Python客户端API在pip install apache-beam[gcp]的最新版本中发生了巨大变化,例如在我当前使用的google-cloud-bigquery1.8.0版本中不起作用。

如果您使用的是bigquery.TableFieldSchema()软件包的最新版本,则可以通过以下方法从JSON文件中获取所需的bigquery.TableSchema()列表(例如,创建表所必需的列表)。这是安德烈·皮耶罗尼(Andrea Pierleoni)上面发布的代码的改编(感谢!)

google-cloud-bigquery

现在,假设您有一个表的schema already defined in JSON。假设您有this particular "schema.json" file,然后使用上述帮助方法,则可以为Python客户端获取所需的SchemaField表示形式,如下所示:

def _get_field_schema(field):
    name = field['name']
    field_type = field.get('type', 'STRING')
    mode = field.get('mode', 'NULLABLE')
    fields = field.get('fields', [])

    if fields:
        subschema = []
        for f in fields:
            fields_res = _get_field_schema(f)
            subschema.append(fields_res)
    else:
        subschema = []

    field_schema = bigquery.SchemaField(name=name, 
        field_type=field_type,
        mode=mode,
        fields=subschema
    )
    return field_schema


def parse_bq_json_schema(schema_filename):
    schema = []
    with open(schema_filename, 'r') as infile:
        jsonschema = json.load(infile)

    for field in jsonschema:
        schema.append(_get_field_schema(field))

    return schema

现在到create a table having the above schema using the Python SDK,您可以这样做:

SchemaField

您可以选择设置基于时间的分区(如果需要),如下所示:

>>> res_schema = parse_bq_json_schema("schema.json")

>>> print(res_schema)

[SchemaField(u'event_id', u'INTEGER', u'REQUIRED', None, ()), SchemaField(u'event_name', u'STRING', u'REQUIRED', None, ()), SchemaField(u'event_types', u'STRING', u'REPEATED', None, ()), SchemaField(u'product_code', u'STRING', u'REQUIRED', None, ()), SchemaField(u'product_sub_code', u'STRING', u'REPEATED', None, ()), SchemaField(u'source', u'RECORD', u'REQUIRED', None, (SchemaField(u'internal', u'RECORD', u'NULLABLE', None, (SchemaField(u'name', u'STRING', u'REQUIRED', None, ()), SchemaField(u'timestamp', u'TIMESTAMP', u'REQUIRED', None, ()))), SchemaField(u'external', u'RECORD', u'NULLABLE', None, (SchemaField(u'name', u'STRING', u'REQUIRED', None, ()), SchemaField(u'timestamp', u'TIMESTAMP', u'REQUIRED', None, ()))))), SchemaField(u'timestamp', u'TIMESTAMP', u'REQUIRED', None, ()), SchemaField(u'user_key', u'RECORD', u'REQUIRED', None, (SchemaField(u'device_id', u'STRING', u'NULLABLE', None, ()), SchemaField(u'cookie_id', u'STRING', u'NULLABLE', None, ()), SchemaField(u'profile_id', u'STRING', u'NULLABLE', None, ()), SchemaField(u'best_id', u'STRING', u'REQUIRED', None, ()))), SchemaField(u'message_id', u'STRING', u'REQUIRED', None, ()), SchemaField(u'message_type', u'STRING', u'REQUIRED', None, ()), SchemaField(u'tracking_id', u'STRING', u'NULLABLE', None, ()), SchemaField(u'funnel_stage', u'STRING', u'NULLABLE', None, ()), SchemaField(u'location', u'RECORD', u'NULLABLE', None, (SchemaField(u'latitude', u'FLOAT', u'REQUIRED', None, ()), SchemaField(u'longitude', u'FLOAT', u'REQUIRED', None, ()), SchemaField(u'geo_region_id', u'INTEGER', u'NULLABLE', None, ()))), SchemaField(u'campaign_id', u'STRING', u'NULLABLE', None, ()), SchemaField(u'topic', u'STRING', u'REQUIRED', None, ())]

这最终创建了表:

dataset_ref = bqclient.dataset('YOUR_DATASET')
table_ref = dataset_ref.table('YOUR_TABLE')
table = bigquery.Table(table_ref, schema=res_schema)

答案 4 :(得分:0)

这是一个可以帮助您的简单程序。

import json
from apache_beam.io.gcp.internal.clients import bigquery


def bq_schema(json_schema):
    table_schema = bigquery.TableSchema()
    with open(json_schema) as json_file:
        data = json.load(json_file)
        for p in data:
            field = bigquery.TableFieldSchema()
            field.name = p['name']
            field.type = p['type']
            field.mode = p['mode']
            table_schema.fields.append(field)
    return table_schema

答案 5 :(得分:0)

现在,您可以使用内置的parse_table_schema_from_json函数:

from apache_beam.io.gcp.bigquery_tools import parse_table_schema_from_json

with open('schema.json') as f:
    schema_string = f.read()
table_schema = parse_table_schema_from_json(schema_string)