Scala 如何使用映射对象列表创建Spark SQL数据框

Scala 如何使用映射对象列表创建Spark SQL数据框,scala,apache-spark,dataframe,apache-spark-sql,bigdata,Scala,Apache Spark,Dataframe,Apache Spark Sql,Bigdata,我在Scala列表中有多个Map[String,String]。例如: map1 = Map("EMP_NAME" -> “Ahmad”, "DOB" -> “01-10-1991”, "CITY" -> “Dubai”) map2 = Map("EMP_NAME" -> “Rahul”, "DOB" -> “06-12-1991”, "CITY" -> “Mumbai”) map3 = Map("EMP_NAME" -> “John”, "DOB" -

我在Scala列表中有多个Map[String,String]。例如:

map1 = Map("EMP_NAME" -> “Ahmad”, "DOB" -> “01-10-1991”, "CITY" -> “Dubai”)
map2 = Map("EMP_NAME" -> “Rahul”, "DOB" -> “06-12-1991”, "CITY" -> “Mumbai”)
map3 = Map("EMP_NAME" -> “John”, "DOB" -> “11-04-1996”, "CITY" -> “Toronto”)
list = List(map1, map2, map3)
现在我想创建一个数据帧,如下所示:

EMP_NAME    DOB             CITY
Ahmad       01-10-1991      Dubai
Rahul       06-12-1991      Mumbai
John        11-04-1996      Toronto

我如何做到这一点?

您可以这样做:

import spark.implicits._

val df = list
  .map( m => (m.get("EMP_NAME"),m.get("DOB"),m.get("CITY")))
  .toDF("EMP_NAME","DOB","CITY")

df.show()

+--------+----------+-------+
|EMP_NAME|       DOB|   CITY|
+--------+----------+-------+
|   Ahmad|01-10-1991|  Dubai|
|   Rahul|06-12-1991| Mumbai|
|    John|11-04-1996|Toronto|
+--------+----------+-------+

您可以这样做:

import spark.implicits._

val df = list
  .map( m => (m.get("EMP_NAME"),m.get("DOB"),m.get("CITY")))
  .toDF("EMP_NAME","DOB","CITY")

df.show()

+--------+----------+-------+
|EMP_NAME|       DOB|   CITY|
+--------+----------+-------+
|   Ahmad|01-10-1991|  Dubai|
|   Rahul|06-12-1991| Mumbai|
|    John|11-04-1996|Toronto|
+--------+----------+-------+

稍微不太具体的方法,例如:

val map1 = Map("EMP_NAME" -> "Ahmad", "DOB" -> "01-10-1991", "CITY" -> "Dubai")
val map2 = Map("EMP_NAME" -> "John",  "DOB" -> "01-10-1992", "CITY" -> "Mumbai")
///...
val list = List(map1, map2) // map3, ...
val RDDmap = sc.parallelize(list)

// Get cols dynamically
val cols = RDDmap.take(1).flatMap(x=> x.keys)

// Map is K,V like per Map entry
val df = RDDmap.map{ value=>
                     val list=value.values.toList
                     (list(0), list(1), list(2))
       }.toDF(cols:_*) // dynamic column names assigned

df.show(false)
返回:

+--------+----------+------+
|EMP_NAME|DOB       |CITY  |
+--------+----------+------+
|Ahmad   |01-10-1991|Dubai |
|John    |01-10-1992|Mumbai|
+--------+----------+------+
或者回答你的子问题,如下所示——至少我认为这是你要问的,但可能不是:

val RDDmap = sc.parallelize(List(
   Map("EMP_NAME" -> "Ahmad", "DOB" -> "01-10-1991", "CITY" -> "Dubai"),
   Map("EMP_NAME" -> "John",  "DOB" -> "01-10-1992", "CITY" -> "Mumbai")))
   ...

// Get cols dynamically
val cols = RDDmap.take(1).flatMap(x=> x.keys)

// Map is K,V like per Map entry
val df = RDDmap.map{ value=>
                 val list=value.values.toList
                 (list(0), list(1), list(2))
       }.toDF(cols:_*) // dynamic column names assigned

当然,您可以动态地构建一个列表,但仍然需要分配贴图元素。看见我只要从文件中读出来就可以了

稍微不太具体的方法,例如:

val map1 = Map("EMP_NAME" -> "Ahmad", "DOB" -> "01-10-1991", "CITY" -> "Dubai")
val map2 = Map("EMP_NAME" -> "John",  "DOB" -> "01-10-1992", "CITY" -> "Mumbai")
///...
val list = List(map1, map2) // map3, ...
val RDDmap = sc.parallelize(list)

// Get cols dynamically
val cols = RDDmap.take(1).flatMap(x=> x.keys)

// Map is K,V like per Map entry
val df = RDDmap.map{ value=>
                     val list=value.values.toList
                     (list(0), list(1), list(2))
       }.toDF(cols:_*) // dynamic column names assigned

df.show(false)
import org.apache.spark.SparkContext
import org.apache.spark.sql._
import org.apache.spark.sql.types.{StringType, StructField, StructType}

object DataFrameTest2 extends Serializable {
  var sparkSession: SparkSession = _
  var sparkContext: SparkContext = _
  var sqlContext: SQLContext = _

  def main(args: Array[String]): Unit = {
    sparkSession = SparkSession.builder().appName("TestMaster").master("local").getOrCreate()
    sparkContext = sparkSession.sparkContext

    val sqlContext = new org.apache.spark.sql.SQLContext(sparkContext)

    val map1 = Map("EMP_NAME" -> "Ahmad", "DOB" -> "01-10-1991", "CITY" -> "Dubai")
    val map2 = Map("EMP_NAME" -> "Rahul", "DOB" -> "06-12-1991", "CITY" -> "Mumbai")
    val map3 = Map("EMP_NAME" -> "John", "DOB" -> "11-04-1996", "CITY" -> "Toronto")
    val list = List(map1, map2, map3)

    //create your rows
    val rows = list.map(m => Row(m.values.toSeq:_*))

    //create the schema from the header
    val header = list.head.keys.toList
    val schema = StructType(header.map(fieldName => StructField(fieldName, StringType, true)))

    //create your rdd
    val rdd = sparkContext.parallelize(rows)

    //create your dataframe using rdd
    val df = sparkSession.createDataFrame(rdd, schema)
    df.show()
  }
}
返回:

+--------+----------+------+
|EMP_NAME|DOB       |CITY  |
+--------+----------+------+
|Ahmad   |01-10-1991|Dubai |
|John    |01-10-1992|Mumbai|
+--------+----------+------+
或者回答你的子问题,如下所示——至少我认为这是你要问的,但可能不是:

val RDDmap = sc.parallelize(List(
   Map("EMP_NAME" -> "Ahmad", "DOB" -> "01-10-1991", "CITY" -> "Dubai"),
   Map("EMP_NAME" -> "John",  "DOB" -> "01-10-1992", "CITY" -> "Mumbai")))
   ...

// Get cols dynamically
val cols = RDDmap.take(1).flatMap(x=> x.keys)

// Map is K,V like per Map entry
val df = RDDmap.map{ value=>
                 val list=value.values.toList
                 (list(0), list(1), list(2))
       }.toDF(cols:_*) // dynamic column names assigned


当然,您可以动态地构建一个列表,但仍然需要分配贴图元素。看见我只要从文件中读出来就可以了

谢谢。还有一点:如何动态循环这个列表0,列表1,列表2?我的意思是,与其硬编码1、2和3,它可以从类似listi的东西中获取吗?更新的答案实际上是另一个答案。请接受其他情况。@BluePhantom,我不会假设映射的.key和.value的结果将始终保持KV成对顺序。@LeoC请详细说明如果m=Map1->a,2->b,…,我认为假设m.key和m.value的元素一定会像1,2。。。和a,b,…,因为映射和集合都不保持顺序。谢谢你。还有一点:如何动态循环这个列表0,列表1,列表2?我的意思是,与其硬编码1、2和3,它可以从类似listi的东西中获取吗?更新的答案实际上是另一个答案。请接受其他情况。@BluePhantom,我不会假设映射的.key和.value的结果将始终保持KV成对顺序。@LeoC请详细说明如果m=Map1->a,2->b,…,我认为假设m.key和m.value的元素一定会像1,2。。。和a,b,…,因为Map和Set都不保留顺序。协议是您选择其他答案中的一个作为正确答案,除非没有其他人提供或您认为它们不合适。我认为在这种情况下,所有答案都是正确的。你的也是第一个。不确定如何标记多个正确答案。另外,我只是在寻找最通用的解决方案。在real中,我将为大约40多个列动态创建和填充数据集。顺便说一句,我非常感谢您提供的解决方案:那么请接受它,因为它更灵活,对于40 cols方法,。但你可以投票。选择权在你。我多次高估了你的答案。但我得到的信息是:谢谢你的反馈!声誉低于15的人所投的票将被记录,但不会改变公开显示的帖子分数:看来我需要先建立自己的声誉:对,就是这样。然后,你可以只接受答案,如果你认为这是最好的,那么就这样做,否则就选择另一个。协议是你选择其他答案中的一个作为正确答案,除非没有其他人提供,或者你觉得它们不合适。我认为在这种情况下,所有答案都是正确的。你的也是第一个。不确定如何标记多个正确答案。另外,我只是在寻找最通用的解决方案。在real中,我将为大约40多个列动态创建和填充数据集。顺便说一句,我非常感谢您提供的解决方案:那么请接受它,因为它更灵活,对于40 cols方法,。但你可以投票。选择权在你。我多次高估了你的答案。但我得到的信息是:谢谢你的反馈!声誉低于15的人所投的票将被记录,但不会改变公开显示的帖子分数:看来我需要先建立自己的声誉:对,就是这样。然后你只能接受答案,如果你认为它是最好的,那么就这样做,否则就选择另一个。
import org.apache.spark.SparkContext
import org.apache.spark.sql._
import org.apache.spark.sql.types.{StringType, StructField, StructType}

object DataFrameTest2 extends Serializable {
  var sparkSession: SparkSession = _
  var sparkContext: SparkContext = _
  var sqlContext: SQLContext = _

  def main(args: Array[String]): Unit = {
    sparkSession = SparkSession.builder().appName("TestMaster").master("local").getOrCreate()
    sparkContext = sparkSession.sparkContext

    val sqlContext = new org.apache.spark.sql.SQLContext(sparkContext)

    val map1 = Map("EMP_NAME" -> "Ahmad", "DOB" -> "01-10-1991", "CITY" -> "Dubai")
    val map2 = Map("EMP_NAME" -> "Rahul", "DOB" -> "06-12-1991", "CITY" -> "Mumbai")
    val map3 = Map("EMP_NAME" -> "John", "DOB" -> "11-04-1996", "CITY" -> "Toronto")
    val list = List(map1, map2, map3)

    //create your rows
    val rows = list.map(m => Row(m.values.toSeq:_*))

    //create the schema from the header
    val header = list.head.keys.toList
    val schema = StructType(header.map(fieldName => StructField(fieldName, StringType, true)))

    //create your rdd
    val rdd = sparkContext.parallelize(rows)

    //create your dataframe using rdd
    val df = sparkSession.createDataFrame(rdd, schema)
    df.show()
  }
}