如何将多个过滤器应用于一个数据框?

时间:2019-09-20 16:37:41

标签: python apache-spark apache-spark-sql pyspark-sql

我有一个看起来像的数据框

+-------+-------+
| Code1 | Code2 |
+-------+-------+
| A     |     1 |
| B     |     1 |
| A     |     2 |
| B     |     2 |
| C     |     2 |
| D     |     2 |
| D     |     3 |
| F     |     3 |
| G     |     3 |
+-------+-------+

然后我想应用一组唯一的过滤器,如下所示:

  • 方案1->对Code1 IN(A,B)进行过滤
  • 方案2->对Code1 IN(A,D)和Code2 IN(2,3)进行过滤
  • 方案3->对Code2 = 2进行过滤

应用过滤器的结果应为如下所示的数据框:

+-------+-------+----------+
| Code1 | Code2 | Scenario |
+-------+-------+----------+
| A     |     1 |        1 |
| B     |     1 |        1 |
| A     |     2 |        1 |
| B     |     2 |        1 |
| A     |     2 |        2 |
| D     |     2 |        2 |
| D     |     3 |        2 |
| A     |     2 |        3 |
| B     |     2 |        3 |
| C     |     2 |        3 |
| D     |     2 |        3 |
+-------+-------+----------+

问题:通过python使用spark做到这一点的最有效方法是什么?

我是新手,所以我真的是从概念上提出问题,不需要明确的解决方案。我的目标是在操作中实现尽可能多的并行性。我的实际示例涉及使用38列的初始数据帧作为csv文件,其大小从100MB到几GB,大约为100MB到150GB。

该解决方案的原始设计是依次处理每个方案过滤器,并将合并的过滤后的数据帧合并在一起,但是我觉得这否定了使用spark的全部观点。

EDIT :可以吗?对于每种情况,我都会先过滤再进行合并,这都是转换(惰性评估)。最终的执行计划是否足够聪明,可以自动并行化多个唯一过滤器?

是否没有一种方法可以并行应用过滤器,例如,与应用过滤器2和3同时应用方案过滤器1?我们是否必须“炸毁”初始数据帧N次,其中N =#个场景过滤器,在新数据帧后追加一个“场景#”列,并应用一个类似于以下内容的大过滤器:

WHERE (Scenario = 1 AND Code1 IN (A,B)) OR
      (Scenario = 2 AND Code1 IN (A,D) AND Code2 IN (2,3)) OR
      (Scenario = 3 AND Code2 = 2)

如果这最终是最有效的方法,那么它是否还取决于“被炸毁”的数据帧需要占用多少内存?如果“被炸毁”的数据帧占用的内存多于群集所占用的内存,那么我是否只需要处理内存中可以容纳的尽可能多的方案?

2 个答案:

答案 0 :(得分:0)

您可以一次应用所有过滤器:

  data.withColumn("scenario",
    when('code1.isin("A", "B"), 1).otherwise(
      when('code1.isin("A", "D") && 'code2.isin("2","3"), 2).otherwise(
        when('code2==="2",3)
      )
    )
  ).show()

但是您还有另一个问题,例如值(A,2)在您所有的场景1,2,3中都可能存在。在这种情况下,您可以尝试以下方式:

  data.withColumn("s1", when('code1.isin("A", "B"), 1).otherwise(0))
    .withColumn("s2",when('code1.isin("A", "D") && 'code2.isin("2","3"), 1).otherwise(0))
    .withColumn("s3",when('code2==="2",1).otherwise(0))
    .show()

输出:

+-----+-----+---+---+---+
|code1|code2| s1| s2| s3|
+-----+-----+---+---+---+
|    A|    1|  1|  0|  0|
|    B|    1|  1|  0|  0|
|    A|    2|  1|  1|  1|
|    B|    2|  1|  0|  1|
|    A|    2|  1|  1|  1|
|    D|    2|  0|  1|  1|
|    D|    3|  0|  1|  0|
|    A|    2|  1|  1|  1|
|    B|    2|  1|  0|  1|
|    C|    2|  0|  0|  1|
|    D|    2|  0|  1|  1|
+-----+-----+---+---+---+

答案 1 :(得分:0)

在对我的问题的编辑中,我质疑惰性评估是否是解决问题的关键。在Spark UI中进行了一些研究后,我得出的结论是,即使我的原始解决方案看起来像,它针对每种情况都依次应用了转换(先过滤后合并),实际上它是同时应用所有转换,一旦调用动作(例如dataframe.count())。 screenshot here代表dataframe.count()作业转换阶段的事件时间轴。

该作业包括96个方案,每个方案在原始数据帧上都有一个唯一的筛选器。您可以看到我的本地计算机同时运行8个任务,其中每个任务代表一个场景中的一个过滤器。

最后,一旦对结果数据帧调用了操作,Spark将负责优化过滤器以并行运行。