Scala中如何用for循环比较同一数组元素?Spark数据处理求助
搞定Spark RDD分组拼接字符串的问题
嘿,作为Scala和Spark初学者遇到这种问题太正常了,我来帮你理清楚问题所在,然后给出靠谱的解法~
首先先明确你的需求:把给定RDD里相同长度的字符串拼接在一起,最终输出以「(字符串长度, 拼接后的字符串)」为元素的数组——单个长度的字符串直接保留,多个同长度的就拼成一个字符串,对吧?
先说说你现有代码的问题
你用collect()把RDD拉到本地Driver节点处理,这在数据量小的时候看似没问题,但完全违背了Spark分布式处理的初衷,数据量大的时候直接会内存溢出。而且嵌套循环的逻辑有明显bug:
- 双重循环会重复处理配对(比如
dog和cat会被处理两次:i=dog,j=cat 和 i=cat,j=dog),导致重复输出 - 你只是打印拼接后的字符串,没有把长度和拼接结果组合成要求的键值对,也没做分组聚合,自然得不到预期的数组结构
正确的Spark RDD处理方式
我们用Spark的分布式转换操作来实现,核心思路是按字符串长度分组,再对每组内的字符串做拼接,全程在分布式集群上处理,效率拉满:
val a = sc.parallelize(List("dog","tiger","lion","cat","panther","eagle")) val res = a // 第一步:把每个字符串映射成(长度,原字符串)的键值对 .map(s => (s.length, s)) // 第二步:按长度分组,得到(长度,同长度字符串的迭代器) .groupByKey() // 第三步:把每组里的所有字符串拼接成一个 .mapValues(strings => strings.mkString("")) // 转换成数组(如果需要的话) .collect() // 打印结果看看 res.foreach(println)
运行这段代码后,你会得到:
(3,dogcat) (4,lion) (5,tigereagle) (7,panther)
和你的预期输出只是顺序不同——Spark的分组结果顺序不保证,如果需要特定顺序,加个排序就行:
val sortedRes = res.sortBy(_._1)
额外说明
如果你的需求其实是同长度字符串两两拼接(而不是全部拼接),那逻辑会不一样,但从你的预期输出看应该不是。不过还是给你补个例子,用cartesian实现两两拼接并去重:
val pairwiseRes = a .cartesian(a) .filter { case (s1, s2) => s1.length == s2.length && s1 != s2 } .map { case (s1, s2) => (s1.length, s1 + s2) } .distinct() // 去掉(s1,s2)和(s2,s1)的重复结果 .collect()
内容的提问来源于stack exchange,提问作者Ashitosh
相关产品推荐
相关产品推荐

