在保持多个值的同时计算键的出现次数

时间:2018-03-15 01:12:40

标签: scala apache-spark

我在计算密钥出现次数时遇到了一些麻烦,同时还保留了几个值。

通常我会这样做:

val a = file1.map(x => (x, 1)).reduceByKey(_ + _)

,它给出了每个键的出现次数。

但是,我还希望在计算密钥出现次数的同时保留每次出现密钥的值。像这样:

val a = file1.map(x => (x(1), (x(2), 1)).reduceByKey{case (x,y) => (x._1, y._1, x._2+y._2)}

例如:如果密钥x(1)是一个国家而x(2)是一个城市,我想保留一个国家/地区的所有城市,并了解一个国家/地区有多少个城市

3 个答案:

答案 0 :(得分:0)

将城市的数量与其列表保持在一起是一件复杂而多余的事情。您可以收集所有城市,并在最后添加尺寸:

使用数据框接口当然更容易(假设数据框为(key:Int, city:String)

import org.apache.spark.sql.{ functions => f}
import spark.implicits._
df.groupBy($"key").
   agg(f.collect_set($"city").as("cities")).
   withColumn("ncities", f.size($"cities"))

但你可以用raw rdd做类似的事情(我在(id,city)的输入元组中假设)

rdd.map{ x => (x(0),Set(x(1)))}.
   reduceByKey{ case(x,y) => x ++ y }.
   map { case(x,y:Set[_]) => (x,y, y.size)}

答案 1 :(得分:0)

在这种情况下,我建议使用数据框而不是RDD,并使用groupByagg方法。

您可以使用toDF函数轻松将RDD转换为数据框,只需确保先输入含义。假设RDD有两列的示例:

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

val df = rdd.toDF("country", "city")

然后使用groupBy并汇总您想要的值。

df.groupBy("country").agg(collect_set($"city").as("cities"), count($"city").as("count"))

答案 2 :(得分:0)

我建议您使用dataframes以及dataframes 优化且易于使用而不是rdds

但是,如果您想了解reduceByKey功能(例如保留其他信息,如您所说的城市信息),那么您可以执行以下操作

假设您有rdd

val rdd = sc.parallelize(Seq(
  ("country1", "city1"),
  ("country1", "city2"),
  ("country1", "city3"),
  ("country1", "city3"),
  ("country2", "city1"),
  ("country2", "city2")
))

您尝试的reducyByKey需要进行一些修改

rdd.map(x => (x._1, (Set(x._2), 1)))  //I have used Set to get distinct cities (you can use list or arrays or any other collection
  .reduceByKey((x,y)=> (x._1 ++ y._1, x._2 + y._2))  //cities are also summed and counts are also summed

应该给你

(country2,(Set(city1, city2),2))
(country1,(Set(city1, city2, city3),4))

我希望答案很有帮助

如果您想详细了解reduceByKey,可以查看我的detailed answer