Как отсортировать DataFrame с моим компаратором с помощью Scala? - PullRequest
4 голосов
/ 12 марта 2019

Я хотел бы отсортировать DataFrame на основе столбца с моим собственным компаратором.Это можно сделать в Spark SQL?

Например, предположим, что у меня есть DataFrame, зарегистрированный как таблица «MyTable» со столбцом «Day», тип которого «string»:

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

И я хочу выполнить этот запрос:

SELECT * FROM MyTable ORDER BY Day

Я бы хотел заказать столбец «День» с моим собственным компаратором.Я думал об использовании UDF, но я не знаю, возможно ли это.Обратите внимание, что я действительно хочу использовать мой компаратор в операциях Sort / Order By.Я не хочу конвертировать строку из столбца Day в Datetime или что-то подобное.

Ответы [ 2 ]

3 голосов
/ 13 марта 2019

В SparkSQL у вас нет выбора и вам необходимо использовать orderBy с одним или несколькими столбцами.С RDD вы можете использовать собственный java-подобный компаратор, если хотите.На самом деле, вот подпись sortBy метода RDD ( cf скаладока Spark 2.4 ):

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 Comparator (Ordering на самом деле наследуется от 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
2 голосов
/ 12 марта 2019

Это общий способ сделать это с фреймом данных

val df = spark.sql("SELECT * FROM MyTable")

df.orderby("yourcolumn")

orderby docs


Если ваши данные меньше (Похоже, у вас есть только названия недель) и вы можете собирать в виде списка и использовать функцию scala sortWith

Функция sortWith Сортирует эту последовательность в соответствии с функцией сравнения.он берет функцию сравнения и сортирует ее в соответствии с ней. Вы можете предоставить свою собственную функцию сравнения.

Пример, отличный от вашего:

scala> case class Emp(id: Int, name: String, salary: Double)
defined class Emp

scala> val emp1 = Emp(1, "james", 13000.00)
emp1: Emp = Emp(1,james,13000.0)

scala> val emp2 = Emp(2, "michael", 12000.00)
emp2: Emp = Emp(2,michael,12000.0)

scala> val emp3 = Emp(3, "Ram", 15000.00)
emp3: Emp = Emp(3,Ram,15000.0)

scala> val empList = List(emp1,emp2,emp3)
empList: List[Emp] = List(Emp(1,james,13000.0), Emp(2,michael,12000.0), Emp(3,Ram,15000.0))

// sort in descending order on the basis of salary.
scala> empList.sortWith(_.salary > _.salary)

Другие параметры: Как отсортировать RDD в Scala Spark? Чтобы использовать эту опцию, вам нужно преобразовать фрейм данных в PairedRDD, а затем выполнить сортировку по ключу, используя ответ, приведенный там.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...