web-dev-qa-db-fra.com

Comment trier un RDD dans Scala Spark?

Lecture Spark méthode sortByKey:

sortByKey([ascending], [numTasks])   When called on a dataset of (K, V) pairs where K implements Ordered, returns a dataset of (K, V) pairs sorted by keys in ascending or descending order, as specified in the boolean ascending argument.

Est-il possible de renvoyer juste "N" quantité de résultats. Donc, au lieu de renvoyer tous les résultats, retournez simplement le top 10. Je pourrais convertir la collection triée en tableau et utiliser la méthode take mais puisque c'est une opération O(N) existe-t-il une méthode plus efficace?

34
blue-sky

Vous avez probablement déjà lu le code source:

  class OrderedRDDFunctions {
   // <snip>
  def sortByKey(ascending: Boolean = true, numPartitions: Int = self.partitions.size): RDD[P] = {
    val part = new RangePartitioner(numPartitions, self, ascending)
    val shuffled = new ShuffledRDD[K, V, P](self, part)
    shuffled.mapPartitions(iter => {
      val buf = iter.toArray
      if (ascending) {
        buf.sortWith((x, y) => x._1 < y._1).iterator
      } else {
        buf.sortWith((x, y) => x._1 > y._1).iterator
      }
    }, preservesPartitioning = true)
  }

Et, comme vous le dites, les données entière doivent passer par l'étape de lecture aléatoire - comme le montre l'extrait de code.

Cependant, votre préoccupation concernant l'invocation ultérieure de take (K) peut ne pas être aussi précise. Cette opération ne fait PAS défiler tous les N éléments:

  /**
   * Take the first num elements of the RDD. It works by first scanning one partition, and use the
   * results from that partition to estimate the number of additional partitions needed to satisfy
   * the limit.
   */
  def take(num: Int): Array[T] = {

Alors, il semblerait:

O(myRdd.take(K)) << O(myRdd.sortByKey()) ~= O(myRdd.sortByKey.take(k)) (at least for small K) << O(myRdd.sortByKey().collect()

19
javadba

Si vous n'avez besoin que du top 10, utilisez rdd.top(10). Cela évite le tri, donc c'est plus rapide.

rdd.top effectue un passage parallèle dans les données, collecte les N supérieurs de chaque partition dans un segment, puis fusionne les segments. Il est une O (rdd.count) opération. Le tri serait O (rdd.count log rdd.count), et entraînerait beaucoup de transfert de données - il fait un shuffle, donc toutes les données seraient transmises sur le réseau.

51
Daniel Darabos

Une autre option, au moins à partir de PySpark 1.2.0, est l'utilisation de takeOrdered .

Dans l'ordre croissant:

rdd.takeOrdered(10)

Par ordre décroissant:

rdd.takeOrdered(10, lambda x: -x)

Principales valeurs k pour les paires k, v:

rdd.takeOrdered(10, lambda (k, v): -v)
8
jruizaranguren