2小时入门SparkSQL编程

SparkSql编程之《DataFrame行动操作》 一、数据准备,json文件 项目处新建people.json文件 {"name":"Michael"} {"name":"Andy", "age":30} {"name":"Justin", "age":19} 创建DataFrame val df = spark.read.json("input/people.json") 二、DataFrame上的行动操作 行动操作有:show、collect、collectAsList、describe、first、 head、 take、 t.. 阅读详情

公众号后台回复关键字:pyspark,获取本项目github地址。

本节将介绍SparkSQL编程基本概念和基本用法。

不同于RDD编程的命令式编程范式,SparkSQL编程是一种声明式编程范式,我们可以通过SQL语句或者调用DataFrame的相关API描述我们想要实现的操作。

然后Spark会将我们的描述进行语法解析,找到相应的执行计划并对其进行流程优化,然后调用相应基础命令进行执行。

我们使用pyspark进行RDD编程时,在Excutor上跑的很多时候就是Python代码,当然,少数时候也会跑java字节码。

但我们使用pyspark进行SparkSQL编程时,在Excutor上跑的全部是java字节码,pyspark在Driver端就将相应的Python代码转换成了java任务然后放到Excutor上执行。

因此,使用SparkSQL的编程范式进行编程,我们能够取得几乎和直接使用scala/java进行编程相当的效率(忽略语法解析时间差异)。此外SparkSQL提供了非常方便的数据读写API,我们可以用它和Hive表,HDFS,mysql表,Cassandra,Hbase等各种存储媒介进行数据交换。

美中不足的是,SparkSQL的灵活性会稍差一些,其默认支持的数据类型通常只有 Int,Long,Float,Double,String,Boolean 等这些标准SQL数据类型, 类型扩展相对繁琐。对于一些较为SQL中不直接支持的功能,通常可以借助于用户自定义函数(UDF)来实现,如果功能更加复杂,则可以转成RDD来进行实现。

本节我们将主要介绍以下主要内容:

  • RDD和DataFrame的对比

  • 创建DataFrame

  • DataFrame保存成文件

  • DataFrame的API交互

  • DataFrame的SQL交互

import findspark

#指定spark_home为刚才的解压路径,指定python路径
spark_home = "/Users/liangyun/ProgramFiles/spark-3.0.1-bin-hadoop3.2"
python_path = "/Users/liangyun/anaconda3/bin/python"
findspark.init(spark_home,python_path)

import pyspark 
from pyspark.sql import SparkSession

#SparkSQL的许多功能封装在SparkSession的方法接口中

spark = SparkSession.builder \
        .appName("test") \
        .config("master","local[4]") \
        .enableHiveSupport() \
        .getOrCreate()

sc = spark.sparkContext


一,RDD,DataFrame和DataSet对比

DataFrame参照了Pandas的思想,在RDD基础上增加了schma,能够获取列名信息。

DataSet在DataFrame基础上进一步增加了数据类型信息,可以在编译时发现类型错误。

DataFrame可以看成DataSet[Row],两者的API接口完全相同。

DataFrame和DataSet都支持SQL交互式查询,可以和 Hive无缝衔接。

DataSet只有Scala语言和Java语言接口中才支持,在Python和R语言接口只支持DataFrame。

DataFrame数据结构本质上是通过RDD来实现的,但是RDD是一种行存储的数据结构,而DataFrame是一种列存储的数据结构。

二,创建DataFrame

1,通过toDF方法转换成DataFrame

可以将RDD用toDF方法转换成DataFrame

#将RDD转换成DataFrame
rdd = sc.parallelize([("LiLei",15,88),("HanMeiMei",16,90),("DaChui",17,60)])
df = rdd.toDF(["name","age","score"])
df.show()
df.printSchema()
+---------+---+-----+
|     name|age|score|
+---------+---+-----+
|    LiLei| 15|   88|
|HanMeiMei| 16|   90|
|   DaChui| 17|   60|
+---------+---+-----+

root
 |-- name: string (nullable = true)
 |-- age: long (nullable = true)
 |-- score: long (nullable = true)

2, 通过createDataFrame方法将Pandas.DataFrame转换成pyspark中的DataFrame

import pandas as pd 

pdf = pd.DataFrame([("LiLei",18),("HanMeiMei",17)],columns = ["name","age"])
df = spark.createDataFrame(pdf)
df.show()
+---------+---+
|     name|age|
+---------+---+
|    LiLei| 18|
|HanMeiMei| 17|
+---------+---+
# 也可以对列表直接转换
values = [("LiLei",18),("HanMeiMei",17)]
df = spark.createDataFrame(values,["name","age"])
df.show()
+---------+---+
|     name|age|
+---------+---+
|    LiLei| 18|
|HanMeiMei| 17|
+---------+---+

4, 通过createDataFrame方法指定schema动态创建DataFrame

可以通过createDataFrame的方法指定rdd和schema创建DataFrame。

这种方法比较繁琐,但是可以在预先不知道schema和数据类型的情况下在代码中动态创建DataFrame.

from pyspark.sql.types import *
from pyspark.sql import Row
from datetime import datetime

schema = StructType([StructField("name", StringType(), nullable = False),
                     StructField("score", IntegerType(), nullable = True),
                     StructField("birthday", DateType(), nullable = True)])

rdd = sc.parallelize([Row("LiLei",87,datetime(2010,1,5)),
                      Row("HanMeiMei",90,datetime(2009,3,1)),
                      Row("DaChui",None,datetime(2008,7,2))])

dfstudent = spark.createDataFrame(rdd, schema)

