Scala+Spark文本相似度均值计算问题求助
搞定Spark文本相似度的平均值计算
嘿,作为Scala+Spark新手,你已经完成了核心的相似度计算逻辑,只差最后一步求平均值啦!我来帮你完善代码,顺便给你提个效率优化的小建议~
先说说原代码的小问题
你用cartesian(笛卡尔积)再过滤相同单词的方式,其实效率不高——笛卡尔积会生成两个RDD所有元素的组合,再过滤掉不匹配的,当单词数量多的时候会浪费很多资源。更高效的方式是用join操作,直接关联两个RDD中相同单词的统计结果。
完整的修正代码
import org.apache.spark._ import org.apache.spark.SparkContext._ object WordCount { def main(args: Array[String]): Unit = { val conf = new SparkConf().setAppName("WordCount") val sc = new SparkContext(conf) // 第一个文本的词频统计 val wordCounts1 = sc.textFile("/chatblanc.txt") .flatMap(_.split("\\W+")) .map((_, 1)) .reduceByKey(_ + _) // 第二个文本的词频统计 val wordCounts2 = sc.textFile("/chatnoir.txt") .flatMap(_.split("\\W+")) .map((_, 1)) .reduceByKey(_ + _) // 用join高效关联两个文本中相同的单词,得到(单词, (文本1的词频, 文本2的词频)) val commonWordCounts = wordCounts1.join(wordCounts2) // 计算每个共同单词的相似度,逻辑和你原来的一致 val individualSimilarities = commonWordCounts.map { case (word, (count1, count2)) => Math.min(count1, count2).toDouble / Math.max(count1, count2).toDouble } // 计算所有相似度的平均值——两种方式任选其一 // 方式1:直接用Spark RDD提供的mean()方法(最简单) val averageSimilarity = individualSimilarities.mean() // 方式2:手动累加总和和元素数量,适合理解底层逻辑 // val (totalSimilarity, count) = individualSimilarities.map(s => (s, 1)) // .reduce((acc, current) => (acc._1 + current._1, acc._2 + current._2)) // val averageSimilarity = totalSimilarity / count // 输出结果 println("======= Individual Similarities ========") individualSimilarities.collect().foreach(println) println(s"======= Average Similarity: $averageSimilarity ========") // 记得关闭SparkContext释放资源 sc.stop() } }
关键步骤解释
- 用
join替代笛卡尔积:wordCounts1.join(wordCounts2)会直接匹配两个RDD中key相同的条目,得到(单词, (count1, count2))的结构,比先做笛卡尔积再过滤高效N倍。 - 计算单个相似度:和你原来的逻辑完全一致,用最小词频除以最大词频得到单个单词的相似度。
- 计算平均值:
- 方式1用
mean()方法:Spark已经帮我们封装好了,直接调用就能得到Double类型RDD的平均值,最简单省心。 - 方式2手动计算:用
reduce累加所有相似度的总和,同时统计元素数量,最后相除,适合你理解Spark的reduce操作逻辑。
- 方式1用
- 关闭SparkContext:加上
sc.stop()是个好习惯,避免资源泄漏。
测试结果
按照你的输入文本,单个相似度是1.0,1.0,1.0,0.5,1.0,1.0,总和是5.5,元素数量是6,所以平均值是5.5/6 ≈ 0.9167,代码运行后会正确输出这个值。
内容的提问来源于stack exchange,提问作者aniss cherkaoui
相关产品推荐
相关产品推荐

