给出这样的数据:
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
而不是创建架构但仍需要知道如何过滤键/值对
答案 0 :(得分:0)
正如您所提到的,解决问题的一种方法是将Character.isDigit
与split
和flatMap
一起使用。以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._
)。