【问题标题】:Computing rank of a row with multiple columns - scala计算具有多列的行的等级 - scala
【发布时间】:2015-12-19 07:08:10
【问题描述】:

我想根据金额字段对一组列进行排名。对于组合字段(Nbr,TypeCd)的相同值,rank应该相同。这需要在 scala 中,spark 和 scala 版本分别为 1.3 和 2.10。需要的代码是scala中需要的。

示例输入数据:

Id  Nbr    TypeCd   Amt
a1  2010    online  25
a2  2010    online  25
a3  2010    online  15
a4  2011    store   100
a5  2011    store   50
a4  2011    store   90
a6  2011    store   90
a7  2011    store   90

样本输出数据

Id      Nbr    TypeCd   Amt Rank
a1  2010       online   25  1
a2  2010       online   25  1
a3  2010       online   15  3
a4  2011       store    100 1
a5  2011       store    50  5
a4  2011       store    90  2
a6  2011       store    90  2
a7  2011       store    90  2

【问题讨论】:

  • 你能详细描述一下排序的标准吗?我可以在示例中看到 a1 和 a4 具有不同的 Nbr 和 TypeCd 仍然具有相同的等级。您想计算 Nbr 和 TypeCd 子组中的排名吗?
  • 如果不转换为 RDD,在 1.3 中是无法实现的。
  • 感谢 zero323 的回复。我可以转换为 RDD。我查看了stackoverflow.com/questions/33729787/computing-rank-of-a-row/…,这是基于一个字段的,我需要使用多个字段,例如本例中的 Nbr 和 TypeCd。非常感谢您的帮助。
  • 老实说,升级到 >= 1.4 会更有意义。基于 RDD 的代码不能很好地概括,我为链接问题提供的代码是解决不同的问题(缺少PARTITION BY clause)。
  • 在 1.5 中,有窗口函数,但在 1.3 中,我不能使用它们。这就是我尝试使用 RDD 实现的目标。

标签: scala apache-spark


【解决方案1】:

这不是最佳答案,但考虑到您的限制,我会这样做:

// Group by Nbr & TypeCd
val groupedData = input.map(x => ((x._2, x._3), x)).groupByKey().map(x => x._2.toList)

// Within each subgroup sort based on the Amount in descending order
val sortedSubGroups = groupedData.map(x => x.sortWith(_._4 > _._4))

// Now assign ranks in each subgroups
val rankAssignedList = sortedSubGroups.map(x => assignRank(x)).flatMap(x => x)

其中assignRank,只是遍历子组中所有元素的列表,并按如下方式分配排名:

def assignRank(inputList : List[(String, Int, String, Int)]) : List[(String, Int, String, Int, Int)] = 
{
    var rank = 1;
    var prevAmt = 0;
    var elementPosition = 1;
    var outputList = List[(String, Int, String, Int, Int)]();
    for(element <-  inputList)
    {
        // Check if the Current Amount is lesser than Previous one
        if(element._4 != prevAmt)
        {
            rank = elementPosition
        }

        outputList = outputList ::: List((element._1, element._2, element._3, element._4 , rank))
        prevAmt = element._4
        elementPosition = elementPosition + 1
    }

    return outputList
}

【讨论】:

  • 看起来很接近,但排名计算逻辑看起来不对。您不能盲目地增加(否则 zipWithIndex 会起作用)每个元素的排名。
  • 是的,排名逻辑看起来不正确,我们无法增加每一行的排名。我们需要比较 amt 字段,如果相同,则排名将相同,对于下一个 amt,排名将发生变化。
  • 如果我可以通过添加多个列进行分区和排序来使用以下解决方案,那么这解决了我的问题。 stackoverflow.com/questions/33729787/computing-rank-of-a-row/…
  • 我明白了,我错过了您希望具有相似数量的元素具有相同排名的部分。这只是意味着通过与以前的排名进行比较来更改 assignRank 方法。我认为这应该是一个小小的改变
  • 我是 spark 和 scala 的新手,如果您能提供更新后的代码 sn-p,那将非常有帮助...非常感谢..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-27
  • 1970-01-01
  • 2021-08-20
相关资源
最近更新 更多