我正在对数据集进行基本的调试。 我在文件test.csv中有如下数据
abc,1
def,2
ghi,3
jkl,4
mno,5
我在数据框中阅读
val df= spark.read.csv("test.csv")
val repart=df.repartition(5,col("_c1"))
repart.write.csv("/home/partfiles/")
现在写完数据后,它已经创建了 5个零件文件,这是正确的。 但在这个过程中,只有三个部分文件具有如下所示的适当数据。
part00000 -empty
part00001 -jkl,4
part00002 -empty
part00003 -ghi,3
part00004 - abc,1
def,2
mno,5
但是因为我根据第二列进行了重新分区,并且理想情况下所有数据都不同,所以应该创建5个不同的零件文件。
根据数据集API文档
将由给定分区表达式分区的新数据集返回到numPartitions。生成的数据集是散列分区的。
然后我用google搜索了一些东西,发现了这篇关于分区的惊人文章(How does HashPartitioner work?) 正如本文中提到的,DataSet使用Murmur3Hash算法。所以我编写了一些小代码来根据这篇SO文章(How can I use Scala's MurmurHash implementation: scala.util.MurmurHash3?)得到哈希值。
class Murmur3{
import scala.util.hashing.{ MurmurHash3 => MH3 }
val values= (1 to 5).map(p=> p.toString)
val result = values.map(n => (n,MH3.stringHash(n,MH3.stringSeed)))
def resultVal(): Unit ={
val dn= result.map( d=> d._1 -> (d._2,d._2 % 5)) //
dn.foreach(println)
}
}
这给了我这个价值。输出类似于(数字,(hasvalue,hashvalue%5))
(1,(-1672130795,0))
(2,(382493853,3))
(3,(1416458177,2))
(4,(1968144336,1))
(5,(2100358791,1))
现在从这些数据中,它必须生成4个部分文件。但是如何生成3部分文件。 请告诉我数据集中的散列分区是如何工作的。
答案 0 :(得分:1)
你犯的错误是假设在Scala字符串上进行散列。实际上Spark直接在不安全的字节数组上进行哈希。
所以表达式等同于
import org.apache.spark.sql.functions.hash
Seq("1", "2", "3", "4", "5").toDF.select(
when(hash($"value") % 5 > 0, hash($"value") % 5 )
.otherwise(hash($"value") % 5 + 5)
).show
// +-----------------------------------------------------------------------------------------+
// |CASE WHEN ((hash(value) % 5) > 0) THEN (hash(value) % 5) ELSE ((hash(value) % 5) + 5) END|
// +-----------------------------------------------------------------------------------------+
// | 4|
// | 4|
// | 3|
// | 1|
// | 4|
// +-----------------------------------------------------------------------------------------+
给出观察到的分布。