学习一门开源技术一般有两种入门方法,一种是去看官网文档,比如Getting Started - Spark 3.2.0 Documentation (apache.org),另一种是去看官网的例子,也就是%SPARK_HOME%\examples下面的代码。打开IDEA,选择File-Open...

跟前面文章中方法一样导入jars目录到classpath。

Spark解析json字符串

第一个例子是读取并解析Json。这个例子的结果让我有些震惊,先上代码:

  1. public
    static
    void main(String[] args) {
  2.     SparkSession session = SparkSession.builder().master("local[1]").appName("SparkSqlApp").getOrCreate();
  3.  
  4.     Dataset<Row> json = session.read().json("spark-core/src/main/resources/people.json");
  5.     json.show();
  6. }

让我惊讶的是文件的内容。例子里面的文件是三个大括号并列,文件扩展名是.json,由于没有中括号,所以格式是错的:

  1. {"name":"Michael"}
  2. {"name":"Andy", "age":30}
  3. {"name":"Justin", "age":19}

但是spark解析出来了:

于是我把文件改成下面这样向看下结果

  1. [{"name":"Michael"},
  2. {"name":"Andy", "age":30},
  3. {"name":"Justin", "age":19}
  4. ]

你猜输出是什么?

显然,spark没有解析出第一行,而且把第4行也解析了。这也说明了为什么样例的文件可以解析:首先跟文件扩展名是没啥关系的,另外spark是按行解析,只要考虑这一行是否符合解析要求就可以,行末可以有逗号。所以把文件改成下面也是可以的

  1. {"name":"Michael"},
  2. {"name":"Andy", "age":30},..
  3. {"name":"Justin", "age":19}

第一行后面有逗号,第二行后面还有两个点。

SQL 查询

在之前的例子中,读取文件返回的是Dataset<String>,因为之前确实是读取的文件内容。现在使用json()方法返回的是DataFrame,数据是经过spark处理过的。

DataFrame提供了一些好用的方法,用的最多的就是show()。它主要用于调试,可以把数据以表格形式打印。spark确实给DataFrame生成了表结构,可以通过printSchema()方法查看

不但有字段名,还有字段类型,还有是否可空(好像都能空)。

DF还提供了类似于sql查询的方法,比如select()/groupBy(),和where类似的filter()等:

这里我们首先给年龄字段+1,并通过别名(相等于SQL里的AS)让他覆盖之前的字段,然后查询比19大的记录,最后根据年龄分组汇总。

如果我们把新字段不覆盖原字段呢?你猜是执行报错还是啥结果?

That's all?当然不是,Spark提供了更强大的SQL操作:视图

View

视图分临时视图和全局视图。临时视图时会话级别的,会话结束了视图就没了;全局视图时应用级别的,只要Spark应用不停,视图就可以跨会话使用。

可见临时视图和全局视图可以叫一样的名字,它们的内容互不干扰。因为要访问全局视图需要通过global_temp库。不信你可以这样试一下

  1. Dataset<Row> group = json.select(col("name"), col("age").plus(1).alias("age1"))
  2.         .filter(col("age").gt(19))
  3.         .groupBy("age1")
  4.         .count();
  5.  
  6. group.createOrReplaceTempView("people");
  7. json.createOrReplaceGlobalTempView("people");
  8. Dataset<Row> temp = session.sql("select * from people");
  9. Dataset<Row> global = session.sql("select * from global_temp.people");
  10. Dataset<Row> global1 = session.newSession().sql("select * from global_temp.people");
  11. temp.show();
  12. global.show();
  13. global1.show();

Dataset

我们已经跟Dataset打过不少交道了,这里再稍晚多说一点点。实际上如果你是自己摸索而不是完全看我写的,下面这些内容估计都已经探索出来了。

1 转换自DF

DF是无类型的,Dataset是有类型的。如果要把无类型的转成有类型的,就需要提供一个类型定义,就像mysql表和Java的PO一样。

先来定义Java类:

  1. public
    class Person implements Serializable {
  2.   private String name;
  3.   private
    long age;
  4.  
  5.   public String getName() {
  6.     return name;
  7.   }
  8.  
  9.   public
    void setName(String name) {
  10.     this.name = name;
  11.   }
  12.  
  13.   public
    long getAge() {
  14.     return age;
  15.   }
  16.  
  17.   public
    void setAge(long age) {
  18.     this.age = age;
  19.   }
  20. }

这个类必须实现序列化接口,原因在前面也说过了。

接下来把读入json的DataFrame转成Dataset:

之前都是使用Encoders内置的编码器,这里通过bean()方法生成我们自定义类的编码器,然后传给DF的as()方法就转成了Dataset。

既然转成了强类型的Dataset,那能把每一个对象拿出来吗?给Person类增加toString方法,然后遍历Dataset:

结果报错了竟然:已经生成了集合,却不能访问元素?

报错原因很简单:我们类中的age是原始数据类型,但是实际数据有一个null。把long age改成Long age即可:

但是为什么会这样呢?!~我猜是因为as方法用的编码器(序列化工具)和foreach用到的解码器不匹配,spark的编码器不要求数据符合Java编译规则。

来自Java集合

目前我们掌握了通过读取文件(textFile(path))、转化其他Dataset(map/flatMap)和转换DF来生成Dataset,如果已经有一堆数据了,也可以直接创建。

SparkSession重载了大量根据数据集生成Dataset和DataFrame的方法,可以自由选择:

所以我们创建一个List来生成,只能是List,不能是Collection

