数据帧上任意数量的过滤器

时间:2017-03-13 08:35:12

标签: scala apache-spark apache-spark-sql

我有许多过滤器需要应用于Spark中的数据框,但它首先在运行时我知道哪些过滤器给用户。目前我将它们添加到单独的filter函数中,但如果未定义其中一个过滤器,则会失败

myDataFrame
    .filter(_filter1)
    .filter(_filter2)
    .filter(_filter3)...

如果不需要,我无法真正了解如何在运行时动态排除fx _filter2

我应该通过创建一个大过滤器来实现:

var filter = _filter1
if (_filter2 != null)
    filter = filter.and(_filter2)
...

或者在Spark中我找不到一个很好的模式吗?

3 个答案:

答案 0 :(得分:1)

起初我会摆脱空过滤器:

// Edit "FullName" text box field.
FormTextData fullNameData = (FormTextData)formData["FullName"];
fullNameData.Value = "Jane Doe";

// Edit "BirthDate" text box field.
FormTextData birthDateData = (FormTextData)formData["BirthDate"];
birthDateData.Value = new DateTime(2000, 1, 1);

// Edit "Salary" text box field.
FormTextData salaryData = (FormTextData)formData["Salary"];
salaryData.Value = 5432.1;

然后定义链式过滤器的功能:

val filters:List[A => Boolean] = nullableFilters.filter(_!=null)

现在您可以简单地将过滤器应用于您的df:

def chainFilters[A](filters:List[A => Boolean])(v:A) = filters.forall(f => f(v))

答案 1 :(得分:1)

一种可能的解决方案是将所有filters默认为lit(true)

import org.apache.spark.sql.functions._

val df = Seq(1, 2, 3).toDF("x")

val filter_1 = lit(true)
val filter_2 = col("x") > 1
val filter_3 = lit(true)

val filtered = df.filter(filter_1).filter(filter_2).filter(filter_3)

这将使null保持在您的代码之外,并且将从执行计划中删除简单的真实谓词:

filtered.explain
== Physical Plan ==
*Project [value#1 AS x#3]
+- *Filter (value#1 > 1)
   +- LocalTableScan [value#1]

你当然可以使它更简单和一系列谓词:

import org.apache.spark.sql.Column

val preds: Seq[Column] = Seq(lit(true), col("x") > 1, lit(true))
df.where(preds.foldLeft(lit(true))(_ and _))

并且,如果实施得当,则完全跳过占位符。

答案 2 :(得分:0)

为什么不:

var df = // load
if (_filter2 != null) {
    df = df.filter(_filter2)
}
etc

或者,创建一个过滤器列表:

var df = // load
val filters = Seq (filter1, filter2, filter3, ...)
filters.filter(_ != null).foreach (x => df = df.filter(x))

//对不起,如果代码中有一些错误,那就更有想法 - 目前我无法测试代码