dfstudent.show()
+---------+-----+----------+
|     name|score|  birthday|
+---------+-----+----------+
|    LiLei|   87|2010-01-05|
|HanMeiMei|   90|2009-03-01|
|   DaChui| null|2008-07-02|
+---------+-----+----------+

4,通过读取文件创建

可以读取json文件,csv文件,hive数据表或者mysql数据表得到DataFrame。

#读取json文件生成DataFrame
df = spark.read.json("data/people.json")
df.show()
+----+-------+
| age|   name|
+----+-------+
|null|Michael|
|  30|   Andy|
|  19| Justin|
+----+-------+
#读取csv文件
df = spark.read.option("header","true") \
 .option("inferSchema","true") \
 .option("delimiter", ",") \
 .csv("data/iris.csv")
df.show(5)
df.printSchema()
+-----------+----------+-----------+----------+-----+
|sepallength|sepalwidth|petallength|petalwidth|label|
+-----------+----------+-----------+----------+-----+
|        5.1|       3.5|        1.4|       0.2|    0|
|        4.9|       3.0|        1.4|       0.2|    0|
|        4.7|       3.2|        1.3|       0.2|    0|
|        4.6|       3.1|        1.5|       0.2|    0|
|        5.0|       3.6|        1.4|       0.2|    0|
+-----------+----------+-----------+----------+-----+
only showing top 5 rows

root
 |-- sepallength: double (nullable = true)
 |-- sepalwidth: double (nullable = true)
 |-- petallength: double (nullable = true)
 |-- petalwidth: double (nullable = true)
 |-- label: integer (nullable = true)
#读取csv文件
df = spark.read.format("com.databricks.spark.csv") \
 .option("header","true") \
 .option("inferSchema","true") \
 .option("delimiter", ",") \
 .load("data/iris.csv")
df.show(5)
df.printSchema()
+-----------+----------+-----------+----------+-----+
|sepallength|sepalwidth|petallength|petalwidth|label|
+-----------+----------+-----------+----------+-----+
|        5.1|       3.5|        1.4|       0.2|    0|
|        4.9|       3.0|        1.4|       0.2|    0|
|        4.7|       3.2|        1.3|       0.2|    0|
|        4.6|       3.1|        1.5|       0.2|    0|
|        5.0|       3.6|        1.4|       0.2|    0|
+-----------+----------+-----------+----------+-----+
only showing top 5 rows

root
 |-- sepallength: double (nullable = true)
 |-- sepalwidth: double (nullable = true)
 |-- petallength: double (nullable = true)
 |-- petalwidth: double (nullable = true)
 |-- label: integer (nullable = true)
#读取parquet文件
df = spark.read.parquet("data/users.parquet")
df.show()
+------+--------------+----------------+
|  name|favorite_color|favorite_numbers|
+------+--------------+----------------+
|Alyssa|          null|  [3, 9, 15, 20]|
|   Ben|           red|              []|
+------+--------------+----------------+

#读取hive数据表生成DataFrame

spark.sql("CREATE TABLE IF NOT EXISTS src (key INT, value STRING) USING hive")
spark.sql("LOAD DATA LOCAL INPATH 'data/kv1.txt' INTO TABLE src")
df = spark.sql("SELECT key, value FROM src WHERE key < 10 ORDER BY key")
df.show(5)

+---+-----+
|key|value|
+---+-----+
|  0|val_0|
|  0|val_0|
|  0|val_0|
|  0|val_0|
|  0|val_0|
+---+-----+
only showing top 5 rows
#读取mysql数据表生成DataFrame
"""
url = "jdbc:mysql://localhost:3306/test"
df = spark.read.format("jdbc") \
 .option("url", url) \
 .option("dbtable", "runoob_tbl") \
 .option("user", "root") \
 .option("password", "0845") \
 .load()\
df.show()
"""

三,DataFrame保存成文件

可以保存成csv文件,json文件,parquet文件或者保存成hive数据表

#保存成csv文件
df = spark.read.format("json").load("data/people.json")
df.write.format("csv").option("header","true").save("data/people_write.csv")
#先转换成rdd再保存成txt文件
df.rdd.saveAsTextFile("data/people_rdd.txt")
#保存成json文件
df.write.json("data/people_write.json")
#保存成parquet文件, 压缩格式, 占用存储小, 且是spark内存中存储格式,加载最快
df.write.partitionBy("age").format("parquet").save("data/namesAndAges.parquet")
df.write.parquet("data/people_write.parquet")
#保存成hive数据表
df.write.bucketBy(42, "name").sortBy("age").saveAsTable("people_bucketed")

四,DataFrame的API交互

from pyspark.sql import Row
from pyspark.sql.functions import * 

df = spark.createDataFrame(
    [("LiLei",15,"male"),
     ("HanMeiMei",16,"female"),
     ("DaChui",17,"male")]).toDF("name","age","gender")

df.show()
df.printSchema()

+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
|   DaChui| 17|  male|
+---------+---+------+

root
 |-- name: string (nullable = true)
 |-- age: long (nullable = true)
 |-- gender: string (nullable = true)

1,Action操作

DataFrame的Action操作包括show,count,collect,,describe,take,head,first等操作。

#show
df.show()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
|   DaChui| 17|  male|
+---------+---+------+
#show(numRows: Int, truncate: Boolean) 
#第二个参数设置是否当输出字段长度超过20时进行截取
df.show(2,False) 
+---------+---+------+
|name     |age|gender|
+---------+---+------+
|LiLei    |15 |male  |
|HanMeiMei|16 |female|
+---------+---+------+
only showing top 2 rows
#count
df.count()
3
#collect
df.collect()
[Row(name='LiLei', age=15, gender='male'),
 Row(name='HanMeiMei', age=16, gender='female'),
 Row(name='DaChui', age=17, gender='male')]
