1. 练习

数据:

(1)需求1:统计有过连续3天以上销售的店铺有哪些,并且计算出连续三天以上的销售额

第一步:将每天的金额求和(同一天可能会有多个订单)

SELECT
sid,dt,SUM(money) day_money
FROM
v_orders
GROUP BY sid,dt

第二步:给每个商家中每日的订单按时间排序并打上编号

SELECT
sid,dt,day_money,
ROW_NUMBER() OVER(PARTITION BY sid ORDER BY dt) rn
FROM
(
SELECT
sid,dt,SUM(money) day_money
FROM
v_orders
GROUP BY sid,dt
) t1

第三步:获取date与rn的差值的字段

SELECT
sid ,dt,day_money,date_sub(dt,rn) diff
FROM
(
SELECT
sid,dt,day_money,
ROW_NUMBER() OVER(PARTITION BY sid ORDER BY dt) rn
FROM
(
SELECT
sid,dt,SUM(money) day_money
FROM
v_orders
GROUP BY sid,dt
) t1
) t2

第四步: 最终结果

SELECT
sid,MIN(dt),MAX(dt),SUM(day_money) cmoney,COUNT(*) cc
FROM
(
SELECT
sid ,dt,day_money,date_sub(dt,rn) diff
FROM
(
SELECT
sid,dt,day_money,
ROW_NUMBER() OVER(PARTITION BY sid ORDER BY dt) rn
FROM
(
SELECT
sid,dt,SUM(money) day_money
FROM
v_orders
GROUP BY sid,dt
) t1
) t2
)
GROUP BY sid,diff
HAVING cc >=3

(2)需求2:统计店铺按月份的销售额和累计到该月的总销售额

  • SQL风格(只写sq语句,省略代码部分)
SELECT
sid,month,month_sales,
SUM(month_sales) OVER(PARTITION BY sid ORDER BY month) total_sales // 默认是其实位置到当前位置的累加
--PARTITION BY sid ORDER BY mth ASC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 完整的写法
FROM
(
SELECT
sid,
DATE_FORMAT(dt,'yyyy-MM') month,
--substr(dt,1,7) month, 用此函数来取月份也行
SUM(money) month_sales
FROM
v_orders
GROUP BY sid, month
)

结果

  • DSL风格
