1. 读取数据库的形式创建DataFrame

DataFrameFromJDBC
object DataFrameFromJDBC {
def main(args: Array[String]): Unit = {
// 创建SparkSession实例
val spark: SparkSession = SparkSession.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
.getOrCreate()
// 创建连接数据库需要的参数
val probs: Properties = new Properties()
probs.setProperty("driver", "com.mysql.jdbc.Driver")
probs.setProperty("user","root")
probs.setProperty("password", "feng")
// 使用sparksession创建DF
val df: DataFrame = spark.read.jdbc("jdbc:mysql://localhost:3306/db_user?characterEncoding=UTF-8", "t_result", probs)
// df.printSchema()
// import spark.implicits._
// df.where($"total_money" > 500).show() // 此种形式一定要导入隐式转换 df.where("money > 500").show() // 可以不导入隐式转换
}
}

2. Parquet格式的数据源 

 2.1 spark读取的数据源效率高低需要考虑下面三点

  • 1. park SQL可以读取结构化数据,读取对应格式  数据可以返回DataFrame【元数据信息,不返回的话就要自己关联shema信息,如下图】

  数据存储格式有schema信息

  • 2. 数据存储空间更小

  有特殊的序列化机制,可以使用高效的压缩机制

  • 3. 读取的效率更高

  使用高效的序列化和反序列化机制,可以指定查询哪些列,不select某些列,就不读取对应的数据(以前rdd读取数据的话是每行数据的所有列(字段)都会读取)

2.2 json、csv、Parquet形式的数据源的读取效率对比

2.2.1 

(1)json(满足2.1中的1)

数据会有冗余,name、age等字段属性会被多次读取

(2)csv(满足2.1中的2)

此种形式的数据读取只会读取一次字段属性,效率相比json的形式高点,但它默认没有压缩方式

(3)Parquet(满足2.1中的三点,是sparksql最喜欢的数据源格式)

  读取数据可以返回元数据信息、

  支持压缩,默认是snappy压缩

  更加高效的序反列化,列式存储

2.2.2 案 例:

(1)获取parquet格式数据

object JDBCToParquet {
def main(args: Array[String]): Unit = {
// 创建SparkSession实例
val spark: SparkSession = SparkSession.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
.getOrCreate()
// 创建连接数据库需要的参数
val probs: Properties = new Properties()
probs.setProperty("driver", "com.mysql.jdbc.Driver")
probs.setProperty("user","root")
probs.setProperty("password", "feng")
// 使用sparksession创建DF
val df: DataFrame = spark.read.jdbc("jdbc:mysql://localhost:3306/db_user?characterEncoding=UTF-8", "t_result", probs)
// 将df的数据转换成parquet
df.write.parquet("E:/javafile/spark/out1")
spark.stop()
}
}

得到的文件部分内容如下(可见是被处理过的)

(2)读取parquet格式的文件

object JDBCToParquet {
def main(args: Array[String]): Unit = {
// 创建SparkSession实例
val spark: SparkSession = SparkSession.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
.getOrCreate()
// 创建连接数据库需要的参数
val df: DataFrame = spark.read.parquet("E:/javafile/spark/part1.snappy.parquet")
//df.show()
//parquet格式是列式存储,可以按需查询,效率更高
df.select("cname", "money").show()
spark.stop()
}
}

运行结果

3. Orc格式的数据源

(1)获取Orc格式数据(hive 使用MR喜欢的数据格式) 

package com._51doit.spark08

import java.util.Properties

import org.apache.spark.sql.{DataFrame, SparkSession}

