按键排序,但值使用Scala有多个元素

时间:2016-10-13 03:22:08

标签: arrays scala sorting apache-spark

我对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)
}

2 个答案:

答案 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))))