2017-10-28 77 views
0

我是Scala/spark的新手。我正在研究Scala/Spark应用程序,该应用程序从配置单元表中选择几列,然后将其转换为可变映射,其中第一列是键,第二列是值。例如:将Dataframe转换为Scala可变映射不会产生相同数量的记录

+--------+--+ 
| c1  |c2| 
+--------+--+ 
|Newyork |1 | 
| LA |0 | 
|Chicago |1 | 
+--------+--+ 

将被转换为Scala.mutable.Map(Newyork -> 1, LA -> 0, Chicago -> 1)

这里是我的上述转换的代码:

val testDF = hiveContext.sql("select distinct(trim(c1)),trim(c2) from default.table where trim(c1)!=''") 
val testMap = scala.collection.mutable.Map(testDF.map(r => (r(0).toString,r(1).toString)).collectAsMap().toSeq: _*) 

我有与转换没有问题。然而,当我打印的行中Dataframe计数和Map的大小,我看到他们不匹配:

println("Map - "+testMap.size+" DataFrame - "+testDF.count) 
//Map - 2359806 DataFrame - 2368295 

我的想法是转换Dataframescollections并进行一些比较。我也从其他表中获取数据,但它们只是单列。我没有问题将它们转换为ArrayBuffer[String] - 计数匹配。

我不明白为什么我对testMap有问题。通常,DF中的计数行和Map的大小应该匹配,对不对?

是否因为记录太多?我如何在DF中获得与Map相同的记录数?

任何帮助,将不胜感激。谢谢。

回答

2

我相信计数不匹配是由Map中删除重复密钥(即城市名称)引起的。按照设计,Map通过删除所有重复项来保留唯一键。例如:

val testDF = Seq(
    ("Newyork", 1), 
    ("LA", 0), 
    ("Chicago", 1), 
    ("Newyork", 99) 
).toDF("city", "value") 

val testMap = scala.collection.mutable.Map(
    testDF.rdd.map(r => (r(0).toString, r(1).toString)). 
    collectAsMap().toSeq: _* 
) 
// testMap: scala.collection.mutable.Map[String,String] = 
// Map(Newyork -> 99, LA -> 0, Chicago -> 1) 

您可能想要使用不同的集合类型或在Map键中包含标识字段以使其唯一。根据您的数据处理需求,您可以通过groupBy还的数据汇总到一个像地图非数据帧象下面这样:

testDF.groupBy("city").agg(count("value").as("valueCount")) 

在这个例子中,总的valueCount应与原来的行数。

+0

谢谢你的答案!我想知道当我使用配置单元的'distinct'功能选择值时,怎么会有重复。后来我注意到这些值中有逗号,并使用'regexp_replace'来删除所有逗号。但我仍然不明白如何能有这么多重复首先。对此有何想法? – Hemanth

+0

无论您如何对列进行分组,标准SQL都会将“distinct”关键字应用于“select”子句中所有列的组合。换句话说,'select distinct(col_a),col_b ...'与'select distinct col_a,col_b ...'没有区别,因此只保证'col_a + col_b'是唯一的。 –

0

如果您将具有重复键的条目添加到地图中,重复项会自动删除。所以你应该比较的是:

println("Map - "+testMap.size+" DataFrame - "+testDF.select($"c1").distinct.count) 
相关问题