object JDBCToOrc {
def main(args: Array[String]): Unit = {
// 创建SparkSession实例
val spark: SparkSession = SparkSession.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
.enableHiveSupport() // 让sparkSQL开启对Hive的支持
.getOrCreate()
// 创建连接数据库需要的参数
val probs: Properties = new Properties()
probs.setProperty("driver", "com.mysql.jdbc.Driver")
probs.setProperty("user","root")
probs.setProperty("password", "feng")
// 使用sparksession创建DF
val df: DataFrame = spark.read.jdbc("jdbc:mysql://localhost:3306/db_user?characterEncoding=UTF-8", "t_result", probs)
// 将df数据转换成Orc
df.write.orc("E:/javafile/spark/out2")
spark.stop()
}
}

(2)读取Orc格式的文件

object OrcDataSource {
def main(args: Array[String]): Unit = {
// 创建SparkSession实例
val spark: SparkSession = SparkSession.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
.enableHiveSupport() // 让sparkSQL开启对Hive的支持
.getOrCreate()
// 读取Orc数据源
val df: DataFrame = spark.read.orc("E:/javafile/spark/out2")
// df.printSchema()
df.where("money > 500").show()
spark.stop()
}
}

4.spark_sql整合hive

(1)安装mysql并创建一个普通用户,并且授权(nysql5.7后密码不能设置的很简单)  

set global validate_password_policy=LOW;
set global validate_password_length=6;
CREATE USER 'bigdata'@'%' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON hivedb.* TO 'bigdata'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;
FLUSH PRIVILEGES;

(2)在spark的conf目录下。添加一个hive-site.xml,指向mysql的源数据库hivedb

<configuration>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://feng05:3306/hivedb?createDatabaseIfNotExist=true</value>
<description>JDBC connect string for a JDBC metastore</description>
</property> <property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
<description>Driver class name for a JDBC metastore</description>
</property> <property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>bigdata</value>
<description>username to use against metastore database</description>
</property> <property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>feng</value>
<description>password to use against metastore database</description>
</property> </configuration>

(3)上传一个mysql链接驱动,并启动spark_sql

./spark-sql --master spark://feng05:7077 --executor-memory 800m --total-executor-cores 3 --driver-class-path /root/mysql-connector-java-5.1.39.jar

(4)执行(3)操作后,sparkSQL会在mysql上创建一个database(hivedb),需要手动改一下DBS表中的DB_LOCATION_UIR改成hdfs的地址,如下

(5)重新启动SparkSQL的命令行,即可完成spark与hive的整合

(6)由上面可知,操作时会出现大量的日志信息,想要改变这种情况,可以如下操作

  进入安装spark目录中测conf文件(/usr/apps/spark-2.3.3-bin-hadoop2.7/conf),将log4j.properties.template文件改成log4j.properties,并编辑内容如下

(7) 重启spark_sql即可得到干净无太多日志信息的界面,如下

补充:

  • -e    后面跟SQL命令  
./spark-sql --master spark://node-1.51doit.cn:7077 --executor-memory 1g --total-executor-cores 4 --driver-class-path /root/mysql-connector-java-5.1.47.jar -e "select * from user"
  •  -f   后面跟sql脚本
./spark-sql --master spark://node-1.51doit.cn:7077 --executor-memory 1g --total-executor-cores 4 --driver-class-path /root/mysql-connector-java-5.1.47.jar -f /root/hql.sql

5.在IDEA中编写spark程序,用来操作hive,分析数据

代码如下

/**
* 在IDEA中编写spark程序,并且支持hive,可以使用Hive的源数据库
*/
object SparkHive { def main(args: Array[String]): Unit = { System.setProperty("HADOOP_USER_NAME", "root")
val spark = SparkSession.builder()
.appName("SparkHive")
.master("local[*]")
.enableHiveSupport() //开启Spark对Hive的支持,spark完全兼容Hive
.getOrCreate() //读取HDFS中的非结构化数据,对数据进行处理 //在hive中建表
//写Hive SQL分析数据
spark.sql("CREATE TABLE person (id bigint, name string, age int) ROW FORMAT" +
" DELIMITED FIELDS TERMINATED BY ','" ) spark.sql("LOAD DATA LOCAL INPATH '/Users/star/Desktop/person.txt' INTO TABLE person") val df = spark.sql("SELECT * FROM person WHERE id > 2") df.show() spark.stop() }
}