object RollupMthIncomeDSL {
def main(args: Array[String]): Unit = {
// 创建SparkSession
val spark: SparkSession = SparkSession.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
.getOrCreate()
// 读取文件创建DataSet
val orders: DataFrame = spark.read
.option("header", "true")
.option("inferSchema", "true") // inferSchema为true可以自动推测数据的类型,默认false,则所有的数据都是String类型的
.csv("F:\\大数据第三阶段\\spark\\spark-day09\\资料\\order.csv")
import spark.implicits._
import org.apache.spark.sql.functions._
// 获取月份,并按照sid和月份进行分组,聚合
val result: DataFrame = orders.groupBy($"sid", date_format($"dt", "yyyy-MM") as "month")
.agg(sum($"money") as "month_sales")
// withColumn相当于在原有基础上再增加一列,此处使用select重新获取表也行
//.select('sid, 'month, 'month_sales, sum('month_sales) over(Window.partitionBy('sid)
// .orderBy('month).rowsBetween(Window.unboundedPreceding, Window.currentRow)) as "rollup_sales")
.withColumn("rollup_sales", sum('month_sales) over (Window.partitionBy('sid) // 'sid相当于$"sid"
.orderBy('month).rowsBetween(Window.unboundedPreceding, Window.currentRow)))
result.show()
spark.stop()
}
}
  • RDD风格
object RollupMthIncomeRDD {
def main(args: Array[String]): Unit = {
// 创建SparkContext
val conf = new SparkConf()
.setAppName(this.getClass.getName)
.setMaster("local[*]")
val sc: SparkContext = new SparkContext(conf)
val lines: RDD[String] = sc.textFile("F:\\大数据第三阶段\\spark\\spark-day09\\资料\\order.csv")
val reduced: RDD[((String, String), Double)] = lines.map(line => {
val fields: Array[String] = line.split(",")
val sid: String = fields(0)
val dateStr: String = fields(1)
val month: String = dateStr.substring(0, 7)
val money: Double = fields(2).toDouble
((sid, month), money)
}).reduceByKey(_ + _)
// 按照shop id分组
val result: RDD[(String, String, String, Double)] = reduced.groupBy(_._1._1).mapValues(it => {
//将迭代器中的数据toList放入到内存
//并且按照月份排序【字典顺序】
val sorted: List[((String, String), Double)] = it.toList.sortBy(_._1._2)
var rollup = 0.0
sorted.map(t => {
val sid = t._1._1
val month = t._1._2
val month_sales = t._2
rollup += month_sales
(sid, month, rollup)
})
}).flatMapValues(lst => lst).map(t => (t._1, t._2._1, t._2._2, t._2._3))
result.foreach(println)
sc.stop()
}
}

注意点:可以直接读取csv文件获取DataFram,再获取rdd,如下

 2. 分组topN的实现(大数据学习day21中的计算学科最受欢迎老师topN)

  •  SQL 

注意点:此处的文件格式是text的,所以需要用SparkContext的textFile方法来读取数据,然后处理此数据,得到需要的字段(subject,teacher),再利用toDF("subject", "teacher")方法获取对应的DataFrame,从而创建相应的视图

object FavoriteTeacherSQL {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
.getOrCreate()
import spark.implicits._
val lines: RDD[String] = spark.sparkContext.textFile("E:\\javafile\\spark\\teacher100.txt")
// 处理数据,获取DataFrame,用于创建视图
val df: DataFrame = lines.map(line => {
val fields = line.split("/")
val subject = fields(2).split("\\.")(0)
val teacher = fields(3)
(subject, teacher)
}).toDF("subject", "teacher")
// 创建视图
df.createTempView("v_teacher") var topN: Int = 2
// SQL实现分组topN
spark.sql(
s"""
|SELECT
| subject,teacher,counts
| rk
|FROM
|(
| SELECT
| subject,teacher,counts,
| RANK() OVER(PARTITION BY subject ORDER BY counts DESC) rk
| FROM
| (
| SELECT
| subject,teacher,
| count(*) counts
| FROM
| v_teacher
| GROUP BY subject, teacher
| ) t1
|) t2 WHERE rk <= $topN
|""".stripMargin).show()
}
}

此处的小知识点:

row_number(), rank(), dense_rank()方法的区别

row_number() over() 打行号,行号从1开始
rank() over() 排序,有并列,如果有两个第1,就没有第2了,然后直接第3,跳号
dense_rank() over() 排序,有并列,不跳号
  • DSL
object FavoriteTeacherDSL {
def main(args: Array[String]): Unit = {
val spark: SparkSession = SparkSession.builder()
.appName(this.getClass.getSimpleName)
.master("local[*]")
.getOrCreate()
import spark.implicits._
val lines: RDD[String] = spark.sparkContext.textFile("E:\\javafile\\spark\\teacher100.txt")
// 处理数据,获取DataFrame,用于创建视图
val df: DataFrame = lines.map(line => {
val fields = line.split("/")
val subject = fields(2).split("\\.")(0)
val teacher = fields(3)
(subject, teacher)
}).toDF("subject", "teacher")
import org.apache.spark.sql.functions._
df.groupBy("subject","teacher")
.agg(count("*") as "counts")
.withColumn("rk",dense_rank().over(Window.partitionBy($"subject").orderBy($"counts" desc)) )
.filter('rk <= 2)
.show() spark.stop()
}
}

3. spark自定义函数-UDF

  UDF:一进一出(输入一行,返回一行)

  UDTF: 一进多出

  UDAF: 多进一出

object MyConcatWsUDF {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().appName(this.getClass.getSimpleName)
.master("local[*]")
.getOrCreate()
import spark.implicits._
val tp: Dataset[(String, String)] = spark.createDataset(List(("aaa", "bbb"), ("aaa", "ccc"), ("aaa", "ddd")))
val df: DataFrame = tp.toDF("f1", "f2")
//注册自定义函数
//MY_CONCAT_WS函数名称
//后面传入的scala的函数就是具有的实现逻辑
spark.udf.register("MY_CONCAT_WS", (s: String, first: String, second:String) => {
first + s + second
}) import org.apache.spark.sql.functions._
//df.selectExpr("CONCAT_WS('-', f1, f2) as f3")
//df.select(concat_ws("-", $"f1", 'f2) as "f3").show()
//df.selectExpr("MY_CONCAT_WS('_', f1, f2) as f3").show()
df.createTempView("v_data") spark.sql(
"""
|SELECT MY_CONCAT_WS('-', f1, f2) f3 FROM v_data
""".stripMargin).show()
spark.stop()
}
}

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

  1. Spark(十三)SparkSQL的自定义函数UDF与开窗函数

    一 自定义函数UDF 在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_ ...

  2. 大数据学习——hive函数