#first
df.first()
Row(name='LiLei', age=15, gender='male')
#take
df.take(2)
[Row(name='LiLei', age=15, gender='male'),
 Row(name='HanMeiMei', age=16, gender='female')]
#head
df.head(2)
[Row(name='LiLei', age=15, gender='male'),
 Row(name='HanMeiMei', age=16, gender='female')]

2,类RDD操作

DataFrame支持RDD中一些诸如distinct,cache,sample,foreach,intersect,except等操作。

可以把DataFrame当做数据类型为Row的RDD来进行操作,必要时可以将其转换成RDD来操作。

df = spark.createDataFrame([("Hello World",),("Hello China",),("Hello Spark",)]).toDF("value")
df.show()
+-----------+
|      value|
+-----------+
|Hello World|
|Hello China|
|Hello Spark|
+-----------+
#map操作,需要先转换成rdd
rdd = df.rdd.map(lambda x:Row(x[0].upper()))
dfmap = rdd.toDF(["value"]).show()
+-----------+
|      value|
+-----------+
|HELLO WORLD|
|HELLO CHINA|
|HELLO SPARK|
+-----------+
#flatMap,需要先转换成rdd
df_flat = df.rdd.flatMap(lambda x:x[0].split(" ")).map(lambda x:Row(x)).toDF(["value"])
df_flat.show()
+-----+
|value|
+-----+
|Hello|
|World|
|Hello|
|China|
|Hello|
|Spark|
+-----+
#filter过滤
df_filter = df.rdd.filter(lambda s:s[0].endswith("Spark")).toDF(["value"])

df_filter.show()
+-----------+
|      value|
+-----------+
|Hello Spark|
+-----------+
# filter和broadcast混合使用
broads = sc.broadcast(["Hello","World"])

df_filter_broad = df_flat.filter(~col("value").isin(broads.value))

df_filter_broad.show() 
+-----+
|value|
+-----+
|China|
|Spark|
+-----+
#distinct
df_distinct = df_flat.distinct()
df_distinct.show() 

+-----+
|value|
+-----+
|World|
|China|
|Hello|
|Spark|
+-----+
#cache缓存
df.cache()
df.unpersist()
#sample抽样
dfsample = df.sample(False,0.6,0)

dfsample.show()  
+-----------+
|      value|
+-----------+
|Hello China|
|Hello Spark|
+-----------+
df2 = spark.createDataFrame([["Hello World"],["Hello Scala"],["Hello Spark"]]).toDF("value")
df2.show()
+-----------+
|      value|
+-----------+
|Hello World|
|Hello Scala|
|Hello Spark|
+-----------+
#intersect交集
dfintersect = df.intersect(df2)

dfintersect.show()
+-----------+
|      value|
+-----------+
|Hello Spark|
|Hello World|
+-----------+
#exceptAll补集

dfexcept = df.exceptAll(df2)
dfexcept.show()

+-----------+
|      value|
+-----------+
|Hello China|
+-----------+

3,类Excel操作

可以对DataFrame进行增加列,删除列,重命名列,排序等操作,去除重复行,去除空行,就跟操作Excel表格一样。

df = spark.createDataFrame([
("LiLei",15,"male"),
("HanMeiMei",16,"female"),
("DaChui",17,"male"),
("RuHua",16,None)
]).toDF("name","age","gender")

df.show()
df.printSchema()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
|   DaChui| 17|  male|
|    RuHua| 16|  null|
+---------+---+------+

root
 |-- name: string (nullable = true)
 |-- age: long (nullable = true)
 |-- gender: string (nullable = true)
#增加列
dfnew = df.withColumn("birthyear",-df["age"]+2020)

dfnew.show() 
+---------+---+------+---------+
|     name|age|gender|birthyear|
+---------+---+------+---------+
|    LiLei| 15|  male|     2005|
|HanMeiMei| 16|female|     2004|
|   DaChui| 17|  male|     2003|
|    RuHua| 16|  null|     2004|
+---------+---+------+---------+
#置换列的顺序
dfupdate = dfnew.select("name","age","birthyear","gender")
dfupdate.show()
#删除列
dfdrop = df.drop("gender")
dfdrop.show() 
+---------+---+
|     name|age|
+---------+---+
|    LiLei| 15|
|HanMeiMei| 16|
|   DaChui| 17|
|    RuHua| 16|
+---------+---+
#重命名列
dfrename = df.withColumnRenamed("gender","sex")
dfrename.show() 
+---------+---+------+
|     name|age|   sex|
+---------+---+------+
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
|   DaChui| 17|  male|
|    RuHua| 16|  null|
+---------+---+------+

#排序sort,可以指定升序降序
dfsorted = df.sort(df["age"].desc())
dfsorted.show()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|   DaChui| 17|  male|
|    RuHua| 16|  null|
|HanMeiMei| 16|female|
|    LiLei| 15|  male|
+---------+---+------+
#排序orderby,默认为升序,可以根据多个字段
dfordered = df.orderBy(df["age"].desc(),df["gender"].desc())

dfordered.show()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|   DaChui| 17|  male|
|HanMeiMei| 16|female|
|    RuHua| 16|  null|
|    LiLei| 15|  male|
+---------+---+------+
#去除nan值行
dfnotnan = df.na.drop()

