【Python笔记】Spark Sql max+structの作用

疑问:max+struct的作用?

test.map(x => tester(x._1, x._2, x._3, x._4, x._5))
    .toDS
    .select($"ac", $"sk", struct($"num1", struct($"time", $"num1")).as("grp"))
    .groupBy($"ac", $"sk")
    .agg(max($"grp")).show(false)

解答

Struct结构用于按字典顺序排序,从左往右地按字段比较。在上述例子中:

  1. 首先会比较第一顺位的字段num1
    • 如果num1不相等,那么会返回更大的num1
    • 如果num1相等,那么会跳到第二顺位struct($"time", $"num1")继续比较,先看第二顺位的第一个字段time
  1. 第二顺位的第二个字段num1,和第一顺位都是num1,而num1已经比较过了,所以第二顺位的第二个字段num1不会影响到最终的排序结果

原文链接🔗——

The StructTypes are compared lexicographically - field by field, from left to right and all fields have to recursively orderable. So in your case:

  1. It will compare the first element of the struct.
    • If the elements are not equal it will return the struct with higher value.
    • Otherwise it will proceed to the point 2.
  1. Since the second field is complex as well, it will repeat procedure
    from point 1 this time comparing time fields first.

Note that nested num1 can be evaluated on if top level num1 fields are equal, therefore it doesn’t affect the ordering in practice.

实战

首局/首条/最后一局/最后一条

一般来说,对于这类查询的方式有两种

  • 先通过MAX/MIN聚合函数找到最大/最小的那条数据,再通过该结果和原表做联合查询得到结果
  • 通过窗口函数row_number来查询结果

在Spark中对于struct的MAX/MIN函数会按照struct的第一个字段进行判断,因此提供了一个tricky的做法,MAX(STRUCT(xxxx)),这样的好处是,这是无需排序或关联,有更好的运行效率.

但这个方式只有Spark SQL有效


为了更直观的了解三个方法的差别,下面举一个例子

tsaccount_idkills
112
212

对于表match,希望得到account_id第一场比赛的记录,也就是输出

tsaccount_idkills
112
  • 方案1:
SELECT * 
FROM 
	(
		SELECT account_id, 
		 	   MIN(ts) ts 
		FROM match 
		GROUP BY account_id
	) t1 
JOIN 
	match 
USING(account_id,ts)
  • 方案2:
SELECT * 
FROM 
	(
		SELECT *, 
			   row_number() over(partition by account_id order by ts) rnum 
	    FROM match
	 ) t1 
WHERE rnum = 1
  • 使用Spark tricky:
SELECT account_id, 
	   first.* 
FROM 
	(
		SELECT account_id,
   			   MIN(STRUCT(ts, kills)) first 
   		FROM match 
   		GROUP BY account_id
   	) t1
Spark SQL的`struct`函数主要用于构建结构化数据的表示,特别是在DataFrame或Dataset中。它可以将一组键值对组合成一个类似Python字典、JavaScript对象或SQL表头的结构。 ### `struct`的基本语法: ```java struct(col1, col2, ...) ``` 这里的参数可以是列名或者是具体的值。如果传递的是列名,则会引用DataFrame或Dataset中的实际列;如果传递的是值,那么这些值将会被当作结构体的元素填充到新创建的数据集或者DataFrame中。 #### 示例: 假设我们有一个名为`people`的DataFrame,它有三列:`name`, `age`, 和 `city`。 我们可以使用`struct`函数来创建一个新的DataFrame,其中每一行都是一个包含这三列信息的对象结构: ```scala import org.apache.spark.sql.functions._ val people = spark.read.format("csv").option("header", "true").load("path/to/people.csv") val peopleWithStructs = people.select( expr("struct(name as PersonName, age as PersonAge, city as PersonCity) as person") ) ``` 在这个例子中: - `expr`是一个用于执行表达式的函数。 - `struct(name as PersonName, age as PersonAge, city as PersonCity)` 创建了一个新的结构体字段,其中每个列都被映射到了一个新字段上。 - `as person` 是一个新的字段名称,这个结构体会被放入`person`字段中。 ### 相关问题: 1. **如何在Spark SQL中使用struct处理缺失值?** 如果某个键对应的值在输入数据中不存在怎么办? 答案在于使用`whenNotNull`或者其他条件判断函数来检查键是否存在于输入字段中,并基于此选择填充或忽略特定值。 2. **如何将一个现有的DataFrame转换为只包含结构化的列?** 这种情况常见于需要对外提供更复杂数据结构的服务场景。 可以利用上述示例中展示的方法,在现有数据的基础上创建一个新的DataFrame,其中包含结构化的列。 3. **在Spark SQL中,当需要操作多个并不同步更新的struct字段时,应该注意哪些问题?** 需要注意的是,操作这些结构化数据时可能会涉及到并发问题和数据一致性问题。例如,如果试图同时修改多个相互依赖的结构化字段,可能需要考虑采用事务机制或其他同步策略来保证数据的一致性和完整性。 通过以上内容,你应该能够理解Spark SQL中`struct`的基本使用及其应用案例。此外,这些知识对于处理更复杂的结构化数据和优化查询性能非常有用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值