如何使用Scala与我的比较器对DataFrame进行排序?

时间:2019-03-12 18:15:27

标签: scala sorting apache-spark apache-spark-sql

我想用自己的比较器根据一列对DataFrame进行排序。可以在Spark SQL中执行此操作吗?

例如,假设我有一个注册为表“ MyTable”的数据框,其列为“天”,其类型为“字符串”:

id  | Day  
--------------------
1   | Fri           
2   | Mon           
3   | Sat           
4   | Sun           
5   | Thu           

我想执行此查询:

SELECT * FROM MyTable ORDER BY Day

我想用自己的比较器订购“日”列。我曾考虑过使用UDF,但不知道是否可行。请注意,我真的想在“排序/排序依据”操作中使用我的比较器。我不想将String从Day列转换为Datetime或类似的内容。

2 个答案:

答案 0 :(得分:3)

在SparkSQL中,您别无选择,需要对一个或多个列使用orderBy。对于RDD,如果愿意,可以使用类似Java的自定义比较器。实际上,这是sortBycf the scaladoc of Spark 2.4)的RDD方法的签名:

def sortBy[K](f: (T) ⇒ K, ascending: Boolean = true, numPartitions: Int = this.partitions.length)
    (implicit ord: Ordering[K], ctag: ClassTag[K]): RDD[T] 

这意味着您可以提供自己选择的Ordering,就像Java ComparatorOrdering实际上是从Comparator继承来的)一样。

为简单起见,假设我要按列“ x”的绝对值进行排序(这可以在没有比较器的情况下完成,但假设我需要使用比较器)。我首先在行上定义比较器:

class RowOrdering extends Ordering[Row] {
    def compare(x : Row, y : Row): Int = x.getAs[Int]("x").abs - y.getAs[Int]("x").abs
}

现在让我们定义数据并对其进行排序:

val df = Seq( (0, 1),(1, 2),(2, 4),(3, 7),(4, 1),(5, -1),(6, -2),
    (7, 5),(8, 5), (9, 0), (10, -9)).toDF("id", "x")
val rdd = df.rdd.sortBy(identity)(new RowOrdering(), scala.reflect.classTag[Row])
val sorted_df = spark.createDataFrame(rdd, df.schema)
sorted_df.show
+---+---+
| id|  x|
+---+---+
|  9|  0|
|  0|  1|
|  4|  1|
|  5| -1|
|  6| -2|
|  1|  2|
|  2|  4|
|  7|  5|
|  8|  5|
|  3|  7|
| 10| -9|
+---+---+

另一种解决方案是定义隐式排序,这样您在排序时就不需要提供它。

implicit val ord = new RowOrdering()
df.rdd.sortBy(identity)

最后,请注意df.rdd.sortBy(_.getAs[Int]("x").abs)将获得相同的结果。另外,您可以使用元组排序来执行更复杂的操作,例如按绝对值排序,如果相等,则将正值放在第一位:

df.rdd.sortBy(x => (x.getAs[Int]("x").abs, - x.getAs[Int]("x"))) //RDD
df.orderBy(abs($"x"), - $"x") //dataframe

答案 1 :(得分:2)

这是处理数据框的通用方法

/**/
$id = $_GET["id"]; //SANITIZE INPUT!!!!!!
$sql1 = "SELECT username, address, country, zipcode, photo, bio FROM user WHERE id = '$id'";
        $result = $conn->query($sql1);
        if($result->num_rows > 0)
        {
            while($row = $result->fetch_assoc())
            {
                echo "<div id = 'account'>";
                    echo "<span id = 'image'><a id = 'accounts' href = 'accounts.php'><img src = '".$row['photo']."' alt = 'profile photo' width = '100px' height = '100px' style = 'margin-right:40px; margin-top: 5px;'></span>";
                    echo "<div id = 'username'><big><b style='text-transform:lowercase;'>".$row['username']."</big></a></b><br><small><i><q>".$row['bio']."</q></i></small><br>Lives in <b style='text-transform: capitalize;'>".$row['address']."</b><br>From <b>".$row['country']."</b></div><button id = 'addFriend' type = 'button' onclick = 'addFriends()'>Add friend</button>";
                echo "</div>";
            }
        }
/**/

orderby docs


如果您的 数据较少(似乎仅具有星期名称) ,则可以作为列表收集并使用scala sortWith函数

  

val df = spark.sql("SELECT * FROM MyTable") df.orderby("yourcolumn") 函数根据比较结果对该序列进行排序   功能。它需要一个比较器功能并根据它进行排序。   可以提供您自己的自定义比较功能。

与您的示例不同:

sortWith

其他选项是: How to sort an RDD in Scala Spark? 为了使用此选项,您需要将数据帧转换为PairedRDD,然后使用此处给出的答案进行sortbykey。