Il n'y a pas de méthode isEmpty
sur les RDD, alors quelle est la manière la plus efficace de tester si un RDD est vide?
RDD.isEmpty()
fera partie de Spark 1.3.0.
Sur la base des suggestions de ce fil de discussion Apache et plus tard de quelques commentaires à cette réponse, j'ai fait quelques petites expériences locales. La meilleure méthode consiste à utiliser take(1).length==0
.
def isEmpty[T](rdd : RDD[T]) = {
rdd.take(1).length == 0
}
Il doit s'exécuter dans O(1)
sauf lorsque le RDD est vide, auquel cas il est linéaire dans le nombre de partitions.
Merci à Josh Rosen et Nick Chammas de m'avoir signalé cela.
Remarque: cela échoue si le RDD est de type RDD[Nothing]
, Par ex. isEmpty(sc.parallelize(Seq()))
, mais ce n'est probablement pas un problème dans la vie réelle. isEmpty(sc.parallelize(Seq[Any]()))
fonctionne très bien.
take(1)==0
, grâce aux commentaires. Ma suggestion initiale: Utilisez mapPartitions
.
def isEmpty[T](rdd : RDD[T]) = {
rdd.mapPartitions(it => Iterator(!it.hasNext)).reduce(_&&_)
}
Il doit évoluer dans le nombre de partitions et n'est pas aussi propre que take(1)
. Il est cependant robuste aux RDD de type RDD[Nothing]
.
J'ai utilisé ce code pour les timings.
def time(n : Long, f : (RDD[Long]) => Boolean): Unit = {
val start = System.currentTimeMillis()
val rdd = sc.parallelize(1L to n, numSlices = 100)
val result = f(rdd)
printf("Time: " + (System.currentTimeMillis() - start) + " Result: " + result)
}
time(1000000000L, rdd => rdd.take(1).length == 0L)
time(1000000000L, rdd => rdd.mapPartitions(it => Iterator(!it.hasNext)).reduce(_&&_))
time(1000000000L, rdd => rdd.count() == 0L)
time(1000000000L, rdd => rdd.takeSample(true, 1).isEmpty)
time(1000000000L, rdd => rdd.fold(0)(_ + _) == 0L)
time(1L, rdd => rdd.take(1).length == 0L)
time(1L, rdd => rdd.mapPartitions(it => Iterator(!it.hasNext)).reduce(_&&_))
time(1L, rdd => rdd.count() == 0L)
time(1L, rdd => rdd.takeSample(true, 1).isEmpty)
time(1L, rdd => rdd.fold(0)(_ + _) == 0L)
time(0L, rdd => rdd.take(1).length == 0L)
time(0L, rdd => rdd.mapPartitions(it => Iterator(!it.hasNext)).reduce(_&&_))
time(0L, rdd => rdd.count() == 0L)
time(0L, rdd => rdd.takeSample(true, 1).isEmpty)
time(0L, rdd => rdd.fold(0)(_ + _) == 0L)
Sur ma machine locale avec 3 cœurs de travail, j'ai obtenu ces résultats
Time: 21 Result: false
Time: 75 Result: false
Time: 8664 Result: false
Time: 18266 Result: false
Time: 23836 Result: false
Time: 113 Result: false
Time: 101 Result: false
Time: 68 Result: false
Time: 221 Result: false
Time: 46 Result: false
Time: 79 Result: true
Time: 93 Result: true
Time: 79 Result: true
Time: 100 Result: true
Time: 64 Result: true
Depuis Spark 1. la isEmpty()
fait partie de l'API RDD. Un correctif qui provoquait l'échec de isEmpty
a été ultérieurement corrigé dans Spark 1.4 .
Pour les DataFrames, vous pouvez faire:
val df: DataFrame = ...
df.rdd.isEmpty()
Voici un extrait du code issu de l'implémentation RDD (à partir de 1.4.1).
/**
* @note due to complications in the internal implementation, this method will raise an
* exception if called on an RDD of `Nothing` or `Null`. This may be come up in practice
* because, for example, the type of `parallelize(Seq())` is `RDD[Nothing]`.
* (`parallelize(Seq())` should be avoided anyway in favor of `parallelize(Seq[T]())`.)
* @return true if and only if the RDD contains no elements at all. Note that an RDD
* may be empty even when it has at least 1 partition.
*/
def isEmpty(): Boolean = withScope {
partitions.length == 0 || take(1).length == 0
}