dfnotnan.show()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
|   DaChui| 17|  male|
+---------+---+------+
#填充nan值
df_fill = df.na.fill("female")
df_fill.show()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
|   DaChui| 17|  male|
|    RuHua| 16|female|
+---------+---+------+
#替换某些值
df_replace = df.na.replace({"":"female","RuHua":"SiYu"})
df_replace.show()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
|   DaChui| 17|  male|
|     SiYu| 16|  null|
+---------+---+------+
#去重,默认根据全部字段
df2 = df.unionAll(df)
df2.show()
dfunique = df2.dropDuplicates()
dfunique.show()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
|   DaChui| 17|  male|
|    RuHua| 16|  null|
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
|   DaChui| 17|  male|
|    RuHua| 16|  null|
+---------+---+------+

+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    RuHua| 16|  null|
|   DaChui| 17|  male|
|HanMeiMei| 16|female|
|    LiLei| 15|  male|
+---------+---+------+
#去重,根据部分字段
dfunique_part = df.dropDuplicates(["age"])
dfunique_part.show()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|   DaChui| 17|  male|
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
+---------+---+------+

#简单聚合操作
dfagg = df.agg({"name":"count","age":"max"})

dfagg.show()
+-----------+--------+
|count(name)|max(age)|
+-----------+--------+
|          4|      17|
+-----------+--------+

#汇总信息
df_desc = df.describe()
df_desc.show()
+-------+------+-----------------+------+
|summary|  name|              age|gender|
+-------+------+-----------------+------+
|  count|     4|                4|     3|
|   mean|  null|             16.0|  null|
| stddev|  null|0.816496580927726|  null|
|    min|DaChui|               15|female|
|    max| RuHua|               17|  male|
+-------+------+-----------------+------+
#频率超过0.5的年龄和性别
df_freq = df.stat.freqItems(("age","gender"),0.5)

df_freq.show()
+-------------+----------------+
|age_freqItems|gender_freqItems|
+-------------+----------------+
|         [16]|          [male]|
+-------------+----------------+

4,类SQL表操作

类SQL表操作主要包括表查询(select,selectExpr,where),表连接(join,union,unionAll),表分组(groupby,agg,pivot)等操作。

df = spark.createDataFrame([
("LiLei",15,"male"),
("HanMeiMei",16,"female"),
("DaChui",17,"male"),
("RuHua",16,None)]).toDF("name","age","gender")

df.show()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
|   DaChui| 17|  male|
|    RuHua| 16|  null|
+---------+---+------+
#表查询select
dftest = df.select("name").limit(2)
dftest.show()
+---------+
|     name|
+---------+
|    LiLei|
|HanMeiMei|
+---------+
dftest = df.select("name",df["age"] + 1)
dftest.show()
+---------+---------+
|     name|(age + 1)|
+---------+---------+
|    LiLei|       16|
|HanMeiMei|       17|
|   DaChui|       18|
|    RuHua|       17|
+---------+---------+
#表查询select
dftest = df.select("name",-df["age"]+2020).toDF("name","birth_year")
dftest.show()
+---------+----------+
|     name|birth_year|
+---------+----------+
|    LiLei|      2005|
|HanMeiMei|      2004|
|   DaChui|      2003|
|    RuHua|      2004|
+---------+----------+
#表查询selectExpr,可以使用UDF函数,指定别名等
import datetime
spark.udf.register("getBirthYear",lambda age:datetime.datetime.now().year-age)
dftest = df.selectExpr("name", "getBirthYear(age) as birth_year" , "UPPER(gender) as gender" )
dftest.show()
+---------+----------+------+
|     name|birth_year|gender|
+---------+----------+------+
|    LiLei|      2005|  MALE|
|HanMeiMei|      2004|FEMALE|
|   DaChui|      2003|  MALE|
|    RuHua|      2004|  null|
+---------+----------+------+
#表查询where, 指定SQL中的where字句表达式
dftest = df.where("gender='male' and age>15")
dftest.show()
+------+---+------+
|  name|age|gender|
+------+---+------+
|DaChui| 17|  male|
+------+---+------+
#表查询filter
dftest = df.filter(df["age"]>16)
dftest.show()
+------+---+------+
|  name|age|gender|
+------+---+------+
|DaChui| 17|  male|
+------+---+------+
#表查询filter
dftest = df.filter("gender ='male'")
dftest.show()
+------+---+------+
|  name|age|gender|
+------+---+------+
| LiLei| 15|  male|
|DaChui| 17|  male|
+------+---+------+
#表连接join
dfscore = spark.createDataFrame([("LiLei","male",88),("HanMeiMei","female",90),("DaChui","male",50)]) \
          .toDF("name","gender","score") 

dfscore.show()
+---------+------+-----+
|     name|gender|score|
+---------+------+-----+
|    LiLei|  male|   88|
|HanMeiMei|female|   90|
|   DaChui|  male|   50|
+---------+------+-----+
#表连接join,根据单个字段
dfjoin = df.join(dfscore.select("name","score"),"name")
dfjoin.show()
+---------+---+------+-----+
|     name|age|gender|score|
+---------+---+------+-----+
|    LiLei| 15|  male|   88|
|HanMeiMei| 16|female|   90|
|   DaChui| 17|  male|   50|
+---------+---+------+-----+
#表连接join,根据多个字段
dfjoin = df.join(dfscore,["name","gender"])
dfjoin.show()
+---------+------+---+-----+
|     name|gender|age|score|
+---------+------+---+-----+
|HanMeiMei|female| 16|   90|
|   DaChui|  male| 17|   50|
|    LiLei|  male| 15|   88|
+---------+------+---+-----+
#表连接join,根据多个字段
#可以指定连接方式为"inner","left","right","outer","semi","full","leftanti","anti"等多种方式
dfjoin = df.join(dfscore,["name","gender"],"right")
dfjoin.show()
+---------+------+---+-----+
|     name|gender|age|score|
+---------+------+---+-----+
|HanMeiMei|female| 16|   90|
|   DaChui|  male| 17|   50|
|    LiLei|  male| 15|   88|
+---------+------+---+-----+

