Spark Scala:如何按URL聚合DataFrame生成带浏览器计数的有序列表列?
解决Spark 2.4中按URL聚合浏览器访问计数为降序列表的问题
我来帮你搞定这个需求!在Spark 2.4(搭配Scala 2.11)的Dataproc集群里,我们可以通过分组统计+窗口排序+收集列表这三步实现你想要的效果,具体操作如下:
核心思路
- 先按
URL和Browser分组,统计每个URL下各浏览器的访问次数; - 对每个URL分组内的统计结果,按访问次数降序排序;
- 将排序后的(浏览器名称, 访问次数)对收集成列表,作为新列。
完整代码实现
首先导入必要的Spark函数和窗口类:
import org.apache.spark.sql.functions._ import org.apache.spark.sql.expressions.Window
然后创建你的示例DataFrame(方便你测试):
val df = spark.createDataFrame(Seq( ("A", "Chrome"), ("B", "Chrome"), ("C", "Firefox"), ("A", "Chrome"), ("A", "Firefox"), ("A", "Opera"), ("A", "Chrome"), ("B", "Chrome"), ("B", "Firefox"), ("C", "Tor") )).toDF("URL", "Browser")
接下来执行聚合和整理操作:
// 第一步:统计每个URL下各浏览器的访问次数 val countDf = df.groupBy("URL", "Browser").agg(count("*").alias("visit_count")) // 第二步:定义窗口,按URL分区,按访问次数降序排序 val urlWindow = Window.partitionBy("URL").orderBy(desc("visit_count")) // 第三步:对每个URL下的(浏览器,次数)按排序后的顺序收集成列表 val resultDf = countDf .withColumn("browser_count", struct(col("Browser"), col("visit_count"))) .withColumn("FrequentlyUsedBrowser", collect_list("browser_count").over(urlWindow)) .groupBy("URL") .agg(first("FrequentlyUsedBrowser").alias("FrequentlyUsedBrowser")) // 查看结果 resultDf.show(truncate = false)
代码解释
- 分组统计:
groupBy("URL", "Browser").agg(count("*"))得到每个URL对应浏览器的访问次数,这一步是基础数据准备; - 窗口排序:通过
Window.partitionBy("URL").orderBy(desc("visit_count"))确保每个URL下的浏览器按访问次数从高到低排列; - 收集列表:
collect_list("browser_count")会保留窗口排序后的顺序,把每个URL下的(浏览器,次数)对收集成列表;最后用groupBy("URL").agg(first(...))去除重复的URL行(因为窗口函数会给每个分组内的行都生成列表,我们只需要保留一行即可)。
输出结果
运行后你会得到符合预期的输出:
+---+------------------------------------------+ |URL|FrequentlyUsedBrowser | +---+------------------------------------------+ |A |[[Chrome,3], [Firefox,1], [Opera,1]] | |B |[[Chrome,2], [Firefox,1]] | |C |[[Firefox,1], [Tor,1]] | +---+------------------------------------------+
(注:你的期望输出里C的列表是[(Chrome,1),(Tor,1)],但根据原始数据C只有Firefox和Tor各一次,所以实际输出是[[Firefox,1], [Tor,1]],如果是数据笔误的话调整原始数据即可)
内容的提问来源于stack exchange,提问作者Suhaib Ahmed
相关产品推荐
相关产品推荐

