【项目总结】NewStart——PySpark学习笔记

序言

MARSIPM项目后期要在Azure平台上搭算法系统,终归要把之前所有用pandas做数据处理的代码全部重构成PySpark,作为小白从前辈的口中得知PySpark“世界上最烂的语言”后决定笨鸟先飞,既然早晚要承受痛苦,那还是提早做点准备罢,反正答辩完也没什么直接压力了,权当学些新东西了。今天就先把安装指南记录一下,因为PySpark的安装涉及到系统环境的修改,而现在我必须在有公司加密系统的系统备份上使用,以后从公司离开回到之前正常的系统备份后可能还需要重新配置PySpark,留个记录免得到时候不知道怎么改。

预想可能会在这篇博客持续更新一些PySpark的学习内容,到这个岁数总归是技多不压身,多学一点总是没坏处。近期可能会更新一些其他感兴趣的方面的博客,毕竟很久没有做些好玩的事情了,假如时间充裕的话。

PySpark安装指南(WIN10)

首先简单介绍一下PySparkPySpark是基于python语言对Spark数据处理框架的封装,涉及对DataLake, DataBase, DataFrame等多种形式数据的处理,内部还封装了一些统计机器学习,统计分析等模块。相比于传统的pandas数据处理包,PySpark不仅在内容上更加丰富,更重要的是PySpark在处理逻辑上更加优化,使用分布式处理使得在运行上占据更少的内存,提升算法效率。

PySpark的安装教程似乎没有其他人写得那么复杂,需要配置HADOOPJDKSCALA等系统环境,这些一般都是在服务器上部署所需要的,如果只是在PC机上做入门性质的学习,并不需要这么繁琐。

因为笔者之前有Java编程开发的经历,JDK环境是现成的(Java 9.0.4)。从之后PySpark的使用来看,应该只有JDK环境是必须的,其他两个并不必须。关于JDK环境搭建的方法是比较简单的,可以很容易地找到教程。在此不多作赘述,谨以博主renlianggee的相关博客JDK的环境变量配置作为援引。

配置好JDK环境后下载PySpark安装包即可,在pypi官网https://pypi.org/project/pyspark/可以找到setuptar包下载,截至至本文发布,PySpark最新版为2.4.5,下载后解压如下图所示👇

 

 

在解压后的目录下打开cmd输入安装指令,等待安装完成即可。

python setup.py install

不出意外的话就安装完成了,运行一段测试代码看看是否可以运行👇

from pyspark import SparkConf, SparkContext
sc = SparkContext("local", "First App")
print(sc)
 

如果没有发生任何问题,那实在是万幸,但是大概率在以上步骤中会出现一些问题,笔者就自己遇到的问题做一个汇总,也是方便以后需要再次安装时参考。

1. 在安装前需要提前使用pip安装好pypandoc库,

2. 在运行测试代码时,可能会出现如下报错👇

java.io.IOException: Could not locate executable null\bin\winutils.exe in the Hadoop binaries.

出现这个问题的原因是没有配置HADOOP环境,但是我们也不需要特别去配置HADOOP环境,只需要下载应用程序winutils.exe,这里提供下载链接👇

链接:https://pan.baidu.com/s/1-fyyR2aXZXC7w17DXYGMEw 
提取码:fe04 

下载好后在任意目录新建文件夹winutils,并将winutils.exe放置在该文件夹下的bin目录中(如下图所示,笔者将其放在E:/Python/libs/winutils/bin中)👇

接着设置在环境变量的系统变量中新建变量名HADOOP_HOME,值为winutils文件夹的路径,并将%HADOOP_HOME%\bin添加到系统变量Path中👇

重启计算机运行就不会再出现上述的Error了 。

 


 

2020.05.20更新

入门教程

PySpark的语法满满的js风格,很多语法都与python常用习惯相去甚远。让人头痛欲裂(主要是过一遍就全忘了,只能靠常用才能熟练),http://spark.apache.org/docs/latest/api/python/index.html是官方提供的V2.4.5的文档,经过一段时间的入门,笔者认为PySpark主要是基于数据库查询语言SQL展开的数据处理,不过因为Spark框架中架构了python函数以及java函数的引入接口,使得在SQL时可以用函数辅助得到查询或运算结果,建议先从pyspark.sql模块开始学习,pyspark主模块下的方法太抽象,对于我们这种常年不碰JavaSQL菜鸟来说不借助pyspark.sql中的例子很难理解。这里仅做一些入门的示例以及说明,主要是对PySpark有一个初始的印象,后续一些点可能还是会另开新篇进行汇总。

