假设HDFS都每份数据一共存储两份,其中以一块数据有错,那么收集所有块数据的ID,则如下:
5 5 6 6 7 7 8 8 9
在大数据下如何找到9这块数据是错误的。
可以利用异或的数据,求出答案9
异或性质:
1、交换律 a^b=b^a
2、结合律(即(a^b)^c == a^(b^c))
3、对于任何数x,都有x^x=0,x^0=x
4、自反性 A XOR B XOR B = A xor 0 = A
假如spark的任务分区有三个:
分区1:
5 ^ 6 ^ 7
1 0 1 5
1 1 0 6
1 1 1 7
1 0 0 4
分区2:
5 ^ 6 ^ 8
1 0 1 5
1 1 0 6
1 0 0 0 8
1 0 1 1 11
分区3:
7 ^ 8 ^ 9
1 1 1 5
1 0 0 0 6
1 0 0 1 7
0 1 1 0 6
计算结果:
将4,11,6再次进行异或运算
4 ^ 11 ^ 6
1 0 0 4
1 0 1 1 11
1 1 0 6
1 0 0 1 9
模拟spark计算,结果能得到正确的答案9,这是由于满足结合律和交换律。
spark程序(1):
package com.dt.spark.cores.scalaspark程序(2):
import org.apache.spark.{SparkContext, SparkConf}
object CountOnce {
def main (args: Array[String]) {
val conf = new SparkConf().setAppName("CountOnce").setMaster("local")
val sc = new SparkContext(conf)
val data = sc.textFile("E:\\workspases\\data\\CountOnce.txt")
val word = data.map(line => line.toInt)
val result =word.reduce(_^_)
println(result)
}
}
val conf = new SparkConf()
.setAppName("count once")
.set("spark.executor.memory", args(1))
val sc = new SparkContext(conf)
val data = sc.textFile(args(0))
val result = data.mapPartitions( iter => {
var tmp = iter.next().toInt
while (iter.hasNext) {
tmp ^= iter.next().toInt
}
Seq((1, tmp)).iterator//每个分区的数据都是key,都是1,最后收集到一块
}).reduceByKey(_ ^ _).collect
println(result(0))
//备注:mapPartitions函数解释
def mapPartitions[U](f: (Iterator[T]) => Iterator[U], preservesPartitioning: Boolean = false)(implicit arg0: ClassTag[U]): RDD[U]
该函数和map函数类似,只不过映射函数的参数由RDD中的每一个元素变成了RDD中每一个分区的迭代器。如果在映射的过程中需要频繁创建额外的对象,使用mapPartitions要比map高效的过。
比如,将RDD中的所有数据通过JDBC连接写入数据库,如果使用map函数,可能要为每一个元素都创建一个connection,这样开销很大,如果使用mapPartitions,那么只需要针对每一个分区建立一个connection。
参数preservesPartitioning表示是否保留父RDD的partitioner分区信息。