dfjoin = df.join(dfscore,["name","gender"],"outer")
dfjoin.show()
+---------+------+---+-----+
|     name|gender|age|score|
+---------+------+---+-----+
|HanMeiMei|female| 16|   90|
|   DaChui|  male| 17|   50|
|    LiLei|  male| 15|   88|
|    RuHua|  null| 16| null|
+---------+------+---+-----+
#表连接,灵活指定连接关系
dfmark = dfscore.withColumnRenamed("gender","sex")
dfmark.show()
+---------+------+-----+
|     name|   sex|score|
+---------+------+-----+
|    LiLei|  male|   88|
|HanMeiMei|female|   90|
|   DaChui|  male|   50|
+---------+------+-----+

dfjoin = df.join(dfmark,(df["name"] == dfmark["name"]) & (df["gender"]==dfmark["sex"]),
        "inner")
dfjoin.show()
+---------+---+------+---------+------+-----+
|     name|age|gender|     name|   sex|score|
+---------+---+------+---------+------+-----+
|HanMeiMei| 16|female|HanMeiMei|female|   90|
|   DaChui| 17|  male|   DaChui|  male|   50|
|    LiLei| 15|  male|    LiLei|  male|   88|
+---------+---+------+---------+------+-----+

#表合并union
dfstudent = spark.createDataFrame([("Jim",18,"male"),("Lily",16,"female")]).toDF("name","age","gender")
dfstudent.show()
+----+---+------+
|name|age|gender|
+----+---+------+
| Jim| 18|  male|
|Lily| 16|female|
+----+---+------+
dfunion = df.union(dfstudent)
dfunion.show()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    LiLei| 15|  male|
|HanMeiMei| 16|female|
|   DaChui| 17|  male|
|    RuHua| 16|  null|
|      Jim| 18|  male|
|     Lily| 16|female|
+---------+---+------+
#表分组 groupBy
from pyspark.sql import functions as F 
dfgroup = df.groupBy("gender").max("age")
dfgroup.show()
+------+--------+
|gender|max(age)|
+------+--------+
|  null|      16|
|female|      16|
|  male|      17|
+------+--------+
#表分组后聚合,groupBy,agg
dfagg = df.groupBy("gender").agg(F.mean("age").alias("mean_age"),
   F.collect_list("name").alias("names"))
dfagg.show()
+------+--------+---------------+
|gender|mean_age|          names|
+------+--------+---------------+
|  null|    16.0|        [RuHua]|
|female|    16.0|    [HanMeiMei]|
|  male|    16.0|[LiLei, DaChui]|
+------+--------+---------------+

#表分组聚合,groupBy,agg
dfagg = df.groupBy("gender").agg(F.expr("avg(age)"),F.expr("collect_list(name)"))
dfagg.show()

+------+--------+------------------+
|gender|avg(age)|collect_list(name)|
+------+--------+------------------+
|  null|    16.0|           [RuHua]|
|female|    16.0|       [HanMeiMei]|
|  male|    16.0|   [LiLei, DaChui]|
+------+--------+------------------+

#表分组聚合,groupBy,agg
df.groupBy("gender","age").agg(F.collect_list(col("name"))).show()
+------+---+------------------+
|gender|age|collect_list(name)|
+------+---+------------------+
|  male| 15|           [LiLei]|
|  male| 17|          [DaChui]|
|female| 16|       [HanMeiMei]|
|  null| 16|           [RuHua]|
+------+---+------------------+

#表分组后透视,groupBy,pivot
dfstudent = spark.createDataFrame([("LiLei",18,"male",1),("HanMeiMei",16,"female",1),
                    ("Jim",17,"male",2),("DaChui",20,"male",2)]).toDF("name","age","gender","class")
dfstudent.show()
dfstudent.groupBy("class").pivot("gender").max("age").show()
+---------+---+------+-----+
|     name|age|gender|class|
+---------+---+------+-----+
|    LiLei| 18|  male|    1|
|HanMeiMei| 16|female|    1|
|      Jim| 17|  male|    2|
|   DaChui| 20|  male|    2|
+---------+---+------+-----+

+-----+------+----+
|class|female|male|
+-----+------+----+
|    1|    16|  18|
|    2|  null|  20|
+-----+------+----+
#窗口函数

df = spark.createDataFrame([("LiLei",78,"class1"),("HanMeiMei",87,"class1"),
                           ("DaChui",65,"class2"),("RuHua",55,"class2")]) \
    .toDF("name","score","class")

df.show()
dforder = df.selectExpr("name","score","class",
         "row_number() over (partition by class order by score desc) as order")

dforder.show()
+---------+-----+------+
|     name|score| class|
+---------+-----+------+
|    LiLei|   78|class1|
|HanMeiMei|   87|class1|
|   DaChui|   65|class2|
|    RuHua|   55|class2|
+---------+-----+------+

