一、环境配置
本次实训采用3台机器搭建集群环境和软件如下:
(1)Windows操作系统:Windows 10
(2)Python:3.8.10
(3)Hadoop:3.3.4
(4)Spark:3.3.2
(5)Bottle:v0.12.25环境配置如下:
3台机器搭建集群环境
第一台机器配置信息:hadoop1 192.168.32.143
第二台机器配置信息:hadoop2 192.168.32.144
第三台机器配置信息:hadoop3 192.168.32.145
已将设置 hadoop1为yarn集群为主机
三台机器已运行成功:
Bottle是一个快速、简洁、轻量级的基于WSIG的微型Web框架,此框架除了Python的标准库外,不依赖任何其他模块。安装方法是,打开Linux终端,执行如下命令:
sudo apt-get install python3-pip
pip3 install bottle
二、数据获取与存储
本项目的数据从Kaggle的一个跨国在线零售业务的交易数据获取,存储于HDFS分布式文件系统,
首先,在hdfs上创建一个新的目录,并将数据集E_Commerce_Data.csv上传至hdfs上,命令如下:
hdfs dfs -put E_Commerce_Data.csv
hdfs dfs -ls /user/Hadoop
现已将E_Commerce_Data文件传入虚拟机中
将E_Commerce_Data.csv从虚拟机上传至HDFS
接着,使用如下命令进入pyspark的交互式编程环境,对数据进行初步探索和清洗:
在spark环境目录下:
./bin/pyspark
(1) 读取在HDFS上的文件,以csv的格式读取,得到DataFrame对象。
df=spark.read.format(‘com.databricks.spark.csv’).options(header=‘true’,inferschema=‘true’).load('E_Commerce_Data.csv’)
(2) 查看数据集的大小,输出541909,不包含标题行
df.count()
(3) 可以使用printSchema()操作打印出DataFrame的模式信息
(4) 创建临时视图data。
df.createOrReplaceTempView(“data”)
(5) 由于顾客编号CustomID和商品描述Description均存在部分缺失,所以进行数据清洗,过滤掉有缺失值的记录。特别地,由于CustomID为integer类型,所以该字段若为空,则在读取时被解析为0,故用df[“CustomerID”]!=0 条件过滤。
clean=df.filter(df[“CustomerID”]!=0).filter(df[“Description”]!=“”)
(6) 查看清洗后的数据集的大小,输出406829。
clean.count()
(7) 数据清洗结束。根据作业要求,预处理后需要将数据写入HDFS。将清洗后的文件以csv的格式,写入E_Commerce_Data_Clean.csv中(实际上这是目录名,真正的文件在该目录下,文件名类似于part-00000),需要确保HDFS中不存在这个目录,否则写入时会报“already exists”错误。
clean.write.format(“com.databricks.spark.csv”).options(header=‘true’,inferschema=‘true’).save(‘E_Commerce_Data_Clean.csv’)
至此,数据预处理完成。现在去HDFS中的Web端查看数据是否清洗成功
接下来将使用python编写应用程序,对清洗后的数据集进行统计分析。
三、 数据导入
- 创建project.py文件,用于编写应用程序。
首先,导入需要用到的python模块。 - 接着,获取spark sql的上下文。
conf = SparkConf().setMaster(‘local’).setAppName(‘spark_project’)
sc=SparkContext(conf=conf)
sc.setLogLevel(‘WARN’)
spark = SparkSession.builder.getOrCreate()
- 最后,从HDFS中以csv的格式读取清洗后的数据目录E_Commerce_Data_Clean.csv,程序会取出该目录下的所有数据文件,得到DataFrame对象,并创建临时视图data用于后续分析。
df=spark.read.format(‘com.databricks.spark.csv’).options(header=‘true’,inferschema=‘true’).load(‘E_Commerce_Data_Clean.csv’)
df.createOrReplaceTempView(“data”) //创建一个表名为“data”的表
4. 为方便统计结果的可视化,将结果导出为json文件供web页面渲染。使用save方法导出数据:
def save(path, data):
with open(path, ‘w’) as f:
f.write(data)
数据准备工作完成,接下来对数据进行分析。
四、 数据分析
数据分析部分分为概览和关系两个部分
- 概论:
- 客户数最多的10个国家
每个客户由编号CustomerID唯一标识,所以客户的数量为COUNT(DISTINCT CustomerID),再按照国家Country分组统计,根据客户数降序排序,筛选出10个客户数最多的国家。得到的countryCustomerDF为DataFrame类型,执行collect()方法即可将结果以数组的格式返回。
countryCustomerDF=spark.sql(“SELECT Country,COUNT(DISTINCT CustomerID) AS countOfCustomer FROM data GROUP BY Country ORDER BY countOfCustomer DESC LIMIT 10”)
最后调用save方法就可以将结果导出至文件了,格式如:[国家名称,客户数]
可视化图展示:
2) 销量最高的10个国家
Quantity字段表示销量,因为退货的记录中此字段为负数,所以使用SUM(Quantity)即可统计出总销量,即使有退货的情况。再按照国家Country分组统计,根据销量降序排序,筛选出10个销量最高的国家。得到的countryQuantityDF为DataFrame类型,执行collect()方法即可将结果以数组的格式返回。
countryQuantityDF = spark.sql(“SELECT Country,SUM(Quantity) AS sumOfQuantity FROM data GROUP BY Country ORDER BY sumOfQuantity DESC LIMIT 10”)
最后调用save方法就可以将结果导出至文件了,格式如:[国家名称,销量]
可视化展示:
3) 各个国家的总销售额分布情况
UnitPrice 字段表示单价,Quantity字段表示销量,退货的记录中Quantity字段为负数,所以使用SUM(UnitPrice*Quantity)即可统计出总销售额,即使有退货的情况。再按照国家Country分组统计,计算出各个国家的总销售额。得到的countrySumOfPriceDF为DataFrame类型,执行collect()方法即可将结果以数组的格式返回。
countrySumOfPriceDF=spark.sql(“SELECT Country,SUM(UnitPrice*Quantity) AS sumOfPrice FROM data GROUP BY Country”)
最后调用save方法就可以将结果导出至文件了,格式如:[商品编号,销量]
可视化展示: