我对Spark上的Scala很新,并想知道如何创建键值对,键具有多个元素。例如,我有这个婴儿名字的数据集:
年份,姓名,县,号码
2000,JOHN,KINGS,50
2000,BOB,KINGS,40
2000,MARY,NASSAU,60
2001,JOHN,KINGS,14
2001,JANE,KINGS,30
2001,BOB,NASSAU,45
我想找到每个县最常发生的事情,无论一年如何。我该怎么做呢?
我使用循环完成了这个。请参阅下文。但我想知道是否有更短的方法来利用Spark和Scala二元性。 (即我可以减少计算时间吗?)
val names = sc.textFile("names.csv").map(l => l.split(","))
val uniqueCounty = names.map(x => x(2)).distinct.collect
for (i <- 0 to uniqueCounty.length-1) {
val county = uniqueCounty(i).toString;
val eachCounty = names.filter(x => x(2) == county).map(l => (l(1),l(4))).reduceByKey((a,b) => a + b).sortBy(-_._2);
println("County:" + county + eachCounty.first)
}
答案 0 :(得分:0)
您可以使用spark-csv和Dataframe API。如果您使用的是新版本的Spark(2.0),则会略有不同。 Spark 2.0有一个基于spark-csv的原生csv数据源。
使用spark-csv将csv文件加载到Dataframe中。
val df = sqlContext.read.format("com.databricks.spark.csv")
.option("header", "true")
.option("inferSchema", "true")
.load(new File(getClass.getResource("/names.csv").getFile).getAbsolutePath)
df.show
提供输出:
+----+----+------+------+
|Year|Name|County|Number|
+----+----+------+------+
|2000|JOHN| KINGS| 50|
|2000| BOB| KINGS| 40|
|2000|MARY|NASSAU| 60|
|2001|JOHN| KINGS| 14|
|2001|JANE| KINGS| 30|
|2001| BOB|NASSAU| 45|
+----+----+------+------+
DataFrames使用一组操作进行结构化数据操作。您可以使用一些基本操作来成为您的结果。
import org.apache.spark.sql.functions._
df.select("County","Number").groupBy("County").agg(max("Number")).show
提供输出:
+------+-----------+
|County|max(Number)|
+------+-----------+
|NASSAU| 60|
| KINGS| 50|
+------+-----------+
这是你想要实现的目标吗?
请注意import org.apache.spark.sql.functions._
功能所需的agg()
。
有关Dataframes API的更多information
修改强>
正确输出:
df.registerTempTable("names")
//there is probably a better query for this
sqlContext.sql("SELECT * FROM (SELECT Name, County,count(1) as Occurrence FROM names GROUP BY Name, County ORDER BY " +
"count(1) DESC) n").groupBy("County", "Name").max("Occurrence").limit(2).show
提供输出:
+------+----+---------------+
|County|Name|max(Occurrence)|
+------+----+---------------+
| KINGS|JOHN| 2|
|NASSAU|MARY| 1|
+------+----+---------------+
答案 1 :(得分:0)
以下是使用RDD的解决方案。我假设你需要每个县最高的名字。
val data = Array((2000, "JOHN", "KINGS", 50),(2000, "BOB", "KINGS", 40),(2000, "MARY", "NASSAU", 60),(2001, "JOHN", "KINGS", 14),(2001, "JANE", "KINGS", 30),(2001, "BOB", "NASSAU", 45))
val rdd = sc.parallelize(data)
//Reduce the uniq values for county/name as combo key
val uniqNamePerCountyRdd = rdd.map(x => ((x._3,x._2),x._4)).reduceByKey(_+_)
// Group names per county.
val countyNameRdd = uniqNamePerCountyRdd.map(x=>(x._1._1,(x._1._2,x._2))).groupByKey()
// Sort and take the top name alone per county
countyNameRdd.mapValues(x => x.toList.sortBy(_._2).take(1)).collect
输出:
res8: Array[(String, List[(String, Int)])] = Array((KINGS,List((JANE,30))), (NASSAU,List((BOB,45))))