Spark 爬坑记录之percent_rank()【2017存档】

博客讲述了在KMeans聚类前,数据预处理过程中使用percent_rank()操作代替自定义方法,显著提升了Spark计算的效率。通过创建DataFrame,注册临时表并运用Spark SQL的窗口函数percent_rank(),实现了对数据集的优化处理,展示了Spark SQL在大数据处理中的优化能力。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Kmeans 预处理之前的数据预处理部分,需要做一次类似percent_rank() 操作。
举个例子,输入一条记录为user_1,key1,value_1
输入多条记录
按照key1 聚合之后,结果为key1,list[value1,value2…]
将list 排序,并获取count 结果为 key1,count,list
然后计算user1 这条记录的rank = index(value1)/count

    val ah_freqlist_dic_old = user_ah_freq_dic.map(x=>(x._1._2,Nil:+x._2))
      .reduceByKey(_:::_)
      .map(x=>(x._1,(x._2.length).toString +: x._2.sorted))
      .collectAsMap()
val ah_freqlist_dic = sc.broadcast(ah_freqlist_dic_old)
val user_ah_percent_dic = user_ah_freq_dic.map(t=>((t._1._1,t._1._2),ah_freqlist_dic.value.getOrElse(t._1._2,Nil).indexOf(t._2)/((ah_freqlist_dic.value.getOrElse(t._1._2,Nil)(0).toInt).toFloat)))

然后效率极低。

当把这段代码换成 percent_rank() 之后,奇迹发生了

 val df = sqlContext.createDataFrame(user_ah_freq_dic).toDF("user","ah","freq")
    df.registerTempTable("uahf")
    val sql="select user,ah,percent_rank() over (partition by ah order by freq) as rank from uahf"

    val user_ah_percent_dic = sqlContext.sql(sql).rdd.map(x=>((x(0).toString,x(1).toString),x(2).toString.toFloat))

果然spark sql 的是做了优化的。阅读spark sql 的源码,又有计划了

### PERCENT_RANK 函数的定义与用途 `PERCENT_RANK` 是一种窗口函数,用于计算数据集中某一行在其分区中的相对排名。它返回的是当前行相对于整个分区内其他行的位置百分比[^4]。该函数的结果范围是从 `0` 到 `1`,其中第一个值始终为 `0`。 #### 计算逻辑 `PERCENT_RANK` 的具体计算方式如下: \[ \text{PERCENT_RANK} = \frac{\text{(rank of current row - 1)}}{\text{(total number of rows in partition - 1)}} \] 这意味着如果某个分区只有一行,则其 `PERCENT_RANK` 值恒等于 `0`。 --- ### 使用示例 假设有一个学生分数表 (`student_marks`),结构如下: | StudentID | Marks | |-----------|-------| | 1 | 78 | | 2 | 92 | | 3 | 85 | | 4 | 60 | 可以使用以下查询来展示每名学生的成绩以及它们在整个集合中的百分位排名: ```sql WITH cte AS ( SELECT StudentID, Marks, PERCENT_RANK() OVER (ORDER BY Marks ASC) AS PercentRank FROM student_marks ) SELECT * FROM cte; ``` 执行上述语句后,结果可能类似于下表所示: | StudentID | Marks | PercentRank | |-----------|-------|-------------| | 4 | 60 | 0 | | 1 | 78 | 0.333 | | 3 | 85 | 0.666 | | 2 | 92 | 1 | 此结果显示了每位学生的成绩及其对应的百分位排名。 --- ### 数据分区的应用 当需要按某些字段进行分组并分别计算每个子集内的 `PERCENT_RANK` 时,可以通过指定 `PARTITION BY` 子句实现。例如,在不同班级的学生之间独立计算百分位排名: ```sql WITH class_marks AS ( SELECT ClassID, StudentID, Marks, PERCENT_RANK() OVER (PARTITION BY ClassID ORDER BY Marks DESC) AS PercentRank FROM student_class_marks ) SELECT * FROM class_marks; ``` 在此例子中,`ClassID` 被用来划分不同的分组,而每一组内部按照 `Marks` 字段降序排列,并计算相应的百分位排名。 --- ### 性能优化建议 对于大规模数据集,应考虑索引设计以加速排序操作。此外,合理利用公共表达式(CTE)或者临时表存储中间结果能够减少重复计算开销。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值