当前位置: 首页 > 知识库问答 >
问题:

查询复杂类型的Spark-SQL数据帧

缑勇锐
2023-03-14

如何查询具有复杂类型(如映射/数组)的RDD?例如,当我编写此测试代码时:

case class Test(name: String, map: Map[String, String])
val map = Map("hello" -> "world", "hey" -> "there")
val map2 = Map("hello" -> "people", "hey" -> "you")
val rdd = sc.parallelize(Array(Test("first", map), Test("second", map2)))

我认为语法应该是这样的:

sqlContext.sql("SELECT * FROM rdd WHERE map.hello = world")

sqlContext.sql("SELECT * FROM rdd WHERE map[hello] = world")

但我明白了

无法访问类型MapType(StringType,StringType,true)中的嵌套字段

组织。阿帕奇。火花sql。催化剂错误。包$TreeNodeException:未解析的属性

分别地

共有3个答案

干浩然
2023-03-14

这就是我所做的,它成功了

case class Test(name: String, m: Map[String, String])
val map = Map("hello" -> "world", "hey" -> "there")
val map2 = Map("hello" -> "people", "hey" -> "you")
val rdd = sc.parallelize(Array(Test("first", map), Test("second", map2)))
val rdddf = rdd.toDF
rdddf.registerTempTable("mytable")
sqlContext.sql("select m.hello from mytable").show

后果

+------+
| hello|
+------+
| world|
|people|
+------+
司寇祺
2023-03-14

一旦您将其转换为DF,u就可以简单地按照以下方式获取数据:

  val rddRow= rdd.map(kv=>{
    val k = kv._1
    val v = kv._2
    Row(k, v)
  })

val myFld1 =  StructField("name", org.apache.spark.sql.types.StringType, true)
val myFld2 =  StructField("map", org.apache.spark.sql.types.MapType(StringType, StringType), true)
val arr = Array( myFld1, myFld2)
val schema = StructType( arr )
val rowrddDF = sqc.createDataFrame(rddRow, schema)
rowrddDF.registerTempTable("rowtbl")  
val rowrddDFFinal = rowrddDF.select(rowrddDF("map.one"))
or
val rowrddDFFinal = rowrddDF.select("map.one")
敖涵容
2023-03-14

这取决于列的类型。让我们从一些虚拟数据开始:

import org.apache.spark.sql.functions.{udf, lit}
import scala.util.Try

case class SubRecord(x: Int)
case class ArrayElement(foo: String, bar: Int, vals: Array[Double])
case class Record(
  an_array: Array[Int], a_map: Map[String, String], 
  a_struct: SubRecord, an_array_of_structs: Array[ArrayElement])


val df = sc.parallelize(Seq(
  Record(Array(1, 2, 3), Map("foo" -> "bar"), SubRecord(1),
         Array(
           ArrayElement("foo", 1, Array(1.0, 2.0, 2.0)),
           ArrayElement("bar", 2, Array(3.0, 4.0, 5.0)))),
  Record(Array(4, 5, 6), Map("foz" -> "baz"), SubRecord(2),
         Array(ArrayElement("foz", 3, Array(5.0, 6.0)), 
               ArrayElement("baz", 4, Array(7.0, 8.0))))
)).toDF
df.registerTempTable("df")
df.printSchema

// root
// |-- an_array: array (nullable = true)
// |    |-- element: integer (containsNull = false)
// |-- a_map: map (nullable = true)
// |    |-- key: string
// |    |-- value: string (valueContainsNull = true)
// |-- a_struct: struct (nullable = true)
// |    |-- x: integer (nullable = false)
// |-- an_array_of_structs: array (nullable = true)
// |    |-- element: struct (containsNull = true)
// |    |    |-- foo: string (nullable = true)
// |    |    |-- bar: integer (nullable = false)
// |    |    |-- vals: array (nullable = true)
// |    |    |    |-- element: double (containsNull = false)

>

