繁体   English   中英

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

[英]Sort by a key, but value has more than one element using Scala

我对Spark上的Scala还是很陌生,想知道如何创建键值对,并且键具有多个元素。 例如,我有这个数据集用于婴儿的名字:

年,名称,县,编号

2000年,约翰·金斯,50岁

2000,BOB,KINGS,40

2000年,玛丽,NASSAU,60岁

2001,约翰·金斯,14岁

2001,简,金斯,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)
}

您可以使用spark-csv和Dataframe API。 如果您使用的是新版本的Spark(2.0),则略有不同。 Spark 2.0具有基于spark-csv的本地csv数据源。

使用spark-csv将您的csv文件加载到数据帧中。

 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|
+------+-----------+

这是您要达到的目标吗?

请注意agg()函数所需的import org.apache.spark.sql.functions._

有关Dataframes API的更多信息

编辑

为了正确输出:

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|
+------+----+---------------+

这是使用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))))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM