处理Google Cloud Dataflow中BigQuery的tableSchema中的缺失字段和新字段

时间:2018-02-20 04:56:49

标签: google-cloud-platform google-bigquery google-cloud-functions google-cloud-dataflow apache-beam

情况如下:

我的 BigQuery TableSchema 如下:

  {
    "name": "Id",
    "type": "INTEGER",
    "mode": "nullable"
  },
  {
    "name": "Address",
    "type": "RECORD",
    "mode": "repeated",
    "fields":[
      {
        "name": "Street",
        "type": "STRING",
        "mode": "nullable"
      },
      {
        "name": "City",
        "type": "STRING",
        "mode": "nullable"
      }
     ]
   }

我正在从Google云端存储存储桶中读取数据,并使用云端功能写入BigQuery。

我已将云功能中的TableSchema定义为

table_schema = bigquery.TableSchema()

Id_schema = bigquery.TableFieldSchema()
Id_schema.name = 'Id'
Id_schema.type = 'INTEGER'
Id_schema.mode = 'nullable'
table_schema.fields.append(Id_schema)

Address_schema = bigquery.TableFieldSchema()
Address_schema.name = 'Address'
Address_schema.type = 'RECORD'
Address_schema.mode = 'repeated'

Street_schema = bigquery.TableFieldSchema()
Street_schema.name = 'Street'
Street_schema.type = 'STRING'
Street_schema.mode = 'nullable'
Address_schema.fields.append(Street_schema)
table_schema.fields.append(Address_schema)

City_schema = bigquery.TableFieldSchema()
City_schema.name = 'City'
City_schema.type = 'STRING'
City_schema.mode = 'nullable'
Address_schema.fields.append(City_schema)
table_schema.fields.append(Address_schema)

我的数据文件如下所示:(每行都是json)

{"Id": 1, "Address": {"Street":"MG Road","City":"Pune"}}
{"Id": 2, "Address": {"City":"Mumbai"}}
{"Id": 3, "Address": {"Street":"XYZ Road"}}
{"Id": 4}
{"Id": 5, "PhoneNumber": 12345678, "Address": {"Street":"ABCD Road", "City":"Bangalore"}}

问题: 当传入数据有一些丢失的密钥时,我该如何处理? 例如,

  • 数据"Street"的第2行缺失
  • 缺少数据"City"的第3行
  • 缺少数据"Address"的第4行
  • 数据"PhoneNumber"的第5行显示..

问题1 :如果丢失数据(例如,第2行,第3行,第4行),如何处理WriteToBigQuery

问题2 :如果新数据显示在数据中,如何处理? 例如,

  • 在第5行"PhoneNumber"出现.. 如何在运行中在BigQuery表中添加新列? (为了适应这些新添加的字段,我是否必须首先详尽地定义BigQuery表模式?)

问题3 :如何遍历传入数据文件的每一行(同时读取数据文件)并确定要解析的字段?

2 个答案:

答案 0 :(得分:2)

对您而言,其中一个选项是 - 我建议您只使用类型为line的一个字段string将数据写入表中,而不是使用架构更改,并在运行期间应用架构逻辑查询

下面的示例是关于如何在一个字段中对整个行应用模式的BigQuery Standard SQL

     
#standardSQL
WITH t AS (
  SELECT '{"Id": 1, "Address": {"Street":"MG Road","City":"Pune"}}' line UNION ALL
  SELECT '{"Id": 2, "Address": {"City":"Mumbai"}}' UNION ALL
  SELECT '{"Id": 3, "Address": {"Street":"XYZ Road"}}' UNION ALL
  SELECT '{"Id": 4}  ' UNION ALL
  SELECT '{"Id": 5, "PhoneNumber": 12345678, "Address": {"Street":"ABCD Road", "City":"Bangalore"}}' 
)
SELECT
  JSON_EXTRACT_SCALAR(line, '$.Id') id,
  JSON_EXTRACT_SCALAR(line, '$.PhoneNumber') PhoneNumber,
  JSON_EXTRACT_SCALAR(line, '$[Address].Street') Street,
  JSON_EXTRACT_SCALAR(line, '$[Address].City') City 
FROM t  

结果如下

Row id  PhoneNumber Street      City     
1   1   null        MG Road     Pune     
2   2   null        null        Mumbai   
3   3   null        XYZ Road    null     
4   4   null        null        null     
5   5   12345678    ABCD Road   Bangalore      

我认为这种方法可以回答/解决您的所有四个问题

答案 1 :(得分:1)

  

问题:如何在传入数据缺少某些键时进行处理?

     

问题1 :如果缺少数据(例如,第2行,第3行,第4行),如何处理WriteToBigQuery

     

问题2 :如果新数据显示在数据中,如何处理?

我建议将JSON字符串解码为某些数据结构,例如自定义from setuptools import setup, find_packages with open('requirements.txt') as f: requirements = f.read().splitlines() __version__ = "0.0.2" setup( version=__version__ name = "mymodules", packages = find_packages(exclude=['tests', '*.tests', '*.tests.*']), install_requires=requirements, ) 类,您可以在其中访问和操作成员变量,并定义哪些成员是可选的以及哪些是必需的。使用自定义类为您提供抽象级别,以便管道中的下游转换不需要担心如何操作JSON。可以实现下游转换以从Contact对象构建TableRow并且还遵循BigQuery表模式。此设计遵循一般抽象和关注点分离原则,并能够处理丢失或其他字段的所有场景。

  

问题3 :如何遍历传入数据文件的每一行(同时读取数据文件)并确定要解析的字段?

Dataflow执行管道会自动执行此操作。如果管道从Google云端存储中读取(例如,使用Contact),则数据流将处理文件的每一行作为单个元素(单个JSON字符串)。确定要解析的字段是业务逻辑的详细信息,可以在解析JSON字符串的转换中定义。