SparkSQL使用整理(二)

    整理下一些常用到的DataFream和DataSet的API,如何从RDD产生DataFrame和DataSet可以看下之前写的文章“SparkSQL使用整理(一)”。

    本文中读取的people.json文件就是spark例子中自带的people.json文件,本文接下来举的例子都是对这个json文件生成的DataFrame进行操作。

 

一些算子使用示例:

1.select 选取列

    $“age”是一个语法糖,如果没有$,那么“age”就代表一个字符串,加上之后就表示列了,可以对列进行操作,例如+1(建议别这么搞,列名都变了)。

    加载json文件的话,可以自行解析出Schema信息,不需要另外指定了。这个可能应该是和DataSource API有关,这个后续再确认。

 

2.filter/where 过滤数据

    还有一种写法是jsonDF.where($”age”>21),两种算子效果是一样的,where算子底层调用的就是filter,只不过where更加偏向SQL的写法。

 

3.groupBy 聚合

    可以按照一/多列进行聚合,此处的聚合之后会返回聚合的列以及count结果列。groupBy()之后,还可以跟不同算子以实现不同功能,如下所示:(注意:下面提到的算子,除了count,其他在使用时,指定的列必须是numeric column)

count(): 统计每个group中组员的个数

sum(): 计算分组中,指定列列值的总数

不指定具体列时,默认会计算所有的numeric column。例如:

groupBy(“age”).sum()

返回列:age sum(age) sum(money)

max():计算列的最大值

min():计算列的最小值

avg()/mean():计算列的平均值

agg():集成查询,可以一次性调用以上多个算子

 

4.sort/orderBy 排序

    两个算子效果是一样的,orderBy算子底层调用的就是sort。

默认null值是排在最后面,可以指定按照多列进行排序。

默认是升序排序(asc),建议还是在写的时候指定一下吧,代码理解起来也方便点。

 

5.distinct/dropDuplicates 单个DataFrame数据去重

 

6.intersect 取两个DataFrame交集

    两个DataFrame列的数量,列名,列的顺序必须相同,才能正确调用这个算子。

 

7.union 合并两个集合

    union和取交集的要求一样,两个DataFrame列的数量,列名,列的顺序必须相同

    实际上就是将两个DF头尾合在一起,变成一个DataFrame。

 

8.crossJoin 笛卡尔积

    笛卡尔积就是两个DataFrame每一行两两排列组合,如果匹配到之后列没有值,会被赋值为null。

    个人觉得,笛卡尔积的时间复杂度是n平方,不适合在大规模数据下应用,十来万撑死了,所以才会有了各种聚类的算法。

 

9.join 基于两个DataFrame的共同字段,将它们的行结合起来

除了笛卡尔积,SparkSQL还支持如下join操作:

使用示例代码如下:

DF1.join(DF2, Seq("col1", "col2"…), "inner")

和上面的笛卡尔积一样,如果列没有值,会被赋值为null。执行结果会返回两个DataFrame所有的列,例如:

但是,先返回左边的列还是右边的列,好像是不固定的…这个应该是和join内部的机制有关,后续有时间再看源码确认下

 

各种joinType实现的功能如下:

inner: 只连接匹配的行。

outer: 返回左右所有的行,如果某一行在另外一张表中没有匹配的行,用null代替。

leftouter: 返回左表所有的行和右边满足条件的行,如果右边没有匹配的行或者某一列没有,用null代替。

rightouter: 和上面的leftouter相反。

leftsemi: 返回左边的列,如果右边存在有匹配则返回,否则抛弃。IN/EXISTS的一种更高效的实现—hive,类似于:

Select A.Key A.VALUE from A where A.KEY IN (select B.Key from B)

leftanti: 返回左边的列,功能和上边的刚好相反。

 

各种Join图示如下:

 

 

10.joinWith 和join的区别是schema会不一样

支持`inner`, `outer`, `left_outer`, `right_outer`, `leftsemi`,本人目前还没用到过这个算子。按照源码的说明是为了保护原始数据的类型,特别是两个DataFrame有同名列的情况:

This type of join can be useful both for preserving type-safety with the original object types as well as working with relational data where either side of the join has column names in common.

 

11.coalesce/repartition 重分区

    调用这两个算子之后,返回的是一个新的DataSet[T],所以需要将返回结果赋值给新的变量。

    DataFrame的这两个算子区别在与是否真的触发shuffle

    因为coalesce的shuffle是false(窄依赖),所以coalesce只能用于减少partition的数量,因为增加Partition数量肯定是个宽依赖。

 

 

直接使用SQL语句:

使用SQL语句的时候需要向将DataFrame注册成类似数据库表的形式。

表有两种形式,一种是临时表,一种是全局表,两者的区别在于临时表只能在当前的SparkSession中使用,而全局表是绑定到系统数据库:global_temp中的,可以在所有的SparkSession中使用,但是在使用的时候,需要在表名前面加上限定名。

 

DataFrame与DataSet的区别

DataFrame就是DataSet[Row],所以DataSet的算子和DataFrame是一样。两者的区别在于,DataFrame对于Row(一行数据)中到底有哪些字段,每个字段分别又是什么类型是不知道的,只能通过getString或者getAs[类型]或者get(i)这样方式来获取特定字段的内容,而DataSet可以使用._1/._2之类的方式,访问起来比较方便(个人感觉是差不多),两者的区别差不多就是这样。

DataSet有groupByKey算子可以支持更加灵活的聚合操作。例如:

txtDF.groupByKey(x => x.getLong(1)).mapGroups((key,group) => group.map(****))

 

 

 

 

参考:

https://blog.csdn.net/moakun/article/details/80429267(SQL中的Join示例)

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值