我们假设我们有一个这样的数字列表:
lst = [1,2,4,5,9,10]
我如何编写Spark程序以找出该列表中缺少的数字。该计划应返回:3,6,7,8。
我试过累加器,dint工作了。
答案 0 :(得分:1)
您可以尝试使用sc.range
创建一个完整范围的RDD,然后使用subtract
函数:
lst = sc.parallelize([1,2,4,5,9,10])
max_value = lst.max()
full_data = sc.range(1, max_value)
missing_values = full_data.subtract(lst)
如果您事先知道完整列表的大小,则可以避免调用max()
。
答案 1 :(得分:0)
如果您不太担心拥有最佳解决方案,那么一种方法是首先广播您拥有的数据,然后并行化包含所有元素的集合,并根据广播数据对其进行过滤。
像
这样的东西lst = [1,2,4,5,9,10]
broadcastVar = sc.broadcast(lst)
all_elems = sc.parallelize([i+1 for i in range(10)])
all_elems.filter(lambda x: x not in broadcastVar.value)
如果你正在寻找适用于少量数据的东西,那么这很好。如果您有大量数据,那么这种方法很糟糕,不应该使用。
如果需要更好的解决方案,那么我会做以下
然后,您可以编写结果或收集或使用它们进行任何操作。需要注意的一点是,例如,如果我使用了5个执行器,那么键将是1-2,3-4,5-6,7-8,9-10,键7-8不会有任何元素。为了避免这种情况,一个选项是将按键分组的rdd与[(1-2,-1),(3-4,-1),(5-6,-1),(7-8, -1),(9-10,-1)]。如果你有大量的数据,那么与整个工作相比,由此增加的开销非常小。
此示例代码存在许多问题,但将其视为概念验证。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.sql.SparkSession;
import org.spark_project.guava.collect.Lists;
import scala.Tuple2;
public class Main {
public static void main(String[] args) {
SparkSession spark = SparkSession.builder().appName("spark-missing-nr").master("local[*]").getOrCreate();
JavaSparkContext sc = new JavaSparkContext(spark.sparkContext());
Integer[] lst = new Integer[] { 1, 2, 4, 5, 9, 10 };
JavaRDD<Integer> lstRDD = sc.parallelize(Arrays.asList(lst));
// Partition the data by whether number is smaller/equal or larger than
// 5
JavaPairRDD<String, Integer> groupableRDD = lstRDD.mapToPair(i -> {
String group = i <= 5 ? "1-5" : "6-10";
return new Tuple2<String, Integer>(group, i);
});
// Group by key
JavaPairRDD<String, Iterable<Integer>> groupedRDD = groupableRDD.groupByKey();
// so now we have [(1-5,[1, 2, 4, 5]), (6-10,[9, 10])]
System.out.println(groupedRDD.collect());
// map where you iterate over range specified by key
JavaRDD<List<Integer>> missingValuesLists = groupedRDD.map(t -> {
Integer from = new Integer(t._1().split("-")[0]);
Integer to = new Integer(t._1().split("-")[1]);
List<Integer> valuesList = Lists.newArrayList(t._2());
List<Integer> missingValues = new ArrayList<Integer>();
// iterate over range specified by key
for (int i = from; i < to + 1; i++) {
if (!valuesList.contains(i)) {
missingValues.add(i);
}
}
return missingValues;
});
// outputs [[3], [6, 7, 8]]
System.out.println(missingValuesLists.collect());
sc.close();
}
}