【问题标题】:Reducing PCollection after GroupByKey在 GroupByKey 之后减少 PCollection
【发布时间】:2019-08-24 10:50:39
【问题描述】:

我正在尝试根据交易数据生成简单的客户摘要。例如,给定目标交易类型,发生了多少交易,总金额是多少?

原始输入示例:

custid  desc        amount
111     coffee      3.50
111     grocery     23.00
333     coffee      4.00
222     gas station 32.00
222     gas station 55.50
333     coffee      3.00

所需输出示例:

custid nbr_coffee amt_coffee nbr_gas_station amt_gas_station
111    1          3.50       0               0.00
222    0          0          2               87.50
333    2          7.00       0               0

我的目标跑步者将是 Dataflow(但目前使用 DirectRunner 进行测试)。

这是我所拥有的代码 sn-p:

def categorize_coffee(transaction):

    if transaction['trx_desc'] == 'coffee':
        transaction['coffee'] = True
    else:
        transaction['coffee'] = False

    return transaction

def categorize_gas_station(transaction):

    if transaction['trx_desc'] == 'gas station':
        transaction['gas_station'] = True
    else:
        transaction['gas_station'] = False

    return transaction

def summarize_coffee(grouping):

    key, values = grouping
    values = list(values)

    nbr = 0
    amt = 0

    for d in values:
        if d['coffee'] == True:
            nbr+=1
            amt+=d['amount']

    ret_val = {}
    ret_val['cust'] = d['cust']
    ret_val['nbr_coffee'] = nbr
    ret_val['amt_coffee'] = amt

    return ret_val

def summarize_gas_station(grouping):

    key, values = grouping
    values = list(values)

    nbr = 0
    amt = 0

    for d in values:
        if d['gas_station'] == True:
            nbr += 1
            amt += d['amount']

    ret_val = {}
    ret_val['cust'] = d['cust']
    ret_val['nbr_gas_station'] = nbr
    ret_val['amt_gas_station'] = amt

    return ret_val

def create_dict(row):

    vars = row.split(',')
    return {'cust': vars[0], 'trx_desc': str(vars[1]), 'amount': float(vars[2])}

with beam.Pipeline(options=pipeline_options) as p:

    categorized_trx = (
        p | 'get data' >> beam.io.ReadFromText('./test.csv')
        | beam.Map(create_dict)
        | beam.Map(categorize_coffee)
        | beam.Map(categorize_gas_station)
        | beam.Map(lambda trx: (trx['cust'], trx))
        | beam.GroupByKey()
    )

    coffee_trx = (categorized_trx | beam.Map(summarize_coffee))

    gas_station_trx = (categorized_trx | beam.Map(summarize_gas_station))

    result = (coffee_trx, gas_station_trx) | beam.Flatten()

现在的实际结果是:

{'amt_coffee': 7.0, 'cust': u'333', 'nbr_coffee': 2}
{'amt_coffee': 0, 'cust': u'222', 'nbr_coffee': 0}
{'amt_coffee': 3.5, 'cust': u'111', 'nbr_coffee': 1}
{'nbr_gas_station': 0, 'cust': u'333', 'amt_gas_station': 0}
{'nbr_gas_station': 2, 'cust': u'222', 'amt_gas_station': 87.5}
{'nbr_gas_station': 0, 'cust': u'111', 'amt_gas_station': 0}

没有像我预期的那样变平或加入。我是 Beam 新手 - 不确定我是否理解如何正确解决这个问题,所以希望能得到一些见解。

【问题讨论】:

  • 虽然有不同的问题,但这里围绕组合器的答案应该会有所帮助:stackoverflow.com/questions/55445851/…
  • @RezaRokni 这个问题让我看到如果它们被键入为('nbr_coffee',1),我如何组合值。但是在我的情况下,我有('333',('nbr_coffee',1))。我将如何组合每个客户的每个密钥?此外,我将有多个组合器,因为有时我需要计数,而有时我需要数量 - 这会导致我回到组合两个集合的问题吗?
  • Flatten 只会将所有结果合并到一个 PCollection 中。要加入他们,您可以使用 CoGroupByKey 和 cust 作为密钥 beam.apache.org/documentation/programming-guide/…

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


【解决方案1】:

这应该可行:

...

def summarize_coffee(grouping):

    ...

    return (d['cust'], ret_val)


def summarize_gas_station(grouping):

    ...

    return (d['cust'], ret_val)

...

def processJoin(row):
    (customer, data) = row
    coffee_trx=data['coffee_trx']
    gas_station_trx=data['gas_station_trx']
    return (customer, coffee_trx, gas_station_trx)

result = ({coffee_trx: coffee_trx, gas_station_trx: gas_station_trx}
         | 'Group' >> beam.CoGroupByKey()    
         | 'Reshape' >> beam.Map(processJoin)
         | 'Unwind' >> beam.FlatMap(lambda x: x)
         )

【讨论】:

    【解决方案2】:

    Beam 提供Combine 转换,应该允许您组合 PCollection 的元素。看起来对于您的用例,您可以使用 Combine.perKey() 根据键组合 PCollection 的键控元素。作为 combine 函数,你既可以提供一个函数,也可以实现CombineFn

    【讨论】:

    • 您能否提供一个使用 combine 的具体示例来帮助我?上面的评论中推荐了组合器,但我看不出它如何用于实现我想要的输出。
    猜你喜欢
    • 2018-03-09
    • 1970-01-01
    • 2019-02-12
    • 1970-01-01
    • 2021-07-09
    • 1970-01-01
    • 2021-11-22
    • 2020-08-17
    • 2016-06-28
    相关资源
    最近更新 更多