我在列中有100K +名称。我需要比较它们中的每一个以确定它们是否相同(D'Souza,D'Souza)或几乎相同(D'Souza,Dsouza)。
我尝试将cassandra表读入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 +数据。
答案 0 :(得分:5)
列表足够小,您可以将列表转换为广播变量,并让每个节点将它的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)找到最近的项目。
答案 1 :(得分:0)
你的比较函数是否做了比较名称更复杂的事情?如果你所做的只是删除空格和撇号,你可以简单地将RDD转换为一个在名称的简化版本上键入的RDD对,然后使用groupBy对相似的名称进行分组。 e.g:
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)))