如何基于条件获取DataFrame行子集?Spark多表筛选实操咨询
如何从DataFrame中筛选未出现在另一DataFrame指定列中的行?
看起来你想从vertices里找出那些ID既没在edges的srcId也没在dstId里出现过的行,我来给你两种实用的解决办法,比你之前尝试的join方式更高效清晰。
先再明确下你的数据和需求:
你的原始数据
edges DataFrame
| srcId | dstId | timestamp |
|---|---|---|
| 1 | 4 | 1346564657 |
| 1 | 2 | 1345769687 |
| 2 | 4 | 1345769687 |
| 4 | 1 | 1345769687 |
vertices DataFrame
| id | name | s_type |
|---|---|---|
| 1 | abc | A |
| 2 | def | B |
| 3 | rtf | C |
| 4 | wrr | D |
你要的结果是只保留vertices中ID为3的那一行。
方法一:用左反连接(Left Anti Join)「推荐!」
这是Spark处理这类“找左表中不在右表的行”场景最高效的方式,尤其适合大数据量。思路是先把edges里所有出现过的ID提取出来,再和vertices做左反连接——这种连接只会返回左表中没有在右表匹配到的行。
import org.apache.spark.sql.functions._ // 第一步:提取edges中所有出现过的ID,去重后得到一个只含ID的DataFrame val allEdgeIds = edges.select(col("srcId").alias("id")) .union(edges.select(col("dstId").alias("id"))) .distinct() // 第二步:左反连接,直接拿到目标子集 val subVertices = vertices.join(allEdgeIds, Seq("id"), "left_anti") // 查看结果 subVertices.show()
运行后你会得到预期输出:
+---+----+------+ | id|name|s_type| +---+----+------+ | 3| rtf| C| +---+----+------+
方法二:收集ID集合后过滤「适合小数据量」
如果你的edges数据量很小,可以把所有出现过的ID收集到Driver端的集合里,再用过滤的方式筛选。但注意大数据量下别用这个方法,collect()会把数据拉到Driver端,容易内存溢出。
// 收集edges中所有去重后的ID到Set val edgeIdSet = edges.select(col("srcId")) .union(edges.select(col("dstId"))) .distinct() .as[Int] .collect() .toSet // 过滤掉vertices中ID在集合里的行,留下不在的 val subVertices = vertices.filter(!col("id").isin(edgeIdSet.toSeq: _*)) subVertices.show()
说说你之前的尝试问题
你用left join加不等条件的方式,会产生大量笛卡尔积(每个vertices的行都会和edges中不匹配的行连接),后续还要处理空值,不仅效率低,逻辑也容易出错,不如上面两种方法直接。
内容的提问来源于stack exchange,提问作者ScalaBoy
相关产品推荐
相关产品推荐

