我有许多过滤器需要应用于Spark中的数据框,但它首先在运行时我知道哪些过滤器给用户。目前我将它们添加到单独的filter
函数中,但如果未定义其中一个过滤器,则会失败
myDataFrame
.filter(_filter1)
.filter(_filter2)
.filter(_filter3)...
如果不需要,我无法真正了解如何在运行时动态排除fx _filter2
?
我应该通过创建一个大过滤器来实现:
var filter = _filter1
if (_filter2 != null)
filter = filter.and(_filter2)
...
或者在Spark中我找不到一个很好的模式吗?
答案 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))
//对不起,如果代码中有一些错误,那就更有想法 - 目前我无法测试代码