Spark:如何在列的一部分上建立半加和指标或汇总总和?

时间:2019-05-17 18:40:25

标签: java apache-spark apache-spark-sql

我正在尝试重现我在Spark中传统BI中所做的一些分析。使用的技术术语是如何建立半加性指标,但是如果我解释这意味着什么可能会有所帮助。

例如,说我有一个每天的库存量清单。昨天我有100个,今天我有50个。这是一个半累加指标,因为您没有150个。您有50个。因此,您只想对当天的总和进行汇总。但是,诸如销售额之类的东西可以完全累加,例如,您可以将全年的所有销售额相加。

所以问题是我如何使用agg和sum建立一个半加法度量?以及如何编写同时显示半加性和全加性指标的agg语句?例如:

val stocks = (Seq(
             ("2019-05-01", 1, "FB", 1058.45, 100000),
             ("2019-05-01", 1, "NVDA", 40058.45, 150000),
             ("2019-05-03", 1, "FB", 8058.45, 80000),
             ("2019-05-04", 1, "FB", 11058.45, 75000),  // Latest FB entry for account 1 
             ("2019-05-05", 1, "NVDA", 50058.45, 125000),  // Latest NVDA entry for account 1
             ("2019-05-01", 2, "FB", 1058.45, 200000),
             ("2019-05-02", 2, "NVDA", 5058.45, 125000),
             ("2019-05-03", 2, "NVDA", 5058.45, 115000),
             ("2019-05-05", 2, "FB", 1058.45, 65000),   // latest FB entry for account 2
             ("2019-05-06", 2, "NVDA", 5058.45, 105000)  // latest NVDA entry for account 2
          ).toDF("date", "symbol", "account", "sale", "current_holdings"))

 stocks
     .groupBy( stocks.col("symbol") )
     .add( sum("earnings"), sum("current_holdings") )
     .show()

这将产生什么:

+------+---------+----------------+
|symbol|sale     |current_holdings|
+------+---------+----------------+
|    FB| 34291.80|        520000.0|
|  NDVA|105292.20|        525500.0|
+------+---------+----------------+

应该产生:

+------+---------+----------------+
|symbol|sale     |current_holdings|
+------+---------+----------------+
|    FB| 34291.80|          140000|
|  NDVA|105292.20|          230000|
+------+---------+----------------+

在预期中,差异仅在current_holdings列中,该列将汇总所有帐户中的所有最新条目。因此,添加FB的最新条目即可得到:

FB = 75000 + 65000
NVDA = 125000 + 105000

我看过WindowFunctions,但是除了分区中的特定索引之外,我看不到如何指定总和的条件,如果说我需要对特定月份的所有数据进行求和,那将很困难。 Spark如何完成?

PS: 请原谅这个奇怪的例子,我必须将其改编以供公众观看。

PSS: 我也很难做到这一点,因为每个帐户/符号的最新日期都不符合可预测的边界。在我的特定情况下,我实际上是试图对仅属于给定时间段的最后一个月(年,季度等)的事物进行汇总。我希望这是一个简单的情况,但是我想充分探索半加性用例,因此使问题变得更加棘手。

1 个答案:

答案 0 :(得分:1)

PySpark解决方案,可以将其修改为等效的Scala代码。

使用row_number对每个帐户的行进行编号,按日期desc的顺序对符号进行计数,然后对每个组的first行的持有价值求和。

w=Window.partitionBy(stocks.account,stocks.symbol).orderBy(stocks.date.desc())
stocks = stocks.withColumn('rnum',row_number().over(w))
w1 = Window.partitionBy(stocks.symbol)
stocks = stocks.withColumn('sales',sum(stocks.sale).over(w1)).withColumn('holdings',sum(when(stocks.rnum==1,stocks.current_holdings).otherwise(0)).over(w1))
#Final selection
stocks.select(stocks.symbol,stocks.sales,stocks.holdings).distinct().show()