    1 内置函数 测试各种内置函数的快捷方法: 1.创建一个dual表 create table dual(id string); 2.load一个文件(一行,一个空格)到dual表 3.select s ...

  3. 大数据学习系列之六 ----- Hadoop+Spark环境搭建

    引言 在上一篇中 大数据学习系列之五 ----- Hive整合HBase图文详解 : http://www.panchengming.com/2017/12/18/pancm62/ 中使用Hive整合 ...

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

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

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

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

  6. SparkSQL中的自定义函数UDF

    在Spark中,也支持Hive中的自定义函数.自定义函数大致可以分为三种: UDF(User-Defined-Function),即最基本的自定义函数,类似to_char,to_date等 UDAF( ...

  7. 大数据学习(一) | 初识 Hadoop

    作者: seriouszyx 首发地址:https://seriouszyx.top/ 代码均可在 Github 上找到(求Star) 最近想要了解一些前沿技术,不能一门心思眼中只有 web,因为我目 ...

  8. 大数据学习笔记——Hadoop编程实战之Mapreduce

    Hadoop编程实战——Mapreduce基本功能实现 此篇博客承接上一篇总结的HDFS编程实战,将会详细地对mapreduce的各种数据分析功能进行一个整理,由于实际工作中并不会过多地涉及原理,因此 ...

  9. 10_Hive自定义函数UDF

    Hive官方的UDF手册地址是:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF 1.使用内置函数的快捷方法: 创 ...

随机推荐

  1. python mysqlclient安装失败 Command "python setup.py egg_info" failed with error code 1

    python2 python3 中代码 pip install mysqlclient 都安装失败的话, 很有可能是你的操作系统中没有安装mysql 如果确定已经安装了,请忽略下面的内容. Ubunt ...

  2. 树行DP小结

    顾名思义:就是在树上做的DP,依据DFS的性质,在访问过儿子之后返回后将儿子的状态传递给父亲... 先看例题: 此题用贪心也能过,不过正解是DP. 对于树上的DP我们可以直接考虑最优解下各点的状态来方 ...

  3. 设计模式(1-3)-动态代理(WeakCache的运用)

    阅读本篇文章前,请事先阅读 理解Java的强引用.软引用.弱引用和虚引用. 看看什么是强引用.什么是弱引用及它们的用途,很必要!!! 上一节讲到,获取对应的代理类时,首先会从缓存中去拿,若拿不到才会去 ...

  4. 【java+selenium3】时间控件 (九)

    1.问题描述: 在应用selenium实现web自动化时,经常会遇到处理日期控件点击问题,手工很简单,可以一个个点击日期控件选择需要的日期,但自动化执行过程中,完全复制手工这样的操作就有点难了. 如图 ...

  5. vue 快速入门 系列 —— 使用 vue-cli 3 搭建一个项目(上)

    其他章节请看: vue 快速入门 系列 使用 vue-cli 3 搭建一个项目(上) 前面我们已经学习了一个成熟的脚手架(vue-cli),笔者希望通过这个脚手架快速搭建系统(或项目).而展开搭建最好 ...

  6. java eclipse调试提示Source not found 或 一闪而过 解决方法

    Web工程Eclipse  debug方式启动,在断点的位置被成功拦截,但是没有跳转到工程的代码处,提示如下: 当然这个时候如果我继续按F5的话呢,程序又会接着正常运行了.到这里那就是说程序本身是没有 ...

  7. Flume面试题整理

    1.Flume使用场景(☆☆☆☆☆) 线上数据一般主要是落地(存储到磁盘)或者通过socket传输给另外一个系统,这种情况下,你很难推动线上应用或服务去修改接口,实现直接向kafka里写数据,这时候你 ...

  8. 001.AD域控简介及使用

    一 AD概述 1.1 AD简介 域(Domain)是Windows网络中独立运行的单位,域之间相互访问则需要建立信任关系. 当一个域与其他域建立了信任关系后,2个域之间不但可以按需要相互进行管理,还可 ...

  9. Effective C++ 总结笔记(二)

    二.构造/析构/赋值运算 05.了解C++默默编写并调用那些函数 如果自己不声明, 编译器就会暗自为class创建一个default构造函数.一个copy构造函数.一个copy assignment操 ...

  10. 从 ThreadLocal 到 AsyncLocal

    前些天跟大佬们在群里讨论如何在不使用构造函数,不增加方法参数的情况下把一个上下文注入到方法内部使用,得出的结论是 AsyncLocal .感叹自己才疏学浅,居然才知道有 AsyncLocal 这种神器 ...