注意:需要添加如下三个配置文件

  6. SQL风格和DSL风格以及RDD的形式计算连续登陆三天的用户

数据

需求:连续登陆三天的用户

5.1 SQL风格

package com._51doit.spark08

import org.apache.spark.sql.{DataFrame, Dataset, SparkSession}

object UserContinueLoginSQL {
def main(args: Array[String]): Unit = {
// 创建SparkSession
val spark: SparkSession = SparkSession.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
.getOrCreate()
// 读取文件创建DataSet
val access: DataFrame = spark.read.option("header", "true")
.csv("F:\\大数据第三阶段\\spark\\spark-day09\\资料\\access.csv")
// 注册成视图
access.createTempView("v_access_log")
spark.sql(
s"""
|SELECT
|uid,
|MIN(dt) start_date,
|MAX(dt) end_date,
|count(*) clogin
|FROM
|(
| SELECT
| uid,
| dt,
| date_sub(dt, n) diff
| FROM
| (
| SELECT
| uid,
| dt,
| row_number() over(partition by uid order by dt) n
| FROM
| v_access_log
| ) t1
|) t2
|GROUP BY uid,diff
|HAVING clogin >= 3
|""".stripMargin
).show()
spark.stop()
}
}

结果

5.2 DSL风格

package com._51doit.spark08

import org.apache.spark.sql.expressions.{Window, WindowSpec}
import org.apache.spark.sql.{DataFrame, SparkSession} object UserContinueLoginDSL {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
.getOrCreate() //读取csv文件创建DataFrame
val access: DataFrame = spark.read.option("header", "true")
.csv("F:\\大数据第三阶段\\spark\\spark-day09\\资料\\access.csv") //DSL风格的API
import spark.implicits._ val win: WindowSpec = Window.partitionBy($"uid").orderBy($"dt") import org.apache.spark.sql.functions._ access.select($"uid", $"dt", row_number.over(win) as "rn")
.select($"uid", $"dt", expr("date_sub(dt, rn) as dif"))
.groupBy("uid", "dif")
.agg(count("*") as "counts",
min("dt") as "start_date",
max("dt") as "end_data")
.filter("counts >= 3")
.select("uid", "start_date", "end_data", "counts")
.show() spark.stop()
}
}

结果

 5.3 RDD形式

package com._51doit.spark09

