将数据帧转换为scala可变映射不会产生相同数量的记录

将数据帧转换为scala可变映射不会产生相同数量的记录,scala,dictionary,apache-spark,dataframe,collections,Scala,Dictionary,Apache Spark,Dataframe,Collections,我是Scala/spark的新手。我正在开发Scala/Spark应用程序,它从配置单元表中选择两列,然后将其转换为可变映射,第一列是键,第二列是值。例如: +--------+--+ | c1 |c2| +--------+--+ |Newyork |1 | | LA |0 | |Chicago |1 | +--------+--+ val testDF = Seq( ("Newyork", 1), ("LA", 0), ("Chicago", 1), ("

我是Scala/spark的新手。我正在开发Scala/Spark应用程序,它从配置单元表中选择两列,然后将其转换为可变映射,第一列是键,第二列是值。例如:

+--------+--+
| c1     |c2|
+--------+--+
|Newyork |1 |
|   LA   |0 |
|Chicago |1 | 
+--------+--+
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)
将转换为Scala.mutable.MapNewyork->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: _*)
我对转换没有问题。但是,当我打印数据框中的行数和映射的大小时,我发现它们不匹配:

println("Map - "+testMap.size+" DataFrame - "+testDF.count)
//Map - 2359806 DataFrame - 2368295
我的想法是将数据帧转换为集合并执行一些比较。我也从其他表中提取数据,但它们只是单列。我可以将它们转换为ArrayBuffer[String]——计数匹配

我不明白为什么我对测试图有问题。通常,DF中的计数行和映射的大小应该匹配,对吗

是因为记录太多吗?如何将DF中相同数量的记录输入地图


任何帮助都将不胜感激。多谢各位

我认为计数不匹配是因为消除了重复的键,即地图中的城市名称。根据设计,Map通过删除所有重复项来维护唯一键。例如:

+--------+--+
| c1     |c2|
+--------+--+
|Newyork |1 |
|   LA   |0 |
|Chicago |1 | 
+--------+--+
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)
您可能希望使用不同的集合类型,或者在映射键中包含标识字段以使其唯一。根据您的数据处理需要,您还可以通过groupBy将数据聚合到类似地图的数据框中,如下所示:

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

在本例中,valueCount的总数应与原始行数匹配。

我认为计数不匹配是由于消除了重复的键,即地图中的城市名称造成的。根据设计,Map通过删除所有重复项来维护唯一键。例如:

+--------+--+
| c1     |c2|
+--------+--+
|Newyork |1 |
|   LA   |0 |
|Chicago |1 | 
+--------+--+
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)
您可能希望使用不同的集合类型,或者在映射键中包含标识字段以使其唯一。根据您的数据处理需要,您还可以通过groupBy将数据聚合到类似地图的数据框中,如下所示:

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

在本例中,valueCount的总数应与原始行数匹配。

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

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

如果向地图添加具有重复密钥的条目,则会自动删除重复项。所以你应该比较的是:

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

谢谢你的回答!我想知道,当我使用配置单元的distinct函数选择值时,怎么会有重复项。我后来注意到值中有逗号,并使用regexp_replace删除所有逗号。但我还是不明白为什么一开始会有这么多的重复。对此有何想法?标准SQL将关键字distinct应用于select子句中所有列的组合,而不管您如何对列进行分组。换句话说,选择distinctcol\u a、col\u b。。。与选择不同的列a、列b没有区别。。。因此,只保证col_a+col_b是唯一的。谢谢您的回答!我想知道,当我使用配置单元的distinct函数选择值时,怎么会有重复项。我后来注意到值中有逗号,并使用regexp_replace删除所有逗号。但我还是不明白为什么一开始会有这么多的重复。对此有何想法?标准SQL将关键字distinct应用于select子句中所有列的组合,而不管您如何对列进行分组。换句话说,选择distinctcol\u a、col\u b。。。与选择不同的列a、列b没有区别。。。因此,只有保证列a+b是唯一的。