Apache spark 如何根据Spark中其他数据帧中的条件筛选数据帧

Apache spark 如何根据Spark中其他数据帧中的条件筛选数据帧,apache-spark,Apache Spark,我有一个数据框source,希望根据另一个名为blacklist的数据框中的条件筛选出条目。源必须至少匹配一个要过滤掉的黑名单条目。黑名单中的列条件/条目通过和链接。blacklist中的NULL值保留为通配符,这意味着相应的属性可以有任何值来匹配条件 一个简化的例子: 来源: | id | age | color | |----|-----|-------| | 1 | 28 | blue | | 2 | 25 | blue | | 3 | 15 | red | | 4

我有一个数据框
source
,希望根据另一个名为
blacklist
的数据框中的条件筛选出条目。
必须至少匹配一个要过滤掉的
黑名单
条目。
黑名单
中的列条件/条目通过
链接。
blacklist
中的
NULL
值保留为通配符,这意味着相应的属性可以有任何值来匹配条件

一个简化的例子:

来源

| id | age | color |
|----|-----|-------|
| 1  | 28  | blue  |
| 2  | 25  | blue  |
| 3  | 15  | red   |
| 4  | 20  | red   |
| 5  | 27  | green |
| 6  | 30  | green |
| age  | color |
|------|-------|
| 25   | blue  |
| NULL | red   |
| 30   | NULL  |
| id | age | color |
|----|-----|-------|
| 1  | 28  | blue  |
| 5  | 27  | green |
黑名单

| id | age | color |
|----|-----|-------|
| 1  | 28  | blue  |
| 2  | 25  | blue  |
| 3  | 15  | red   |
| 4  | 20  | red   |
| 5  | 27  | green |
| 6  | 30  | green |
| age  | color |
|------|-------|
| 25   | blue  |
| NULL | red   |
| 30   | NULL  |
| id | age | color |
|----|-----|-------|
| 1  | 28  | blue  |
| 5  | 27  | green |
输出

| id | age | color |
|----|-----|-------|
| 1  | 28  | blue  |
| 2  | 25  | blue  |
| 3  | 15  | red   |
| 4  | 20  | red   |
| 5  | 27  | green |
| 6  | 30  | green |
| age  | color |
|------|-------|
| 25   | blue  |
| NULL | red   |
| 30   | NULL  |
| id | age | color |
|----|-----|-------|
| 1  | 28  | blue  |
| 5  | 27  | green |
相应的数据帧:

val source=Seq((1,28,“蓝色”)、(2,25,“蓝色”)、(3,15,“红色”)、(4,20,“红色”)、(5,27,“绿色”)、(6,30,“绿色”)。toDF(“id”、“年龄”、“颜色”)
val blacklist=Seq((部分(25),部分(“蓝色”),(无,部分(“红色”),(部分(30),无)).toDF(“年龄”,“颜色”)
有关真实数据的更多信息:

  • 数据存储在配置单元表中(ORC格式)
  • source
    包含100亿个条目
  • 黑名单
    包含20万个条目,共5列
我的方法(使用Spark 2.3):

val joinCondition=(源(“年龄”)黑名单(“年龄”)||黑名单(“年龄”).isNull)和&(源(“颜色”)黑名单(“颜色”)||黑名单(“颜色”).isNull)
val dataToRemove=source.join(广播(黑名单)、joinCondition)。选择(源(“id”)、源(“年龄”)、源(“颜色”))
val输出=源。除(dataToRemove)
问题与疑问:

上面的代码片段正在工作。但是,对于真正的海量数据,我在运行时持续时间方面存在性能问题。你认为有更好的方法来解决这个黑名单问题吗

我还考虑在驱动程序中创建一个大的过滤条件,只需执行
source.filter(theBigCondition)
。这样做的优点是不需要连接。然而,即使有一个较小的黑名单,我也遇到了有关Catalyst Optimizer的问题


你的想法是什么?

你加入广播的方式可能是解决这个问题的最佳方式

首先,试着了解哪个部分花了这么长时间。 可能是这一部分:

val joinedDf = data.join(broadcast(blacklist))
因此,我的第一个怀疑是10b数据帧中的扭曲数据。由于您的黑色DF非常小,“咸连接”在这种情况下将非常有效

算法的基础:

通过选择一个数字
1-N
执行Salty join。将较小DF中的每一行乘以N。对于
N=3

之前的黑名单:

| age  | color |
|------|-------|
| 25   | blue  |
| 30   | NULL  |
黑名单:

| salt | age  | color |
|------|------|-------|
|   1  | 25   | blue  |
|   2  | 25   | blue  |
|   3  | 25   | blue  |
|   1  | 25   | red   |
|   2  | 25   | red   |
|   3  | 25   | red   |
对于每行较大的DF,添加1-N之间的随机数:

    | salt | age  | color |
    |------|------|-------|
    |   3  | 25   | blue  |
    |   2  | 27   | green |
    |   1  | 25   | blue  |
    |   3  | 45   | red   |
然后添加盐列作为连接的一部分:

saltedData.join(brodcast(saltedBlacklist), Seq("salt","age","color"))
现在我们可以看到,在大DF中,我们有重复的(25,蓝色),但由于它们有不同的盐,它们将分配给更多的机器


咸联接的思想是获得更大的熵。如果我们的连接列中有一个真正扭曲的数据,那么工作人员之间的分布就会很差。通过添加salt,我们可以将小df乘以N的数据膨胀,但通过在新的连接列中获得更好的熵,我们得到了更好的分布,其中包含“salt”列。

让我回答我自己的问题

在本地测试中,我发现除了之外的
非常昂贵。在
源数据中添加一种标志,然后根据该标志进行过滤,以加快速度

val blacklistWithFlag=blacklist.withColumn(“删除”,亮起(真))
val markedSource=source.join(广播(blacklistWithFlag)、joinCondition,“左外”)。选择(源(“id”)、源(“年龄”)、源(“颜色”)、blacklistWithFlag(“删除”))
val output=markedSource.filter(列(“删除”).isNull)。drop(“删除”)

这种方法只需要1个阶段,而不是上述4个阶段。

Hmmm。。。性能问题可能由许多因素引起——既与代码有关,也与硬件配置有关。您的代码看起来非常简单,那么是什么让您认为问题出在广播连接上呢?您有一个相当大的
source
数据集-运行作业需要多长时间,您使用的是什么硬件配置?不幸的是,我对硬件配置没有任何影响。如果没有关于实际数据的任何细节,实际运行时间是毫无意义的。我一直在寻找更好的方法来解决这个问题。谢谢你的评论。您能否更详细地解释一下,当我们有一个广播连接时,为什么这个salty连接会改善分布,以及
spark.sql.shuffle.partitions
在这里是如何发挥作用的?我已经用一些实际的生产数据测试了salted连接。它比没有它要慢。不管怎样,谢谢你,我会记住这个方法来解决未来的问题。