import java.text.SimpleDateFormat
import java.util.{Calendar, Date} import org.apache.spark.rdd.RDD
import org.apache.spark.{Partitioner, SparkConf, SparkContext} import scala.collection.mutable object UserContinuedLoginRDD {
def main(args: Array[String]): Unit = {
// // 判断是否本地运行
// val isLocal = args(0).toBoolean
// val conf: SparkConf = new SparkConf().setAppName(this.getClass.getName)
// if(isLocal){
// conf.setMaster("local[*]")
// }
// 创建SparkContext
val conf = new SparkConf()
.setAppName(this.getClass.getName)
.setMaster("local[*]")
val sc: SparkContext = new SparkContext(conf)
val lines: RDD[String] = sc.textFile("E:/javafile/spark/access.csv")
// 数据处理,获取(uid, date)形式的RDD
val UidDateAndNull: RDD[((String, String), Null)] = lines.map(line => {
val fields: Array[String] = line.split(",")
val uid = fields(0)
val date = fields(1)
((uid, date), null)
})
// 求分区的个数
val uids: Array[String] = UidDateAndNull.keys.map(_._1).distinct().collect()
// 自定义分区器,根据uid分区,并按照(uid,date排序)
val sortedInPartition: RDD[((String, String), Null)] = UidDateAndNull.repartitionAndSortWithinPartitions(new Partitioner() { // 默认按照key排序,所以上面需为((uid,date), null)
val idToPartitionId = new mutable.HashMap[String, Int]()
for (i <- uids.indices) {
idToPartitionId(uids(i)) = i
}
override def numPartitions: Int = uids.length
override def getPartition(key: Any): Int = {
val tp: (String, String) = key.asInstanceOf[(String, String)]
idToPartitionId(tp._1)
}
})
// 给处理后的数据打上行号
val uidTimeAndDate: RDD[((String, Long), String)] = sortedInPartition.mapPartitions(it => {
val sdf: SimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd")
val calendar = Calendar.getInstance()
var i = 0
it.map(t => {
i += 1
val uid = t._1._1
val dateStr = t._1._2
val date: Date = sdf.parse(dateStr)
calendar.setTime(date)
calendar.add(Calendar.DATE, -i)
val dif = calendar.getTime.getTime
((uid, dif), dateStr)
})
})
// 进行计算
val firstResult: RDD[((String, Long), (String, String, Int))] = uidTimeAndDate.groupByKey().mapValues(it => {
val sorted: Seq[String] = it.toList.sorted
//连续登陆的次数
val counts = sorted.size
//起始时间
val start_date = sorted.head
//结束时间
val end_date = sorted.last
(start_date, end_date, counts)
})
// 最终结果
val result: RDD[(String, String, String, Int)] = firstResult.filter(_._2._3 >= 3).map(t => (t._1._1, t._2._1, t._2._2, t._2._3)) //输出结果
val r = result.collect()
println(r.toBuffer)
sc.stop()
}
}

结果

此处注意的知识点:

calendar, 自定义分区器

  

