我有一列100K +名。 我需要比较他们每个人,以确定它们是否相同(杜泽,杜泽)或几乎相同(杜泽,Dsouza)。
我试着读卡桑德拉表到RDD,做与自身柱的笛卡尔积,形成一个元组。 但是,由于该列大小是100K,这导致了巨大的RDD,最终火花作业挂。
下面是我的代码:
val valueRdd = sc.cassandraTable("keyspace", "some_table")
val dataRDD = valueRdd
.map(row => {
(
row
.getStringOption("name")
.get,
}).cache()
val cartesianResult = dataRDD cartesian dataRDD
//Followed by some compare logic. May be soundex or some other library or some fuzzy logic.
这里的问题是,笛卡尔结果将是100K * 100K这是不理想的秩序。 有没有更好的方式来做到这一点?
问题陈述是确定在给定数据集的兄弟姐妹。 该数据集将有它的100K +的数据。
这份名单是足够小,可以将列表转换成广播变量,让每个节点进行比较时的RDD到广播列表的一部分:
val valueRddBC =sc.broadcast(valueRdd.collect())
val similarPairsRdd = valueRdd.flatMap(x =>
valueRddBc.value.filter(y => dist(x,y) > threshold)
.map(y => (x,y)))
100K是很小,但有足够的,你可以做整个事情的驱动程序,如果你想(如果DIST功能也不是很贵,这将可能会更快)。
如果RDD是真正的大,你可以映射项某种指纹忽略大多数与战略无关的项目,诸如LSH(局部敏感哈希)。 这是一个近似最近邻算法,给出了O(1)寻找最接近的项目。
请问您比较函数做任何事情更复杂的比较的名字呢? 如果你正在做的是去掉空格和撇号,你可以简单地转换成RDD键上的名称的简化版本一对RDD,然后用GROUPBY到组相似的名称。 例如:
scala> val rdd = sc.parallelize( List("d'souza", "d souza", "Dsouza") )
scala> rdd.map{
| case x => x.replaceAll(" ", "").replaceAll("'","").toLowerCase -> x
| }.groupByKey.collect
res3: Array[(String, Iterable[String])] = Array((dsouza,CompactBuffer(d'souza, d souza, Dsouza)))