在Apache Spark中应用中值过滤器

时间:2017-06-12 18:00:04

标签: java apache-spark

假设我有一个整数的RDD,如果过滤器的窗口是3,如何应用中值滤波器?

我查看的Spark中的所有map和filter方法,一次只处理一个元素。但是要在窗口中找到中位数,我们想要同时知道窗口中所有元素的值。

我是Spark的新手,非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

我假设您需要应用此Wikipedia页面中描述的中值过滤器。 可以这样做,但在Spark中做效率不高。

基本上,您需要先与x_nRDD[X_N] => RDD[List(X_N -1, X_N, X_N +1)]的邻居建立RDD。这是我的代码,用于计算维基百科中的相同示例。抱歉,它在Scala中,而不是Java中,但我认为这个想法应该是明确的。

val nums = List[Int](2, 80, 6, 3)
val rdd = sc.parallelize(nums, 2)

def median3(x: List[(Int, Int)]): Int = {
    // here we discard the index of x and sort by its value
    val x2 = x.map(_._1).sorted
    x2(1)
}

val filtered = rdd.zipWithIndex.flatMap{
        t =>
            val (x_n, n) = t
            // First, duplicate data: x_n should appear in windows of its neighbours
            List(
                (n - 1, (x_n, -1)), // the last value is kept for illustration
                (n, (x_n, 0)),
                (n + 1, (x_n, 1))
            )
    // grouping by n we will get (x_n-1, x_n, x_n +1)
    // flatMap to discard corner cases
    }.groupByKey().flatMap{
        r =>
            val (i, x) = r
            (i, x.toList) match {
                case (_, x) if x.size == 1 => None // corner cases: n=-1 and n=4
                // first element and last element need special treatment
                case (i, x) if i == 0 => Some((i, median3(List(x.head) ++ x)))
                case (i, x) if x.size == 2 => Some((i, median3(x ++ List(x.reverse.head))))
                // filtering itself
                case (_, x) => Some((i, median3(x)))
            }
    }.sortByKey().map(_._2).collect()
// filtered: Array[Int] = Array(2, 6, 6, 3)

此代码效率低下有两个原因:

  • 它使用3倍的内存(至少)进行数据复制
  • 它执行至少2次关键改组(.groupByKey.sortByKey),这是Spark中最昂贵的操作

如果您的数据适合放在一台机器上,最好选择pandas

答案 1 :(得分:0)

我发现Spark API中的窗口函数和UDAF是实现中值过滤的好方法。

注册UDAF:

sqlContext.udf().register("medianFilter", medianFilterUDAF);

通过窗口调用UDAF:

Column col1 = org.apache.spark.sql.functions.callUDF("medianFilter", intDF.col("column1")).over(Window.orderBy("columnA", "columnB").rowsBetween(-windowSize, windowSize));

medianFilterUDAF是自定义UDAF的对象,它在窗口上执行元素的中值过滤。你必须覆盖UDAF类的方法即。 dataType()evaluate(Row buffer)initialize(MutableAggregationBuffer buffer)update(MutableAggregationBuffer buffer, Row row)merge(MutableAggregationBuffer buffer1, Row buffer2)inputSchema()bufferSchema()deterministic()

因此,对于中值过滤,您必须对缓冲区的元素进行排序,并在evaluate方法中返回中间元素。