神奇的是原本应该一样的代码,执行的时候有一个报错。这个算Java实现的BUG吧,原因参考Java中普通lambda表达式和方法引用本质上有什么区别? - RednaxelaFX的回答 - 知乎

https://www.zhihu.com/question/51491241/answer/126232275

转自RDD

RDD 在Java环境下叫JavaRDD。它也是数据集,可以和Dataset/DataFrame互转。这里不说了,有兴趣可以探索。

Spark3学习【基于Java】3. Spark-Sql常用API的更多相关文章

  1. Spark SQL 编程API入门系列之SparkSQL的依赖

    不多说,直接上干货! 不带Hive支持 <dependency> <groupId>org.apache.spark</groupId> <artifactI ...

  2. Java之String类常用API

    目录 Java之String类常用API char chatAt(int index) int length() char[] toCharArray() String(char value[]) S ...

  3. oracle学习笔记(九) SQL常用函数说明以及使用

    SQL常用函数说明以及使用 以下补充以下常用的函数,更多的请看oracle函数API文档 to_char to_char(8.58,'9.99') to_char(8.50,'9.00') to_ch ...

  4. spark sql 常用语句

    在spark dataFrame数据结构里面使用sql语句查询数据 (因为是RDD和dataFrame数据是只读的,所以不能做修改,删除操作.) 首先将文本数据转换为DataFrame数据格式 有两种 ...

  5. Spark SQL 编程API入门系列之SparkSQL数据源

    不多说,直接上干货! SparkSQL数据源:从各种数据源创建DataFrame 因为 spark sql,dataframe,datasets 都是共用 spark sql 这个库的,三者共享同样的 ...

  6. Spark SQL 编程API入门系列之Spark SQL支持的API

    不多说,直接上干货! Spark SQL支持的API SQL DataFrame(推荐方式,也能执行SQL) Dataset(还在发展) SQL SQL 支持basic SQL syntax/Hive ...

  7. Spark SQL 编程API入门系列之SparkSQL的入口

    不多说,直接上干货! SparkSQL的入口:SQLContext SQLContext是SparkSQL的入口 val sc: SparkContext val sqlContext = new o ...

  8. Spark SQL 编程API入门系列之Spark SQL的作用与使用方式

    不多说,直接上干货! Spark程序中使用SparkSQL 轻松读取数据并使用SQL 查询,同时还能把这一过程和普通的Python/Java/Scala 程序代码结合在一起. CLI---Spark ...

  9. Java(22)常用API一

    1 API 1.1 API概述 什么是API ​ API (Application Programming Interface) :应用程序编程接口 java中的API ​ 指的就是 JDK 中提供的 ...

随机推荐

  1. Linux 系统 Oracle 11g 修改监听端口

    1.查看监听:lsnrctl status 2.停止监听:lsnrctl stop 3.修改oracle安装目录的下的配置文件listener.ora:一般路径为自己Oracle安装目录+/app/o ...

  2. Spring:所有依赖项注入的类型

    一.前言 Spring文档严格只定义了两种类型的注入:构造函数注入和setter注入.但是,还有更多的方式来注入依赖项,例如字段注入,查找方法注入.下面主要是讲使用Spring框架时可能发生的类型. ...

  3. IDEA免费激活至2099年教程,亲测可用

    申明,本教程 Intellij IDEA 最新版激活教程,激活码均收集与网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除.如条件允许,建议大家购买正版. 以下是本人免费激活到 2099 年的 ...

  4. k8s入坑之路(16)kubernetes中CICD/基于宿主机jenkins

    cicd的结合组件 需要代码仓库如gitlab.github.包构建工具Maven等,持续集成工具如jenkins,github/cicd.结合自己脚本实现重复式任务自动化. 传统服务发布流程: 提交 ...

  5. Python MySSH 实现剧本执行器

    通过封装Paramiko这个SSH模块,我们可以实现远程批量管理Linux主机,在上一篇文章中我们封装过一个MySSH类,这个类可以执行命令上传下载文件等,我们在这个类的基础上,实现一个简单的任务执行 ...

  6. requests_cookie登陆古诗文网。session的使用

    通过登录失败,快速找到登录接口 获取hidden隐藏域中的id的value值 # 通过登陆 然后进入到主页面 # 通过找登陆接口我们发现 登陆的时候需要的参数很多 # _VIEWSTATE: /m1O ...

  7. Django 项目配置拆分独立

    目录 一.创建配置目录 二.创建基础配置文件 三.创建各个环境的配置 四.调整settings.py 五.程序使用 六.目录结构 Django 项目中,我们默认的配置是都在 settings.py 文 ...

  8. Dapr-Actor构建块

    前言: 前篇-绑定 文章对Dapr的绑定构建块进行了解,本篇继续对 Actor 构建块进行了解学习. 一.Actor简介: Actors 为最低级别的"计算单元". 换句话说,您将 ...

  9. [atARC123F]Insert Addition

    前置知识 下面,先来介绍一下Stern-Brocot Tree的结构: 其是一棵满二叉树,每一个节点都是一个最简分数,其中根为$\frac{1}{1}$ 假设前$i$层的中序遍历分数依次为$\frac ...

  10. 架构师必备:巧用Canal实现异步、解耦的架构

    本文介绍如何应用Canal实现异步.解耦的架构,后续有空再写文章分析Canal原理和源代码. Canal简介 Canal是用来获取数据库变更的中间件. 伪装自己为MySQL从库,拉取主库binlog并 ...