web-dev-qa-db-ja.com

Scala SparkでRDDをソートする方法は?

読み取りSparkメソッド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.

「N」個の結果だけを返すことは可能ですか?したがって、すべての結果を返す代わりに、上位10を返すだけです。ソートされたコレクションを配列に変換し、takeメソッドを使用できますが、これはO(N)操作より効率的な方法はありますか?

34
blue-sky

ほとんどの場合、すでにソースコードを熟読しています。

  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)
  }

そして、あなたが言うように、スニペットに見られるように、全体データはシャッフルステージを通過する必要があります。

ただし、その後take(K)を呼び出すことに対する懸念はそれほど正確ではない場合があります。この操作は、N個すべてのアイテムを循環しません。

  /**
   * 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] = {

そのため、次のようになります。

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

19
javadba

トップ10のみが必要な場合は、rdd.top(10)を使用します。ソートが回避されるため、高速になります。

rdd.topは、データの1つの並列パスを作成し、ヒープ内の各パーティションの上位Nを収集してから、ヒープをマージします。それis an O(rdd.count)操作。ソートはO(rdd.count log rdd.count)になり、大量のデータ転送が発生します。これはシャッフルを行うため、すべてのデータがネットワーク経由で送信されます。

51
Daniel Darabos

少なくともPySpark 1.2.0からの別のオプションは、 takeOrdered の使用です。

昇順:

rdd.takeOrdered(10)

降順:

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

K、vペアの上位k値:

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