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