如何使用Apache Beam计算运行总计

时间:2017-12-20 20:01:38

标签: google-cloud-dataflow

使用Apache Beam SDK for Google Dataflow我想从一组交易中计算每日余额。

示例数据集可能如下所示,其中包含收款人姓名,交易日期和金额:

<localRepository>D:/repository</localRepository>

mvn -v
Apache Maven 3.5.0 (ff8f5e7444045639af65f6095c62210b5713f426; 2017-04-03T21:39:06+02:00)
Maven home: D:\Envirement\apache-maven-3.5.0-bin\apache-maven-3.5.0\bin\..
Java version: 1.8.0_144, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jre1.8.0_144
Default locale: fr_FR, platform encoding: Cp1252
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"

所需的结果集如下所示:

John, 2017-12-01, 100
John, 2017-12-01, 200
Jane, 2017-12-01, 150
John, 2017-12-02, -100
John, 2017-12-02, 300

我尝试使用John, 2017-12-01, 300 (100 + 200) Jane, 2017-12-01, 150 John, 2017-12-02, 500 (300 + -100 + 300) KV<Pair, BigDecimal>函数来计算Combine.perKey的总和,但不计算前一天的总数。结束余额作为第二天的起始余额。

1 个答案:

答案 0 :(得分:1)

Beam的窗口API在这里使用是正确的:

https://beam.apache.org/documentation/programming-guide/#windowing

具体来说,您必须回答以下问题:

  1. 您希望在哪些情况下执行汇总?
  2. 处理时间你想要答案吗?
  3. 您的帖子中没有足够的信息来回答这些问题 - 您必须提供更多细节 - 您是在批处理还是流式传输模式下运行?您是否希望在每天结束时得到一个答案,或者您是否希望每次有新的交易时都会更新运行总计?或介于两者之间?如果我不得不猜测,听起来你想要保持全局总数(全局事件时间窗口),并且每天更新一次当前值。

    在我们回答了上述问题之后,我们可以编写一些伪代码:

    PCollection<KV<String, Double>> transactionsByName = .... ;     // Read input
    
    PCollection<KV<String, Double> dailyTotalsByName = transactionsByName
      // Group by name
      .apply(GroupByKey.<String, Double>create())   
      // 1-day windows       
      .apply(Window.<KV<String, Iterable<Double>>>into(    
          FixedWindows.of(Duration.standardDays(1))))    
      // Combine each window (see combiners guide [here][1])  
      .apply(Combine.<String, Iterable<Double>, Double>perKey(new SumTotals())); 
    
    PCollection<KV<String, Double> globalTotalsByName = dailyTotalsByName
      // Global windows allow you to combine a running total. Triggering condition
      // specifies 'when' in processing time the answers are materialized. Here we
      // have chosen to output the answer each time a new daily total arrives.
      .apply(Window.<KV<String, Iterable<Double>>>into(new GlobalWindows()))
         .triggering(Repeatedly.forever(AfterPane.elementCountAtLeast(1))))
      // Combine daily totals
      .apply(Combine.<String, Iterable<Double>, Double>perKey(new SumTotals()))
    

    上述代码可能无法完全按原样构建,但概述了至少一种合理的方法。当然,根据输入和问题的具体情况,您可能需要调整触发的频率等。如上所述,这只会在每天结束时给出结果。如果您想要实时运行总计,可以使用更复杂的触发条件来输出当前值。