PY => PySpark-Spark SQL

Spark SQL

Spark SQL 分为三类:

  1. SQL
  2. DataFrame (参考pandas,但略有不同)
  3. Datasets (由于python是动态的,所以不支持python)

初始环境:

import findspark
findspark.init()

from pyspark.sql import SparkSession        
spark = SparkSession.builder.appName('myspark').getOrCreate()    # 初始化session
# spark.sparkContext.parallelize([1,2,3,4]).collect()  # 里面包含之前说过的sparkContext
...
中间这部分留给下面写
...
spark.stop()         # 关闭 session

从json导入为df:

df = spark.read.json("file:///home/lin/data/user.json",multiLine=True) 

打印DF字段信息:

df.printSchema() 

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

CRUD

from pyspark.sql import functions as f

# schema就相当于 pandas 指定的 columns, 双层序列,  [2x4] 的样本
df1 = spark.createDataFrame([[1,2,3,4],[5,6,7,8]],schema=['1_c','2_c', '3_c', '4_c'])
+-----+-----+-----+-----+
|1\_col|2\_col|3\_col|4\_col|
+-----+-----+-----+-----+
|    1|    2|    3|    4|
|    5|    6|    7|    8|
+-----+-----+-----+-----+

# lit可以在指定空列的时候,指定 null值, 或者 int型(里面有很多类型,可以发现)
# df2 = df1.withColumn('null_col', f.lit(None)).withColumn('digit_col', f.lit(2))
df2 = df1.withColumn('5_col', df1['4_col']+1)   # 在原来列字段基础上。
df2.show()

df2 = df1.drop('age')        # 删除 age列
df2 = df1.dropna()           # 删除空行
df2 = df1.drop_duplicates()  # 删除重复-行

和"增",差不多,只不过字段,指定为原有字段字符串即可。

下面的讲的(投影、过滤、排序、分组),几乎都是查。

投影

投影所有:

df.show(n=20)        # 默认就是 n=20 只返回 前20条记录

+---+------+--------+
|age|gender|    name|
+---+------+--------+
| 18|   man|zhangsan|
+---+------+--------+

选中某列投影:

df.select('name','age').show()        # 若直接写 '*', 和直接 df.show()是一个效果

+--------+---+
|    name|age|
+--------+---+
|zhangsan| 18|
+--------+---+

或者用另两种方式投影(投影过程可计算):

df.select(df['name'],df['age']+20).show() # 同上,这是另一种写法,注意一下列名
df.select(df.name, df.age+20).show()      # 同上,这是另二种写法,注意一下列名

+--------+----------+
|    name|(age + 20)|
+--------+----------+
|zhangsan|        38|
+--------+----------+

取出前N条DF,并转化为 [ {} , {} ] 格式

df_user.take(1)  # [Row(age=18, name='张三')]
df_user.head(1)  # [Row(age=18, name='张三')]
df_user.first()  # Row(age=18, name='张三')    # 注意,无列表

排序

df_user.head(1)
df_user.sort(df_user.name.desc()).show()

# 另外说明一点, df的每个熟悉都有,一些操作符函数, desc()就是一种操作符函数

过滤:

df.filter( df['age'] > 15).show()

+---+------+----+
|age|gender|name|
+---+------+----+
+---+------+----+

分组:

df.groupBy('name').count().show()

+--------+-----+
|    name|count|
+--------+-----+
|zhangsan|    1|
+--------+-----+

Join

df_user.join(df_user, on=df_user.name==df_user.name, how='inner').show()

+----+---+----+---+
|name|age|name|age|
+----+---+----+---+
|李四| 20|李四| 20 |
|张三| 18|张三| 18 |
+----+---+----+---+
# 特别提醒, 此 Join, 只要都进来是 DF格式的任何数据库,都可 Join
# 比如: MySQL 和 Hive  ,  Json 也可。

储存为临时视图(表), 并调用sql语句:

