使用Spark UDF的字符串过滤器

时间:2016-06-16 13:46:54

标签: scala apache-spark

input.csv:

  

200,300,889,767,9908,7768,9090

     

300,400,223,4456,3214,6675,333

     

234567890

     

123445667887

我想要的: 读取输入文件并与设置“123,200,300”进行比较,如果匹配,则给出匹配数据 200,300(来自1条输入线)

300(来自2输入行)

123(来自4输入行)

我写的:

  import org.apache.spark.{SparkConf, SparkContext}
  import org.apache.spark.rdd.RDD

  object sparkApp {
    val conf = new SparkConf()
      .setMaster("local")
      .setAppName("CountingSheep")
    val sc = new SparkContext(conf)

    def parseLine(invCol: String) : RDD[String]  = {
      println(s"INPUT, $invCol")
      val inv_rdd = sc.parallelize(Seq(invCol.toString))
      val bs_meta_rdd = sc.parallelize(Seq("123,200,300"))
      return inv_rdd.intersection(bs_meta_rdd)
    }

    def main(args: Array[String]) {
      val filePathName = "hdfs://xxx/tmp/input.csv"
      val rawData = sc.textFile(filePathName)
      val datad = rawData.map{r => parseLine(r)}
    }
  }

我得到以下异常:

  

显示java.lang.NullPointerException

请建议我出错的地方

3 个答案:

答案 0 :(得分:2)

问题解决了。这很简单。

val pfile = sc.textFile("/FileStore/tables/6mjxi2uz1492576337920/input.csv")
case class pSchema(id: Int, pName: String)
val pDF = pfile.map(_.split("\t")).map(p => pSchema(p(0).toInt,p(1).trim())).toDF()
pDF.select("id","pName").show()

enter image description here

定义UDF

val findP = udf((id: Int,
                    pName: String
                    ) => {
  val ids = Array("123","200","300")
  var idsFound : String = ""
  for (id  <- ids){
    if (pName.contains(id)){
      idsFound = idsFound + id + ","
    }
  }
  if (idsFound.length() > 0) {
    idsFound = idsFound.substring(0,idsFound.length -1)
  }    
 idsFound
})

在withCoulmn()

中使用UDF
pDF.select("id","pName").withColumn("Found",findP($"id",$"pName")).show()

enter image description here

答案 1 :(得分:1)

您尝试做的事情可以按照您的方式完成。

Spark不支持嵌套RDD(参见SPARK-5063)。

  

Spark不支持嵌套RDD或在转换中执行Spark操作;这通常会导致NullPointerExceptions(参见SPARK-718作为一个例子)。令人困惑的NPE是StackOverflow上最常见的Spark问题来源之一:

           

我认为我们可以通过向RDD添加逻辑来检测这些错误,以检查sc是否为空(例如将sc转换为getter函数);我们可以使用它来添加更好的错误消息。

答案 2 :(得分:1)

  

简单回答,为什么我们这么复杂?在这种情况下,我们不需要UDF。

这是您的输入数据:

200,300,889,767,9908,7768,9090|AAA
300,400,223,4456,3214,6675,333|BBB
234,567,890|CCC
123,445,667,887|DDD

,您必须将其与123,200,300

相匹配
val matchSet = "123,200,300".split(",").toSet
val rawrdd = sc.textFile("D:\\input.txt")
rawrdd.map(_.split("|"))
      .map(arr => arr(0).split(",").toSet.intersect(matchSet).mkString(",") + "|" + arr(1))
      .foreach(println)

你的输出:

300,200|AAA
300|BBB
|CCC
123|DDD