如何使用scala将一行与spark中的所有其他行进行比较

时间:2016-12-20 23:15:25

标签: scala apache-spark cassandra

我在列中有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 +数据。

2 个答案:

答案 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)))