如何从Spark中的RDD和DataFrame过滤?

时间:2016-02-08 12:27:33

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

我有.tsv个文件pageviews_by_second,其中包含timestamp siterequests字段:

"timestamp"              "site"   "requests"
"2015-03-16T00:09:55"   "mobile"    1595
"2015-03-16T00:10:39"   "mobile"    1544
"2015-03-16T00:19:39"   "desktop"   2460

我希望第一行消失,因为它导致我必须对数据执行的操作出错。

我尝试通过以下方式进行:

1.在分割之前过滤RDD

val RDD1 = sc.textFile("pageviews_by_second")       
val top_row = RDD1.first() 
//returns: top_row: String = "timestamp"    "site"  "requests"    
val RDD2 = RDD1.filter(x => x!= top_row)
RDD2.first() 
//returns: "2015-03-16T00:09:55"    "mobile"    1595

2.分割后过滤RDD

val RDD1 = sc.textFile("pageviews_by_second").map(_.split("\t")
RDD1.first()  //returns res0: Array[String] = Array("timestamp, 'site", "requests")
val top_row = RDD1.first()
val RDD2 = RDD1.filter(x => x!= top_row)
RDD2.first() //returns: res1: Array[String] = Array("timestamp", "site" ,"requests")
val RDD2 = RDD1.filter(x => x(0)!="timestamp" && x(1)!="site" && x(2)!="requests")
 RDD2.first() //returns: res1: Array[String] = Array("timestamp", "site" ,"requests")

3.使用' case class'转换为DataFrame。并过滤它

case class Wiki(timestamp: String, site: String, requests: String)
val DF = sc.textFile("pageviews_by_second").map(_.split("\t")).map(w => Wiki(w(0), w(1), w(2))).toDF()
val top_row = DF.first()
//returns: top_row: org.apache.spark.sql.Row = ["timestamp","site","requests"]
DF.filter(_ => _ != top_row)
//returns: error: missing parameter type
val DF2 = DF.filter(_ => _ != top_row2)

为什么只有第一种方法能够过滤掉第一行,而另外两种方法不能?在方法3中,为什么我会得到错误以及如何纠正错误?

4 个答案:

答案 0 :(得分:2)

首先,您需要了解在删除顶行时要比较的数据类型。

比较两个字符串将在方法1中产生true或false。因此它会过滤掉顶行

在方法2中,您正在比较2个Arrays。使用deep数组方法对scala中的数组进行更深入的比较

Method2
val RDD1 = sc.textFile("D:\\trial.txt").map(_.split("\t"))
val top_row = RDD1.first()
val RDD2 = RDD1.filter(x => x.deep!= top_row.deep)
RDD2.first().foreach(println(_))

在方法3中,您要比较数据帧的两行对象。最好将行转换为toSeq后跟toArray,然后使用deep方法过滤掉第一行数据帧。

//Method 3    
DF.filter(_ => _.toSeq.toArray.deep!=top_row.toSeq.toArray.deep)

如果有帮助还原。感谢!!!

答案 1 :(得分:2)

首先,您真的应该使用spark-csv - 包 - 它可以在创建DataFrame(或rdd)时自动过滤掉标头。您只需指定:)

其次,rdds并非按照您认为的方式排序。调用first无法保证返回csv文件的第一行。这是你的第一个场景,显然你确实得到了第一排,但如果你认为自己很幸运,那就更好了。此外,从可能非常大的数据集中删除这样的标头效率非常低,因为Spark需要搜索所有行以过滤掉单行。

如果订购对您进行进一步计算很重要,您可以随时进行zipWithIndex。这样,您就可以对rdd进行排序以保留排序。

答案 2 :(得分:2)

有办法删除标题,而不是深度比较:

data = sc.textFile('path_to_data') header = data.first() #extract header data = data.filter(lambda x:x !=header) #filter out header

可能与您有关: How do I skip a header from CSV files in Spark?

答案 3 :(得分:0)

我找到了另一种方法,它比我使用的过滤方法更有效。将其作为其他人的答案发布可能会发现它有用:

rdd.mapPartitionsWithIndex { (idx, iter) => if (idx == 0) iter.drop(1) else iter }

来源:https://stackoverflow.com/a/27857878/3546389