PySpark除了sql模块主要用于做数据处理外,还有mlmllib两个模块用于统计及机器学习分析。目前主要就数据处理这块做个入门先。

# 1 SparkSession 模块
1. 处理数据集的入口
2. 用于生成DataFrame, 操作SQL, 读取parquet文件
3. 属性builder:
  - appName(name)  
    + 设置应用名称(在UI界面展示)
  - config(key=None,value=None,conf=None)  
    + 设置一个配置的键值对
  - enableHiveSupport()  
    + 启用Hive支持
  - getOrCreate()
    + 如果没有全局的SparkSession对象,就以当前配置创建一个新的作为全局对象
    + 如果有则会将当前配置应用到全局对象中去
  - master(master)
    + 分配一个url: 如"local\[4\]"表示本地四核运行, "spark://master:7077"表示在集群上运行
4. 属性catalog
5. 属性conf

# 2 类SQLContext(sparkContext,sparkSession=None,sqlContext=None) 
1. 结构性数据处理入口
2. 构造函数
3. 方法createDataFrame(data,schema=None,samplingRatio=None,verifySchema=True)
  - data: RDD, list, pandas.DataFrame(用于创建DataFrame的数据源)
  - schema: 基本就是列字段名, 最常见即传入一个列字段名的列表, 也可以是一个Row对象

4. 方法createExternalTable(tableName, path=None, source=None, schema=None,**options)
5. 方法dropTempTable(tableName)
6. 方法getConf(key,defaultValue=None)
  - 如果key存在则返回value, 否则创建新的key并返回defaultValue;
  - 可以用setConf(key,value)方法来创建键值对
7. 类方法getOrCreate(sc): sc为SparkContext
8. 方法range: sqlContext.range(1,7,2).collect()
  - 返回\[Row(id=1),Row(id=3),Row(id=7)\]
9. 方法read: 返回DataFrameReader
10. 方法registerDataFrameAsTable(df,tableName)
  - 将df转为table
11. 方法sql(sqlQuery): 返回sql语句的查询结果
12. 方法table(tableName): 查看一张表(将转为DataFrame)
13. 方法tableNames(dbName=None): 返回db中的所有表(返回值为list of string)
14. 方法tables(dbName=None): 返回db中的所有表(返回值为DataFrame)
  - 返回值为df, 可以使用df.filter("tableName = 'table1'")来指定一张表
15. 方法uncacheTable(tableName): 清理缓存的表

# 3 类 UDFRegistration(sparkSession)
1. 注册封装的函数, 该类下的方法可以用spark.udf或sqlContext.udf访问
2. 方法register(name,f,returnType=None) 注册Python函数
  - python函数
  - 自定义函数(udf)
3. 方法registerJavaFunction(name,javaClassName,returnType=None) 注册Java函数

# 4 类 DataFrame

 

以下对上面的Markdown提纲做一些例子说明👇

# SparkSession对象创建示例
spark = SparkSession.builder.master("local").appName("Word Count").config("spark.some.config.option", "some-value").getOrCreate()
# SQLContext对象创建示例
sc = SparkContext("local","test1")
sqlContext=SQLContext(sc) 
# builder.config方法示例
from pyspark.conf import SparkConf
SparkSession.builder.config(conf=SparkConf())
# builder.getOrCreate()方法示例
s1 = SparkSession.builder.config("k1","v1").getOrCreate()
print(s1.conf.get("k1")==s1.sparkContext.getConf().get("k1")=="v1")
s2 = SparkSession.builder.config("k2","v2").getOrCreate()
print(s1.conf.get("k1")==s2.conf.get("k1"))
print(s1.conf.get("k2")==s2.conf.get("k2"))
# CreateDataFrame方法示例