大数据学习day25------spark08-----1. 读取数据库的形式创建DataFrame 2. Parquet格式的数据源 3. Orc格式的数据源 4.spark_sql整合hive 5.在IDEA中编写spark程序(用来操作hive) 6. SQL风格和DSL风格以及RDD的形式计算连续登陆三天的用户的更多相关文章

  1. 大数据学习系列之—HBASE

    hadoop生态系统 zookeeper负责协调 hbase必须依赖zookeeper flume 日志工具 sqoop 负责 hdfs dbms 数据转换 数据到关系型数据库转换 大数据学习群119 ...

  2. 大数据学习day26----hive01----1hive的简介 2 hive的安装(hive的两种连接方式,后台启动,标准输出,错误输出)3. 数据库的基本操作 4. 建表(内部表和外部表的创建以及应用场景,数据导入,学生、分数sql练习)5.分区表 6加载数据的方式

    1. hive的简介(具体见文档) Hive是分析处理结构化数据的工具   本质:将hive sql转化成MapReduce程序或者spark程序 Hive处理的数据一般存储在HDFS上,其分析数据底 ...

  3. 大数据学习day24-------spark07-----1. sortBy是Transformation算子,为什么会触发Action 2. SparkSQL 3. DataFrame的创建 4. DSL风格API语法 5 两种风格(SQL、DSL)计算workcount案例

    1. sortBy是Transformation算子,为什么会触发Action sortBy需要对数据进行全局排序,其需要用到RangePartitioner,而在创建RangePartitioner ...

  4. 大数据学习系列之四 ----- Hadoop+Hive环境搭建图文详解(单机)

    引言 在大数据学习系列之一 ----- Hadoop环境搭建(单机) 成功的搭建了Hadoop的环境,在大数据学习系列之二 ----- HBase环境搭建(单机)成功搭建了HBase的环境以及相关使用 ...

  5. 大数据学习系列之五 ----- Hive整合HBase图文详解

    引言 在上一篇 大数据学习系列之四 ----- Hadoop+Hive环境搭建图文详解(单机) 和之前的大数据学习系列之二 ----- HBase环境搭建(单机) 中成功搭建了Hive和HBase的环 ...

  6. 大数据学习系列之七 ----- Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 图文详解

    引言 在之前的大数据学习系列中,搭建了Hadoop+Spark+HBase+Hive 环境以及一些测试.其实要说的话,我开始学习大数据的时候,搭建的就是集群,并不是单机模式和伪分布式.至于为什么先写单 ...

  7. 大数据学习(09)—— Hive语法

    Hive官方网站上有详细的语法说明,参考LanguageManual. 这里我把最常用的几块列出来. HIVE DDL Database 建库语句 CREATE (DATABASE|SCHEMA) [ ...

  8. 大数据学习day29-----spark09-------1. 练习: 统计店铺按月份的销售额和累计到该月的总销售额(SQL, DSL,RDD) 2. 分组topN的实现(row_number(), rank(), dense_rank()方法的区别)3. spark自定义函数-UDF

    1. 练习 数据: (1)需求1:统计有过连续3天以上销售的店铺有哪些,并且计算出连续三天以上的销售额 第一步:将每天的金额求和(同一天可能会有多个订单) SELECT sid,dt,SUM(mone ...

  9. 大数据学习系列之九---- Hive整合Spark和HBase以及相关测试

    前言 在之前的大数据学习系列之七 ----- Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 中介绍了集群的环境搭建,但是在使用hive进行数据查询的时候会非常的慢,因为h ...

随机推荐

  1. linux中的分号 && ||

    几个符号的用法 ; 顺序地独立执行各条命令, 彼此之间不关心是否失败, 所有命令都会执行. && 顺序执行各条命令, 只有当前一个执行成功时候, 才执行后面的. & 放在启动参 ...

  2. 第02课 OpenGL 多边形

    你的第一个多边形: 在第一个教程的基础上,我们添加了一个三角形和一个四边形.也许你认为这很简单,但你已经迈出了一大步,要知道任何在OpenGL中绘制的模型都会被分解为这两种简单的图形.读完了这一课,你 ...

  3. python环境搭建、pycharm安装

    一.      实验目标 (1)  Python环境搭建 (2)  会pycharm安装和使用 (3)  了解python程序设计流程 二.      实验内容 1.勾选Add Python 3.7 ...

  4. ORA-01756: quoted string not properly terminated

    导入sql文件报错:ORA-01756: quoted string not properly terminated 字符集的中英文问题: 临时解决方法:export NLS_LANG=AMERICA ...

  5. SpringBoot配置文件自动映射到属性和实体类(8)

    一.配置文件加载 1.Controller中配置并指向文件 @Controller @PropertySource(value = { "application.properties&quo ...

  6. 远程连接linux | Xshell和Xftp下载安装

    为什么需要远程登录linux 公司开发时候, 具体的情况是这样的: Linux 一般作为服务器使用,而服务器一般放在机房,你不可能在机房操作你的 Linux 服务器.这时我们就需要远程登录到Linux ...

  7. 用Python实现人像动漫化

    用Python实现人像动漫化 本文章会教你如何使用Python实现人像动漫化,先看看效果实例: 实现过程如下: 本案例是使用百度的API来实现的,首先需要进入百度AI开放平台注册账号,具体流程就不讲了 ...

  8. PTA 树的同构 (25分)

    PTA 树的同构 (25分) 输入格式: 输入给出2棵二叉树树的信息.对于每棵树,首先在一行中给出一个非负整数N (≤10),即该树的结点数(此时假设结点从0到N−1编号):随后N行,第i行对应编号第 ...

  9. 史上最简单的排序算法?看起来却满是bug

    大家好,我是雨乐. 今天在搜论文的时候,偶然发现一篇文章,名为<Is this the simplest (and most surprising) sorting algorithm ever ...

  10. 菜鸡的Java笔记 Eclipse 的使用

    Eclipse 的使用    1. Eclipse 简介    2. Eclipse 中的JDT 的使用    3. Eclipse 中的使用 junit 测试        Eclipse (中文翻 ...