+---------+-----+------+-----+
|     name|score| class|order|
+---------+-----+------+-----+
|   DaChui|   65|class2|    1|
|    RuHua|   55|class2|    2|
|HanMeiMei|   87|class1|    1|
|    LiLei|   78|class1|    2|
+---------+-----+------+-----+

六,DataFrame的SQL交互

将DataFrame注册为临时表视图或者全局表视图后,可以使用sql语句对DataFrame进行交互。

不仅如此,还可以通过SparkSQL对Hive表直接进行增删改查等操作。

1,注册视图后进行SQL交互

#注册为临时表视图, 其生命周期和SparkSession相关联
df = spark.createDataFrame([("LiLei",18,"male"),("HanMeiMei",17,"female"),("Jim",16,"male")],
                              ("name","age","gender"))

df.show()
df.createOrReplaceTempView("student")
dfmale = spark.sql("select * from student where gender='male'")
dfmale.show()
+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    LiLei| 18|  male|
|HanMeiMei| 17|female|
|      Jim| 16|  male|
+---------+---+------+

+-----+---+------+
| name|age|gender|
+-----+---+------+
|LiLei| 18|  male|
|  Jim| 16|  male|
+-----+---+------+
#注册为全局临时表视图,其生命周期和整个Spark应用程序关联

df.createOrReplaceGlobalTempView("student")
query = """
 select t.gender
 , collect_list(t.name) as names 
 from global_temp.student t 
 group by t.gender
""".strip("\n")

spark.sql(query).show()
#可以在新的Session中访问
spark.newSession().sql("select * from global_temp.student").show()

+------+------------+
|gender|       names|
+------+------------+
|female| [HanMeiMei]|
|  male|[LiLei, Jim]|
+------+------------+

+---------+---+------+
|     name|age|gender|
+---------+---+------+
|    LiLei| 18|  male|
|HanMeiMei| 17|female|
|      Jim| 16|  male|
+---------+---+------+

2,对Hive表进行增删改查操作

#删除hive表

query = "DROP TABLE IF EXISTS students" 
spark.sql(query) 

#建立hive分区表
#(注:不可以使用中文字段作为分区字段)

query = """CREATE TABLE IF NOT EXISTS `students`
(`name` STRING COMMENT '姓名',
`age` INT COMMENT '年龄'
)
PARTITIONED BY ( `class` STRING  COMMENT '班级', `gender` STRING  COMMENT '性别')
""".replace("\n"," ")
spark.sql(query) 
##动态写入数据到hive分区表
spark.conf.set("hive.exec.dynamic.partition.mode", "nonstrict") #注意此处有一个设置操作
dfstudents = spark.createDataFrame([("LiLei",18,"class1","male"),
                                    ("HanMeimei",17,"class2","female"),
                                    ("DaChui",19,"class2","male"),
                                    ("Lily",17,"class1","female")]).toDF("name","age","class","gender")
dfstudents.show()

#动态写入分区
dfstudents.write.mode("overwrite").format("hive")\
.partitionBy("class","gender").saveAsTable("students")
#写入到静态分区
dfstudents = spark.createDataFrame([("Jim",18,"class3","male"),
                                    ("Tom",19,"class3","male")]).toDF("name","age","class","gender")
dfstudents.createOrReplaceTempView("dfclass3")

#INSERT INTO 尾部追加, INSERT OVERWRITE TABLE 覆盖分区
query = """
INSERT OVERWRITE TABLE `students`
PARTITION(class='class3',gender='male') 
SELECT name,age from dfclass3
""".replace("\n"," ")
spark.sql(query)
#写入到混合分区
dfstudents = spark.createDataFrame([("David",18,"class4","male"),
                                    ("Amy",17,"class4","female"),
                                    ("Jerry",19,"class4","male"),
                                    ("Ann",17,"class4","female")]).toDF("name","age","class","gender")
dfstudents.createOrReplaceTempView("dfclass4")

query = """
INSERT OVERWRITE TABLE `students`
PARTITION(class='class4',gender) 
SELECT name,age,gender from dfclass4
""".replace("\n"," ")
spark.sql(query)
#读取全部数据

dfdata = spark.sql("select * from students")
dfdata.show()
+---------+---+------+------+
|     name|age| class|gender|
+---------+---+------+------+
|      Ann| 17|class4|female|
|      Amy| 17|class4|female|
|HanMeimei| 17|class2|female|
|   DaChui| 19|class2|  male|
|    LiLei| 18|class1|  male|
|     Lily| 17|class1|female|
|    Jerry| 19|class4|  male|
|    David| 18|class4|  male|
|      Jim| 18|class3|  male|
|      Tom| 19|class3|  male|
+---------+---+------+------+

公众号后台回复关键字:pyspark,获取本项目github地址。

SparkSQL的3种Join实现 本文简单介绍SparkSQL中的几种Join实现。SparkSQL会根据用户配置,对不同大小的表应用不同的Join策略,兼顾效率和稳定性。 阅读详情

相关推荐

一天入门大数据开发:Hadoop+Hive+SparkSQL单机环境搭建与全流程实战

面对海量数据处理需求,分布式存储与计算框架是构建现代数据基础设施的核心。其基本原理在于将数据分散存储在多台机器上,并通过并行计算框架高效处理,从而实现高吞吐、高容错的数据分析能力。这一技术价值在于,它使得企业能够以可扩展、低成本的方式处理PB级数据,将数据从成本中心转化为决策资产。典型应用场景包括用户行为日志分析、离线数据仓库构建和商业智能报表生成。本文聚焦于大数据开发的工程实践,通过搭建一个集成了Hadoop、Hive和SparkSQL的单机伪分布式环境,手把手演示如何将本地数据导入HDFS,并使用Hiv