df.createOrReplaceTempView('user')                  # 创建为 user临时视图
df_sql = spark.sql('select * from user').show()     # spark.sql返回的还是df, 所以要show()

+---+------+--------+
|age|gender|    name|
+---+------+--------+
| 18|   man|zhangsan|
+---+------+--------+

RDD 与 DF互转

RDD -> DF

### RDD -> DF 需要把RDD做成两种格式(任选其一)
### 第一种 Row 格式 
    from pyspark import Row
    rdd_user = spark.sparkContext.parallelize( [('张三',18), ('李四',20)] )
    rdd_user_row = rdd_user.map(lambda x:Row(name=x[0], age=x[1]))
    print(rdd_user_row.collect()) # [Row(age=18, name='张三'), Row(age=20, name='李四')]
    df_user = spark.createDataFrame(rdd_user_row)   
    
### 第二种 [('张三', 18),('李四', 20)]
    rdd_user = spark.sparkContext.parallelize( [('张三',18), ('李四',20)] )
    df_user = rdd_user.toDF(['name', 'age'])        # 给定列名
df_user.show()

DF -> RDD

rdd_row = df_user.rdd.map(lambda x: x.asDict())  # 或者 x.name, x.age取值
rdd_row.collect()  # [{'age': 18, 'name': '张三'}, {'age': 20, 'name': '李四'}]

CSV读写

从HDFS中读取(我们先新建一个CSV并扔到HDFS中),

vi mydata.csv:
    name,age
    zhangsan,18
    lisi, 20

hadoop fs -mkdir /data                 # 在HDFS中新建一个目录 /data
hadoop fs -put mydata.csv /data        # 并把本地 mydata.csv扔进去 (-get可拿出来)

在代码中读取 HDFS数据:

df = spark.read.csv("hdfs:///data/mydata.csv", header=True)  
df.show()
# header=True 代表, csv文件的第一行作为csv的抬头(列名)
# df.write.csv("hdfs:///data/mydata.csv", header=True)   # read改为write就变成了写

Hive读写

Hive的配置与依赖之前讲过了(最值得注意的是需要先启动一个 metadata的服务)
先验传送门:https://segmentfault.com/a/1190000020841646

import findspark
findspark.init()

from pyspark.sql import SparkSession   

spark = SparkSession.builder\
    .appName("Spark Hive Example")\
    .master("local[*]")\
    .config("hive.metastore.uris", "thrift://localhost:9083")\
    .enableHiveSupport()\
    .getOrCreate()

spark.sql("use mydatabase")        # 执行Hive 的 SQL, 切换数据库(前提你得有)

读:

df = spark.table('person').show()  # 直接对表操作 (注意,sql语句也可)

写:

df = spark.table('person')
df2 = df.withColumn('nickname', df.name)  # 稍微变动一下,添一个字段
df2.write.saveAsTable("new_person")       # 写入新表

MySQL读写

读:

# 注意0:有好几种方式,我只列举一个 成对的读写配置。
# 注意1: url中 "hive"是数据库名. 你也可以起为别的名
# 注意2:table的值--"TBLS",  它是 MySQL中"hive库"中的一个表。
# 注意3:特别注意! TBLS不是我们想要的表。他只是一个大表,管理了我们hive的信息
#        TBLS中的 一个列属性 "TBL_NAME" 才是真正我们需要的表!! 

df = spark.read.jdbc(
    url='jdbc:mysql://localhost:3306/hive?user=root&password=123',
    table="TBLS",
    properties={"driver":"com.mysql.jdbc.Driver"},
)

df.show()
df.select("TBL_NAME").show()

写:

df.write.jdbc(
    url='jdbc:mysql://localhost:3306/hive?user=root&password=123',
    table="new_table",
    mode='append',
    properties={"driver": "com.mysql.jdbc.Driver"}
)

# 同是特别注意: 和读一样, 它写入的新表,也是一个整体的表结构。
#     此表的一个列"TBL_NAME",它才对应了我们真正要操作的表

你可能感兴趣的:(pyspark,spark,python,sql)