# Example 1 从tuple列表中生成DataFrame
print("========= Example 1 ==========")
l = [('Alice', 1)]
print(spark.createDataFrame(l).collect())
print(spark.createDataFrame(l,['name','age']).collect())

# Example 2 从dict列表中生成DataFrame(最熟悉的)
print("========= Example 2 ==========")
d = [{'name': 'Alice', 'age': 1}]
print(spark.createDataFrame(d).collect())

# Example 3 从rdd生成DataFrame
print("========= Example 3 ==========")
rdd = sc.parallelize(l) # 利用包含多个tuple列表
print(spark.createDataFrame(rdd).collect())
df = spark.createDataFrame(rdd,['name', 'age'])
print(df.collect())

# Example 4 利用Row对象确定字段名
print("========= Example 4 ==========")
from pyspark.sql import Row
Person = Row('name', 'age')
person = rdd.map(lambda r: Person(*r))
df2 = sqlContext.createDataFrame(person)
print(df2.collect())

# Example 5 结构体/SQL字典式生成dataFrame
print("========= Example 5 ==========")
from pyspark.sql.types import *

schema = StructType([
    StructField("name", StringType(), True),
    StructField("age", IntegerType(), True)])

df3 = sqlContext.createDataFrame(rdd, schema)
print(df3.collect())

# Example 6 利用pandas的结果导入
print("========= Example 6 ==========")
print(sqlContext.createDataFrame(df.toPandas()).collect())  
print(sqlContext.createDataFrame(pandas.DataFrame([[1, 2]])).collect())

# Example 7
print("========= Example 7 ==========")
print(sqlContext.createDataFrame(rdd, "a: string, b: int").collect()) # 确定
rdd = rdd.map(lambda row: row[1])
print(sqlContext.createDataFrame(rdd, "int").collect()) # 取int的结果输出
print(sqlContext.createDataFrame(rdd, "boolean").collect()) # 会报错: 因为没有布尔型的结果

 

# registerDataFrameAsTable方法示例
sqlContext.registerDataFrameAsTable(df3,"df3")
# sql方法示例
df2 = sqlContext.sql("SELECT * from df3")
df2.collect()
# tables方法示例
dfs = sqlContext.tables()
result = dfs.filter("tableName = 'df3'")
print(result)
print(result.first())

 

# udf.register方法示例

# Example 1 当f为python函数
print("========= Example 1 ==========")
# 1.1
strlen = spark.udf.register("stringLengthString", lambda x: len(x))
print(spark.sql("SELECT stringLengthString('test')").collect())
print(spark.sql("SELECT 'foo' AS text").select(strlen("text")).collect())
# 1.2
_ = spark.udf.register("stringLengthInt", lambda x: len(x), IntegerType())
print(spark.sql("SELECT stringLengthInt('test')").collect())
# 1.3
_ = spark.udf.register("stringLengthInt", lambda x: len(x), IntegerType())
print(spark.sql("SELECT stringLengthInt('test')").collect())

# Example 2 当f为自定义函数
print("========= Example 2 ==========")
## 2.1
slen = udf(lambda s: len(s), IntegerType())
_ = spark.udf.register("slen", slen)
print(spark.sql("SELECT slen('test')").collect())
## 2.2 
random_udf = udf(lambda: random.randint(0, 100), IntegerType()).asNondeterministic()
new_random_udf = spark.udf.register("random_udf", random_udf)
print(spark.sql("SELECT random_udf()").collect())
## 2.3 pandas_udf示例
pandas_udf("integer", PandasUDFType.SCALAR)  
def add_one(x):
    return x + 1
_ = spark.udf.register("add_one", add_one)
print(spark.sql("SELECT add_one(id) FROM range(3)").collect())

## 2.4 
pandas_udf("integer", PandasUDFType.GROUPED_AGG)  
def sum_udf(v):
    return v.sum()
_ = spark.udf.register("sum_udf", sum_udf)  
q = "SELECT sum_udf(v1) FROM VALUES (3, 0), (2, 0), (1, 1) tbl(v1, v2) GROUP BY v2"
#print(spark.sql(q).collect()) # 会报错: 应该会输出[Row(sum_udf(v1)=1), Row(sum_udf(v1)=5)]

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值