如何根据数据类型过滤数据?

时间:2017-09-15 03:10:13

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

给出这样的数据:

val my_data = sc.parallelize(Array(
  "Key1, foobar, 10, twenty, 20",
  "Key2, impt, 11, sixty, 6",
  "Key3, helloworld, 110, seventy, 9"))

我想过滤并创建一个key,value RDD,如下所示:

key1, foobar
key1, twenty
key2, impt
key2, sixty
key3, helloworld
key3, seventy

我尝试了什么

我认为我可以将数据放在表格中,并推断出数据类型。

//is there a way to avoid writing to file???
my_data.coalesce(1).saveAsTextFile("/tmp/mydata.csv") 
val df_mydata = sqlContext.read
.format("com.databricks.spark.csv")
.option("inferSchema", "true") 
.load("/tmp/mydata.csv")

上面的工作使得我有一个包含正确数据类型的表。但是,我不知道如何过滤数据类型,然后从中创建键/值对。

我也可以使用Character.isDigit而不是创建架构但仍需要知道如何过滤键/值对

1 个答案:

答案 0 :(得分:0)

正如您所提到的,解决问题的一种方法是将Character.isDigitsplitflatMap一起使用。以my_data为例:

val spark = SparkSession.builder.getOrCreate()
import spark.implicits._

val df = my_data.map(_.split(",").map(_.trim).toList.filterNot(s => s.forall(_.isDigit)))
  .flatMap{case ((key: String)::tail) => tail.map(t => (key, t))}.toDF("Key", "Value")
df.show()

这会给你这样的东西:

+----+----------+
| Key|     Value|
+----+----------+
|Key1|    foobar|
|Key1|    twenty|
|Key2|      impt|
|Key2|     sixty|
|Key3|helloworld|
|Key3|   seventy|
+----+----------+

在这里我也将它转换为数据帧,但是如果你想要一个rdd,你可以简单地跳过这一步。要使它工作,每行必须包含一个键,该键应位于字符串的第一个位置。

希望它有所帮助!

编辑:

使用的命令细分。

第一张地图遍历你的rdd中的每个字符串,对于每个字符串应用以下字符串(按顺序):

.split(",")
.map(_.trim)
.toList
.filterNot(s => s.forall(_.isDigit))

让我们以您的第一行为例:"Key1, foobar, 10, twenty, 20"。首先将行拆分为“,”,它将为您提供一个字符串数组Array("Key1", " foobar", " 10", " twenty", " 20")

接下来是map(_.trim)将修剪(删除单词之前和之后的空格)数组中的每个元素,数组也会转换为列表(稍后对于flatMap中的大小写匹配) :List("Key1", "foobar", "10", "twenty", "20")

filterNot将删除所有字符都是数字的所有字符串。这里forall检查每个角色是否满足这个条件。这将删除列表中的一些元素:List("Key1", "foobar", "twenty")

现在,完成过滤后,只有密钥后的分组仍然存在:

flatMap{case ((key: String)::tail) => tail.map(t => (key, t))}

这里key成为每一行列表的第一个元素,在它变为“Key1”之前的示例行之后。 tail只是列表的其余部分。然后,对于不是key值的每个元素,我们将其替换为元组(key, value)。换句话说,每个元素(第一个除外,即key)成为包含key及其自身的元组。这里使用flatMap,否则你会得到一个元组列表,而不是简单的元组。

最后一个是使用toDF("Key", "Value")将其转换为具有命名列的数据框,请注意,这需要在开头使用导入(import spark.implicits._)。