web-dev-qa-db-ja.com

Apache Spark 2つのRDDへのRDDフィルター

RDDを2つの部分に分割する必要があります。

条件を満たす1つの部分。そうでない別の部分。元のRDDでfilterを2回実行できますが、非効率的なようです。私が求めていることを実行できる方法はありますか? APIにも文献にも何も見つかりません。

18
monster

Sparkはデフォルトでこれをサポートしていません。同じデータを2回フィルタリングすることは、事前にキャッシュしておけばそれほど悪くはなく、フィルタリング自体も高速です。

それが本当に2つの異なるタイプである場合は、ヘルパーメソッドを使用できます。

implicit class RDDOps[T](rdd: RDD[T]) {
  def partitionBy(f: T => Boolean): (RDD[T], RDD[T]) = {
    val passes = rdd.filter(f)
    val fails = rdd.filter(e => !f(e)) // Spark doesn't have filterNot
    (passes, fails)
  }
}

val (matches, matchesNot) = sc.parallelize(1 to 100).cache().partitionBy(_ % 2 == 0)

ただし、複数のタイプのデータがあるとすぐに、フィルター処理されたものを新しい値に割り当てます。

22
Marius Soutier

SparkRDDにはそのようなAPIはありません。

rdd.spanのプルリクエスト に基づくバージョンが機能するはずです:

import scala.reflect.ClassTag
import org.Apache.spark.rdd._

def split[T:ClassTag](rdd: RDD[T], p: T => Boolean): (RDD[T], RDD[T]) = {

    val splits = rdd.mapPartitions { iter =>
        val (left, right) = iter.partition(p)
        val iterSeq = Seq(left, right)
        iterSeq.iterator
    }

    val left = splits.mapPartitions { iter => iter.next().toIterator}

    val right = splits.mapPartitions { iter => 
        iter.next()
        iter.next().toIterator
    }
    (left, right)
}

val rdd = sc.parallelize(0 to 10, 2)

val (first, second) = split[Int](rdd, _ % 2 == 0 )

first.collect
// Array[Int] = Array(0, 2, 4, 6, 8, 10)
5

重要なのは、フィルターを実行するのではなく、マップを実行することです。

(T) -> (Boolean, T)

申し訳ありませんが、Scala構文では非効率的です。ただし、回答セットをキーと値のペアにマッピングして分割するという考え方です。キーは、合格したかどうかを示すブール値にすることができます。 'Filter'述語。

パーティションごとの処理を行うことで、さまざまなターゲットへの出力を制御できます。並列処理をダウンストリームの2つのパーティションだけに制限しないように注意してください。

参照 RDDを2つ以上のRDDに分割するにはどうすればよいですか?

4
YoYo

RDD[T]の代わりにTで問題がない場合は、 これを行う 。それ以外の場合は、次のようなことを行うことができます。

val data = sc.parallelize(1 to 100)
val splitData = data.mapPartitions{iter => {
    val splitList = (iter.toList).partition(_%2 == 0)
    Tuple1(splitList).productIterator
  }
}.map(_.asInstanceOf[Tuple2[List[Int],List[Int]]])

そして、アクションを実行するときにリストをマージするには、おそらくこれを減らす必要があります

1
Justin Pihony

subtract functionを使用できます(フィルター操作が高すぎる場合)。

PySparkコード:

rdd1 = data.filter(filterFunction)

rdd2 = data.subtract(rdd1)
0