根据数据的两个不同子集对两个聚合进行不同的计数,分组依据为

时间:2019-04-02 12:14:56

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

考虑我有Dataset<Row>这样的人

Day User    isInstall   isPlayed
1   U1      1           1
1   U2      1           0
1   U3      0           1
1   U4      1           0
1   U4      1           1
2   U6      1           1
2   U7      1           0
2   U8      0           1
2   U8      0           1
2   U7      1           0

我想对Day字段进行分组,并以isInstall为1&isPlayed为1来获得唯一身份用户的数量。结果应该是这样的:

Day    isInstallUU    isPlayedUU
1      3              3
2      2              2

我能够像这样为isInstall和isPlayed计数获取不同的数据集,但是我很困惑如何合并它们并获得一个数据集。

Dataset<Row> result1 = responseDataset.filter(col("isInstall").equalTo(1))
    .groupBy("Day").agg(countDistinct("User").alias("isInstallUU"));

Dataset<Row> result2 = responseDataset.filter(col("isPlayed").equalTo(1))
    .groupBy("Day").agg(countDistinct("User").alias("isPlayedUU"));

如何使用Java Spark API实现此目标?

2 个答案:

答案 0 :(得分:0)

首先,根据作者提供的条件过滤数据框。然后,使用分组依据按“天”列进行汇总,并附加两个新列,分别代表用户的不同计数。 检查以下代码:

    responseDataset.filter(col("isInstall").equalTo(1) && col("isPlayed").equalTo(1))
    .groupBy("Day")
    .agg(countDistinct("User").as("isInstallUU"), countDistinct("User").as("isPlayedUU"));

答案 1 :(得分:0)

一枪做起来有些棘手(但可以做一些工作),因为您正在计算数据的两个不同子集上的聚合。

最简单的方法是计算两个聚合(按照您的尝试)并将其合并:

Dataset<Row> result1 = responseDataset
    .filter(col("isInstall").equalTo(1))
    .groupBy("Day")
    .agg(countDistinct("User").alias("isInstallUU"));

Dataset<Row> result2 = responseDataset
    .filter(col("isPlayed").equalTo(1))
    .groupBy("Day")
    .agg(countDistinct("User").alias("isPlayedUU"));

Dataset<Row> result = result1
    .join(result2, result1.col("Day").equalTo(result1.col("Day")), "full_outer")
    .na().fill(0);

请注意,我使用完全外部联接,因为可能有一些用户未出现在两个子集中。为了避免空值,我将其替换为0。

编辑

如果您好奇的话,有一种方法可以分阶段进行。我们的想法是创建两个其他用户列,当我们不想聚合它们时它们为空(spark忽略countDistinct中的空值)。看起来像这样:

Dataset<Row> result = responseDataset
    .withColumn("userI", when(col("isInstall").equalTo(1), col("user")))
    .withColumn("userP", when(col("isPlayed").equalTo(1), col("user")))
    .groupBy("day")
    .agg(countDistinct(col("userP")).alias("isPlayedUU"),
         countDistinct(col("userI")).alias("isInstallUU"));