congjukun0600的博客 357

大数据技术之Spark——Spark SQL

我们之前学习过hive,hive是一个基于hadoop的SQL引擎工具,目的是为了简化mapreduce的开发。由于mapreduce开发效率不高,且学习较为困难,为了提高mapreduce的开发效率,出现了hive,用SQL的方式来简化mapreduce:hive提供了一个框架,将SQL转换成mapreduce来执行。执行的效率不会因此提升,但开发效率会大大提高。

five小点心的博客 6030

SparkSQL中30多个count distinct导致2小时慢查询?揭秘Expand节点数据膨胀的坑

本文深入解析SparkSQL中多个count distinct操作导致的性能问题,揭示Expand节点数据膨胀机制。通过实际案例展示如何优化30多个count distinct查询,从SQL改写、参数调优到数据预处理,提供全方位解决方案,显著提升执行效率并减少shuffle数据量。

weixin_33704234的博客 395

Spark SQL 核心编程

SparkSQL 核心编程

m0_72168501的博客 986

HiveSQL与SparkSQL对比分析

HiveSQL:本质是一个“翻译器”。它将你编写的 SQL 查询翻译成MapReduce任务在 Hadoop 上运行。它擅长稳定的、超大规模数据的批处理,但延迟较高。SparkSQL:本质是核心框架的一个组件。它将 SQL 查询翻译成基于内存的计算任务。它同样擅长批处理,并且因为内存计算而速度极快,同时还支持流处理、机器学习和图计算。HiveSQLSparkSQL核心比喻可靠但缓慢的货运轮船快速灵活的快艇关键技术MapReduce(磁盘迭代)Spark RDD(内存迭代)最佳场景。

走过冬季 902

pyspark笔记(RDD,DataFrame和Spark SQL)

spark,pyspark,dataframe,spark sql

算法工程师 3689

spark 通过df进行sql处理