>

  • <代码>列。getItem方法

    df.select($"an_array".getItem(1)).show
    
    // +-----------+
    // |an_array[1]|
    // +-----------+
    // |          2|
    // |          5|
    // +-----------+
    

    蜂巢括号语法:

    sqlContext.sql("SELECT an_array[1] FROM df").show
    
    // +---+
    // |_c0|
    // +---+
    // |  2|
    // |  5|
    // +---+
    

    自定义项

    val get_ith = udf((xs: Seq[Int], i: Int) => Try(xs(i)).toOption)
    
    df.select(get_ith($"an_array", lit(1))).show
    
    // +---------------+
    // |UDF(an_array,1)|
    // +---------------+
    // |              2|
    // |              5|
    // +---------------+
    

    除了上面列出的方法之外,Spark还支持在复杂类型上运行的越来越多的内置函数。值得注意的例子包括高阶函数,如转换(SQL2.4、Scala 3.0、PySpark/SparkR 3.1):

    df.selectExpr("transform(an_array, x -> x + 1) an_array_inc").show
    // +------------+
    // |an_array_inc|
    // +------------+
    // |   [2, 3, 4]|
    // |   [5, 6, 7]|
    // +------------+
    
    import org.apache.spark.sql.functions.transform
    
    df.select(transform($"an_array", x => x + 1) as "an_array_inc").show
    // +------------+
    // |an_array_inc|
    // +------------+
    // |   [2, 3, 4]|
    // |   [5, 6, 7]|
    // +------------+
    

    filter(SQL2.4、Scala 3.0、Python/SparkR 3.1)

    df.selectExpr("filter(an_array, x -> x % 2 == 0) an_array_even").show
    // +-------------+
    // |an_array_even|
    // +-------------+
    // |          [2]|
    // |       [4, 6]|
    // +-------------+
    
    import org.apache.spark.sql.functions.filter
    
    df.select(filter($"an_array", x => x % 2 === 0) as "an_array_even").show
    // +-------------+
    // |an_array_even|
    // +-------------+
    // |          [2]|
    // |       [4, 6]|
    // +-------------+
    

    聚合(SQL2.4,Scala 3.0,PySpark/SparkR 3.1):

    df.selectExpr("aggregate(an_array, 0, (acc, x) -> acc + x, acc -> acc) an_array_sum").show
    // +------------+
    // |an_array_sum|
    // +------------+
    // |           6|
    // |          15|
    // +------------+
    
    import org.apache.spark.sql.functions.aggregate
    
    df.select(aggregate($"an_array", lit(0), (x, y) => x + y) as "an_array_sum").show
    // +------------+                                                                  
    // |an_array_sum|
    // +------------+
    // |           6|
    // |          15|
    // +------------+
    

    数组处理函数(array_*),如array_distinct(2.4):

    import org.apache.spark.sql.functions.array_distinct
    
    df.select(array_distinct($"an_array_of_structs.vals"(0))).show
    // +-------------------------------------------+
    // |array_distinct(an_array_of_structs.vals[0])|
    // +-------------------------------------------+
    // |                                 [1.0, 2.0]|
    // |                                 [5.0, 6.0]|
    // +-------------------------------------------+
    

    阵列最大值(2.4):

    import org.apache.spark.sql.functions.array_max
    
    df.select(array_max($"an_array")).show
    // +-------------------+
    // |array_max(an_array)|
    // +-------------------+
    // |                  3|
    // |                  6|
    // +-------------------+
    

    展平(2.4)

    import org.apache.spark.sql.functions.flatten
    
    df.select(flatten($"an_array_of_structs.vals")).show
    // +---------------------------------+
    // |flatten(an_array_of_structs.vals)|
    // +---------------------------------+
    // |             [1.0, 2.0, 2.0, 3...|
    // |             [5.0, 6.0, 7.0, 8.0]|
    // +---------------------------------+
    

    数组zip(2.4):

    import org.apache.spark.sql.functions.arrays_zip
    
    df.select(arrays_zip($"an_array_of_structs.vals"(0), $"an_array_of_structs.vals"(1))).show(false)
    // +--------------------------------------------------------------------+
    // |arrays_zip(an_array_of_structs.vals[0], an_array_of_structs.vals[1])|
    // +--------------------------------------------------------------------+
    // |[[1.0, 3.0], [2.0, 4.0], [2.0, 5.0]]                                |
    // |[[5.0, 7.0], [6.0, 8.0]]                                            |
    // +--------------------------------------------------------------------+
    

    array_union(2.4):

    import org.apache.spark.sql.functions.array_union
    
    df.select(array_union($"an_array_of_structs.vals"(0), $"an_array_of_structs.vals"(1))).show
    // +---------------------------------------------------------------------+
    // |array_union(an_array_of_structs.vals[0], an_array_of_structs.vals[1])|
    // +---------------------------------------------------------------------+
    // |                                                 [1.0, 2.0, 3.0, 4...|
    // |                                                 [5.0, 6.0, 7.0, 8.0]|
    // +---------------------------------------------------------------------+
    

    切片(2.4):

    import org.apache.spark.sql.functions.slice
    
    df.select(slice($"an_array", 2, 2)).show
    // +---------------------+
    // |slice(an_array, 2, 2)|
    // +---------------------+
    // |               [2, 3]|
    // |               [5, 6]|
    // +---------------------+
    

    映射(MapType)列

    >

  • 使用列。getField方法:

    df.select($"a_map".getField("foo")).show
    
    // +----------+
    // |a_map[foo]|
    // +----------+
    // |       bar|
    // |      null|
    // +----------+
    

    使用配置单元括号语法:

    sqlContext.sql("SELECT a_map['foz'] FROM df").show
    
    // +----+
    // | _c0|
    // +----+
    // |null|
    // | baz|
    // +----+
    

    使用带点语法的完整路径:

    df.select($"a_map.foo").show
    
    // +----+
    // | foo|
    // +----+
    // | bar|
    // |null|
    // +----+
    

    使用自定义项

    val get_field = udf((kvs: Map[String, String], k: String) => kvs.get(k))
    
    df.select(get_field($"a_map", lit("foo"))).show
    
    // +--------------+
    // |UDF(a_map,foo)|
    // +--------------+
    // |           bar|
    // |          null|
    // +--------------+
    

    越来越多的功能,如映射键(2.3)

    import org.apache.spark.sql.functions.map_keys
    
    df.select(map_keys($"a_map")).show
    // +---------------+
    // |map_keys(a_map)|
    // +---------------+
    // |          [foo]|
    // |          [foz]|
    // +---------------+
    

    map_values(2.3)

    import org.apache.spark.sql.functions.map_values
    
    df.select(map_values($"a_map")).show
    // +-----------------+
    // |map_values(a_map)|
    // +-----------------+
    // |            [bar]|
    // |            [baz]|
    // +-----------------+
    

    请查看SPARK-23899以获取详细列表。

    使用带点语法的完整路径的struct(StructType)列:

    >

  • 使用DataFrame API

    df.select($"a_struct.x").show
    
    // +---+
    // |  x|
    // +---+
    // |  1|
    // |  2|
    // +---+
    

    使用原始SQL

    sqlContext.sql("SELECT a_struct.x FROM df").show
    
    // +---+
    // |  x|
    // +---+
    // |  1|
    // |  2|
    // +---+
    

    结构数组中的字段可以使用点语法、名称和标准的方法访问:

    df.select($"an_array_of_structs.foo").show
    
    // +----------+
    // |       foo|
    // +----------+
    // |[foo, bar]|
    // |[foz, baz]|
    // +----------+
    
    sqlContext.sql("SELECT an_array_of_structs[0].foo FROM df").show
    
    // +---+
    // |_c0|
    // +---+
    // |foo|
    // |foz|
    // +---+
    
    df.select($"an_array_of_structs.vals".getItem(1).getItem(1)).show
    
    // +------------------------------+
    // |an_array_of_structs.vals[1][1]|
    // +------------------------------+
    // |                           4.0|
    // |                           8.0|
    // +------------------------------+
    

    用户定义类型(UDT)字段可以使用UDF访问。有关详细信息,请参阅Spark SQL引用UDT的属性。

    笔记:

    >

    df.select(explode($"an_array_of_structs")).show
    
    // +--------------------+
    // |                 col|
    // +--------------------+
    // |[foo,1,WrappedArr...|
    // |[bar,2,WrappedArr...|
    // |[foz,3,WrappedArr...|
    // |[baz,4,WrappedArr...|
    // +--------------------+
    

    点语法可以与通配符(*)结合使用,以选择(可能是多个)字段,而无需明确指定名称:

    df.select($"a_struct.*").show
    // +---+
    // |  x|
    // +---+
    // |  1|
    // |  2|
    // +---+
    

    可以使用get_json_objectfrom_json函数查询JSON列。有关详细信息,请参阅如何使用Spark DataFrames查询JSON数据列?

  •  类似资料:
    • 我试图用复杂类型查询spark sql数据帧,其中函数本身应该能够创建和表达式来为嵌套的复杂数据类型生成列数据帧。说 引用自查询SparkSQL具有复杂类型的DataFrame 用于提取地图类型查询可以是 现在如果我有 代替Map[String,String],如何创建一个udf,在数组的情况下接受名称或索引,并为复杂数据类型中的嵌套元素生成结果。假设现在我想查询a_map_new中包含的< co

    • 问题内容: 如何查询具有复杂类型(如地图/数组)的RDD?例如,当我编写此测试代码时: 我认为语法应该是这样的: 或者 但是我明白了 无法访问类型为MapType(StringType,StringType,true)的嵌套字段 和 org.apache.spark.sql.catalyst.errors.package $ TreeNodeException:无法解析的属性 分别。 问题答案:

    • 数字类型 ByteType:代表一个字节的整数。范围是-128到127 ShortType:代表两个字节的整数。范围是-32768到32767 IntegerType:代表4个字节的整数。范围是-2147483648到2147483647 LongType:代表8个字节的整数。范围是-9223372036854775808到9223372036854775807 FloatType:代表4字节的单

    • 当我跑步时 我明白了 有没有其他方法将字符串格式化为日期?或者我应该继续这样做并进行一些修改。我已经有2列数据类型varchar,日期的格式为(mm/dd/yyyy)。我需要在它们之间执行减法以获得天数。当它是varchar格式时,不能这样做。

    • 如何将这个复杂的sql语句更改为JPQL? 这是否可以在JPQL表单中显示?

    • 我使用Spring引导和Spring数据JPA。它工作得很好但是!我需要使用复杂的本地查询从Oracle数据库(源数据从SAP ERP)。 假设查询包含5个joned表(一个键或组合键)。我可以使用很多参数。 解决方案: 1)由于耗时,使用JPA为该查询编写新查询是不真实的。创建表之间的所有键关系似乎很复杂。 2)为了运行这些查询,我使用JDBC。这很容易,因为我准备了本机查询。但我深信这种做法是