【问题标题】:Google Dataflow: running dynamic query with BigQuery+Pub/Sub in PythonGoogle Dataflow:在 Python 中使用 BigQuery+Pub/Sub 运行动态查询
【发布时间】:2019-04-22 19:27:47
【问题描述】:

我想在管道中做什么:

  1. 从 pub/sub 读取(完成)
  2. 将此数据转换为字典(完成)
  3. 从字典中获取指定键的值(完成)
  4. 从 BigQuery 运行参数化/动态查询,其中 where 部分应如下所示:

    SELECT field1 FROM Table where field2 = @valueFromP/S
    

管道

| 'Read from PubSub' >> beam.io.ReadFromPubSub(subscription='')
| 'String to dictionary' >> beam.Map(lambda s:data_ingestion.parse_method(s))
| 'BigQuery' >> <Here is where I'm not sure how to do it>

从 BQ 读取的正常方式是:

| 'Read' >> beam.io.Read(beam.io.BigQuerySource(
                query="SELECT field1 FROM table where field2='string'", use_standard_sql=True))

我已阅读有关参数化 queries 的信息,但我不确定这是否适用于 apache beam。

可以使用侧面输入来完成吗?

最好的方法是什么?


我尝试过的:

def parse_methodBQ(input):
    query=''SELECT field1 FROM table WHERE field1=\'%s\' AND field2=True' % (input['field1'])'
    return query


class ReadFromBigQuery(beam.PTransform):
    def expand(self, pcoll):
        return (
                pcoll
                | 'FormatQuery' >> beam.Map(parse_methodBQ)
                | 'Read' >> beam.Map(lambda s:  beam.io.Read(beam.io.BigQuerySource(query=s)))
        )

with beam.Pipeline(options=pipeline_options) as p:
transform = (p  | 'BQ' >> ReadFromBigQuery()

结果(为什么会这样?):

<Read(PTransform) label=[Read]>

正确的结果应该是这样的:

{u'Field1': u'string', u'Field2': Bool}

解决方案

正在筹备中:

| 'BQ' >> beam.Map(parse_method_BQ))

函数(使用 BigQuery 0.25 API 进行数据流)

def parse_method_BQ(input):
    client = bigquery.Client()
    QUERY = 'SELECT field1 FROM table WHERE field1=\'%s\' AND field2=True' % (input['field1'])
    client.use_legacy_sql = False
    query_job = client.run_async_query(query=QUERY ,job_name='temp-query-job_{}'.format(uuid.uuid4()))  # API request
    query_job.begin()
    while True:
        query_job.reload()  # Refreshes the state via a GET request.
        if query_job.state == 'DONE':
            if query_job.error_result:
                raise RuntimeError(query_job.errors)
            rows = query_job.results().fetch_data()
            for row in rows:
                if not (row[0] is None):  
                    return input
        time.sleep(1)

【问题讨论】:

    标签: python google-bigquery google-cloud-dataflow apache-beam google-cloud-pubsub


    【解决方案1】:

    您可以read the whole table 或使用string query

    我了解您将根据需要使用 parse_methodBQ 方法来自定义查询。由于此方法返回查询,您可以使用 BigQuerySource 调用它。这些行在字典中。

    | 'QueryTable' >> beam.Map(beam.io.BigQuerySource(parse_methodBQ))
    # Each row is a dictionary where the keys are the BigQuery columns
    | 'Read' >> beam.Map(lambda s:  s['data'])
    

    此外,您可以避免自定义查询并使用filter method

    关于侧面输入,请查看食谱中的 this 示例,以更好地了解如何使用它们。

    【讨论】:

    • 感谢您的回答。我是使用 beam.Map 完成的,所以它应该像您提出的解决方案一样。我会将解决方案添加到主帖中。
    • 哪个更能提高性能:使用 filter data 还是像我一样使用 parse_method?
    • 根据您的用例,如果您要使用多个自定义查询,最好让所有表都使用过滤器,但如果您只对所有表进行一些自定义查询可能没用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-09
    • 2022-01-01
    • 2018-08-24
    • 2019-06-05
    • 2020-06-22
    • 2019-07-23
    • 1970-01-01
    相关资源
    最近更新 更多