object DataOperation { def main(args: Array[String]): Unit = { val spark = SparkSession.builder().master("local").appName("data-operation").getOrCreate() //1.读取json进行sql处理 // jsonFile(spark) //2.读取text进行sql处理 textFile(spark) //3....

qq_41458071的博客 886

手机摄影新宠:In-line Hardware EIS如何让你的4K视频稳如鸡头(附实测对比)

本文深入解析了手机摄影中的In-line Hardware EIS(硬件级行内电子图像稳定)技术。通过对比传统软件EIS,阐述了其通过硬件管道实时处理实现极低延迟、减少画面裁切和有效抑制果冻效应的核心优势,并结合4K视频的日夜间实测,展示了该技术如何让手持拍摄的视频“稳如鸡头”,显著提升创作体验与成片质量。

tree的博客 994

qt5编程入门 第2版_2小时入门SparkSQL编程

一,RDD,DataFrame和DataSetDataFrame参照了Pandas的思想,在RDD基础上增加了schma,能够获取列名信息。DataSet在DataFrame基础上进一步增加了数据类型信息,可以在编译时发现类型错误。DataFrame可以看成DataSet[Row],两者的API接口完全相同。DataFrame和DataSet都支持SQL交互式查询,可以和 Hive无缝衔接。Dat...

weixin_40008920的博客 794

汇川H5U搭配步进伺服电机使用CANopen通讯控制电机案例

摘要:本文介绍了基于汇川H5U PLC和STM4260B-CANopen-M步进伺服电机的控制系统搭建流程。主要内容包括:硬件准备(PLC、伺服电机、24V电源)、电机参数默认设置(地址1号、1M波特率)、使用AutoShop软件编写程序(配置CANopen参数、导入电机描述文件、设置PDO参数)以及功能块编程(使能控制、速度控制、绝对位置控制等)。通过查阅通讯手册完成各功能块参数配置,最终在主程序中调用功能块实现控制系统开发。该方案适用于需要精确运动控制的工业自动化场景。

m0_46512607的博客 1596

保姆级教程:用杰理701N可视化SDK搞定ANC降噪配置(从工具到代码全流程)

本文提供了一份详细的杰理701N可视化SDK配置ANC降噪功能的教程,涵盖从开发环境搭建到代码集成的全流程。通过图形化工具和代码示例,帮助开发者快速掌握ANC参数配置技巧,优化降噪效果,解决常见问题。

weixin_30616969的博客 451

dataframe 取2列_2小时入门SparkSQL编程

一,RDD,DataFrame和DataSetDataFrame参照了Pandas的思想,在RDD基础上增加了schma,能够获取列名信息。DataSet在DataFrame基础上进一步增加了数据类型信息,可以在编译时发现类型错误。DataFrame可以看成DataSet[Row],两者的API接口完全相同。DataFrame和DataSet都支持SQL交互式查询,可以和 Hive无缝衔...

weixin_29799175的博客 528

Isaac Sim仿真平台学习(2)系统架构

isaac sim系统架构

weixin_75067193的博客 2699

SparkSQL groupBy的使用

数据格式(消费者ID 消费时间 消费金额) 1 12:01 100 1 12:02 200 1 12:50 100 2 12:50 100 3 13:01 200 需求:统计每个小时,每个用户的消费总额 思路步骤: 1、id加上时间的小时部分(前两位)作为key 2、使用sparkSQl里面的 groupby.agg()方法 groupby(“id”,“time”).agg(sum(“cous...

UniqueChunBlog 9496

report_delay_calculation/check_timing/report_annotated_parasitics/report_analysis_coverge

如何debug 一颗cell 或一段net 的delay, 常用的办法是用report_delay_calculation 报这颗cell 或这段net, 会得到形式如下的report, 从该report 中可以得到: 表头需要特别关注的是command, 确定report 的对象及加的option; From/To pin: cell 的input pin 和...

diedai7174的博客 1798

ISP Tuning实战:从零开始调校相机传感器的完整流程(附避坑指南)

本文详细介绍了ISP Tuning的完整实战流程,即如何从零开始调校相机传感器以优化成像质量。内容涵盖从黑电平校正、镜头阴影校正等基础标定,到自动曝光、伽马校正、色彩校正等核心画质调校,再到降噪与锐化的平衡策略,并提供了关键的避坑指南。掌握ISP Tuning是提升相机传感器性能、实现从‘能用’到‘好用’的关键技术。

weixin_32098457的博客 196

SparkSQL优化

主要介绍了sparksql执行计划查看,参数优化,SQL优化(HIVE适用)等内容

me_to_007的博客 1万+

基于matlab不变矩的数字验证码识别系统

随着互联网技术的快速发展和应用,网络给人们提供了丰富的资源和极大的便利,但随之而来的是互联网系统的安全性问题,而验证码正是加强 Web 系统安全性的产物。全自动区分计算机和人类的图灵测试(Completely Automated Public Turing test to tell Computers and Humans Apart,CAPTCHA)也是验证码的一个应用程序,可以区分用户是人类还是计算机智能单击对象。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 917

SparkSQL中30个count distinct导致2小时慢查询?揭秘Expand节点数据膨胀的坑

本文深入分析了SparkSQL中多个count distinct操作导致慢查询的问题,揭示了Expand节点数据膨胀的机制及其对执行效率的影响。通过实际案例和性能指标对比,提供了参数调优、SQL重写和Bitmap精确去重等多层次优化方案,帮助开发者有效提升查询性能。

weixin_29170327的博客 418

一套C#接口通吃安川/发那科/库卡:工业机器人统一控制框架设计与产线踩坑实录

我们把机器人的通用能力抽象为接口,涵盖连接、运动、IO、寄存器、状态、报警六大类能力,所有品牌适配器都必须实现这个接口。/// 工业机器人统一控制接口// 基础连接// 运动控制// IO与寄存器// 状态与报警// 事件工业机器人统一控制框架的本质,不是把所有品牌的功能都做平,而是找到通用能力的最大公约数,通过分层抽象把品牌差异隔离在底层。上层业务只关注工艺和流程,不需要关心机器人是什么品牌、用什么SDK、通信协议是什么。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 404

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

HiveSQL和SparkSQL的区别

维度HiveSQLSparkSQL性能中等(依赖执行引擎)✅ 高(原生内存计算)功能传统批处理✅ 批+流+ML兼容性✅ 完全 Hive 兼容高度兼容,略有差异生态Hadoop 生态Spark 生态学习成本低(SQL 标准)低(SQL 标准)适用场景传统数仓现代数仓 + 实时分析💡核心结论HiveSQL:企业级数仓的稳定选择,兼容性好,适合传统批处理场景;SparkSQL:现代化数据处理的首选,性能优异,功能丰富,适合批流统一场景。在实际生产中,

走过冬季 1311

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

sparksql 操作hive_SparkSQL 在有赞的实践

文 | 邹晨俊 on 大数据前言有赞数据平台从 2017 年上半年开始,逐步使用 SparkSQL 替代 Hive 执行离线任务,目前 SparkSQL 每天的运行作业数量5000个,占离线作业数目的55%,消耗的 cpu 资源占集群总资源的50%左右。本文介绍由 SparkSQL 替换 Hive 过程中碰到的问题以及处理经验和优化建议,包括以下方面的内容:有赞数据平台的整体架构。SparkSQL...

weixin_26913055的博客 213

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Spark每日半小时(23)——SparkSQL概览及入门

上面讲了Spark结构化数据的一些点,今天就正式走入Spark官方文档的学习了。发现由于版本问题,老书真的是不能看了。今天正好根据Spark变成指南的SparkSQL开始进入正题,嗯嗯,很合适。 概览 SparkSQL是用于结构化数据处理的Spark模块。与基本的Spark RDD API不同,Spark SQL提供的接口为Spark提供了有关数据结构和正在执行的计算的更多信息。在内部,Spa...

DK_ing的博客 423

SparkSQL性能调优

最近在学习spark时,觉得Spark SQL性能调优比较重要,所以自己写下来便于更过的博友查看,同时也希望大家给我指出我的问题和不足 在spark中,Spark SQL性能调优只要是通过下面的一些选项进行优化的: 1 spark.sql.codegen 默认值为false,当它设置为true时,Spark SQL会把每条查询的语句在运行时编译为java的二进制代码。这有什么作用呢?它可以提高

YQlakers的博客 9511

sparksql优化_SparkSQL 在有赞的实践

文 | 邹晨俊 on 大数据前言有赞数据平台从 2017 年上半年开始,逐步使用 SparkSQL 替代 Hive 执行离线任务,目前 SparkSQL 每天的运行作业数量5000个,占离线作业数目的55%,消耗的 cpu 资源占集群总资源的50%左右。本文介绍由 SparkSQL 替换 Hive 过程中碰到的问题以及处理经验和优化建议,包括以下方面的内容:有赞数据平台的整体架构。SparkSQL...

weixin_39964660的博客 142
上一篇: 7道RDD编程练习题
下一篇: 7道SparkSQL编程练习题
算法美食屋
博客等级 码龄9年 2万+粉丝 154原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值