Spark的基础编程
Spark的一些基本概念
1.RDD:弹性分布式数据集,是分布式内存的一个抽象概念,提供了一种高度受限的共享内容模型,即RDD是只读的记录分区的集合,只能基于稳定的物理存储中的数据集来创建RDD,或者通过其它RDD上执行确定的转换操作(如map,join,group by)来创建,这些限制使得实现容错的开销很低。
一个RDD 就是一个分布式对象集合,作为数据结构,RDD本质上是一个只读的分区记录集合,每个RDD可以分成多个分区,每个分区就是一个数据集片段,并且一个RDD的不同分区可以保存到集群上不同的节点上,从而在集群不同的节点上进行并行运算。
2.DAG:有向无环图,反应了RDD之间的依赖关系。
3.Executor:执行者,运行在工作节点(WorkerNode)上的一个进程,负责运行任务(Task),并为应用程序存储数据。
4.Driver:驱动,在local(本机)模式下,驱动程序Driver就是执行了一个Spark Application的main函数和创建Spark Context的进程,包含这个应用的全部代码。
5.Application:应用,用户编写的Spark应用程序。
6.Task:任务,运行在Executer上的工作单元。
7.Job:作业,一个作业包含多个RDD及作用于相应RDD上的各种操作。
8.Stage:阶段,是作业(Job)的基本调度单位,一个作业(Job)会分为多组任务(Task),每组任务就被称为‘阶段’,也被称为任务集。
RDD编程操作
Spark是以RDD为中心运行的,RDD编程是Spark开发的核心,Spark对数据的所有操作不外乎创建RDD,转化已有的RDD以及调用RDD操作进行求值。
1.RDD操作的两种类型【Transformation与Action】
RDD可以被看作Spark的一个对象,它本身运行与内存中,如读文件是一个RDD,计算文件是一个RDD,结果集也是一个RDD,不同的分片,数据之间的依赖,key-value类型的map数据都可以被看作RDD。
Spark针对RDD 的操作包括RDD的转化操作(创建RDD)和RDD行动操作,也就是说RDD的操作分为“转换(Transformation)和行动(Action)”两种操作类型,这也是两个操作阶段,这两类操作的主要区别是:Transformation操作接收RDD并返回RDD,Action操作接收RDD,但返回非RDD(输出一个值或者一个结果)。RDD操作是一种‘惰性操作’,在转换操作阶段没有实施真正的计算,在行动阶段才将转换操作真正实施。
(1)RDD转换操作
对于RDD而言,每一次转换操作都会产生不同的RDD,以供给下一个转换使用。转换得到的RDD是“惰性”求值的,也就是说,整个转换过程只记录了转换的轨迹,并不发生真正的计算,只有遇到行动操作时才会发生真正的计算。
常用的Transformation操作如下表:
类型 | 转换函数 | 含义 |
---|---|---|
map(func) | 返回一个新的RDD,该RDD由每个输入元素经过func函数转换后组成 | |
一般RDD | filter(func) | 返回一个新的RDD,该RDD经由func函数计算后返回值为true的输入元素组成 |
flatMap(func) | 类似于map(func),但是每个输入元素可以被映射为0或多个输出元素(所以func函数应该返回一个序列,而不是单个元素) | |
groupByKey() | 在一个(K,V)的RDD上调用,返回一个(K,Iterator[V])的RDD | |
键值对RDD | reduceByKey(func,[numTasks]) | 在一个(K,V)的RDD上调用,返回一个(K,V)的RDD,使用指定的reduce函数,将key相同的值聚合在一起,与groupByKey()类似,reduce任务的个数可以通过第二个可选参数来设置 |
sortByKey([ascending],[numTasks]) | 在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key值进行排序的(K,V)的RDD | |
mapValues(func) | 对键值对每个value应用函数func,key不变 |
(2)RDD的行动操作
行动操作是真正触发计算的操作。Spark程序执行到行动操作时才会执行真正的计算,从文件或数组中加载数据,完成一次又一次的转换操作,直至得到结果。
常用的Action操作如下表:
行动(方法) | 含义 |
---|---|
count() | 返回RDD数据集中的元素个数 |
collect() | 以数组的形式返回RDD数据集中的所有元素 |
first() | 返回RDD数据集中的第一个元素 |
take(n) | 以数组的形式返回RDD数据集中的前n个元素 |
reduce(func) | 通过函数func(输入两个参数并返回一个值)聚合数据集中的元素 |
foreach(func) | 将RDD数据集中的每个元素传递到函数func中运行 |
2.创建RDD
1.相关知识点
(1)变量sc
每个Spark应用程序都需要一个Spark环境,它为Spark RDD API 交互实现提供主要的入口点。在Spark Shell下,有一个专有的SparkContext已经创建好了,变量名叫做“sc”,负责配置Spark环境;同时提供一个名为‘spark’的变量,负责预配置Spark会话。sc变量只能在Spark命令界面下使用,在python独立程序中则需要先导入SparkContext,再定义sc变量。sc变量就是Spark RDD编程的入口,sc实际就是SparkContext的简称。
(2)SparkContext
SparkContext在Spark应用程序的执行中起主导作用,负责与程序和Spark集群进行交互,包括申请集群资源,创建RDD,实现累加与广播变量等。
任何Spark程序的编写都是从SparkContext开始的。SparkContext是整个项目程序的入口,无论是从本地还是HDFS读取文件,或者通过集合并行化获得RDD,都要先创建SparkContext对象,然后使用SparkContext对象对RDD进行创建和后续的转换操作。Spark Shell操作命令中的sc就代表的是SparkContext对象。使用SparkContext创建RDD主要有两种方法:textFile方法(从文件创建),parallelize方法(从数组创建)。
(3)创建RDD的两种方式
第一种:读取一个外部数据集,比如从本地文件加载数据集,或者从HDFS,Hbase,Cassandra,Amazon S3等外部数据源加载数据集。Spark可以支持文本文件,SequenceFile文件(Hadoop提供的SequenceFile文件是一个由二进制进行序列化过的key/value的字节流组成的文本存储文件)和其它符合Hadoop InputFormat格式的文件。
第二种:调用SparkContext的 parallelize方法,在Driver中一个已经存在的集合(数组)上创建RDD。
2.第一种RDD创建方式【从文件系统中加载数据创建RDD】
在linux本地终端的目录下创建一个文本文件,输入内容,启动Hadoop,将该文本文件上传到HDFS。
cd ~
sudo gedit word.txt
#在该文件中输入一下内容
Hello China
Hello World
你好世界
你好中国
#保存文件,上传到HDFS
start-dfs.sh
hdfs dfs -put word.txt ./input
启动PySpark,从本地文件系统和HDFS中加载数据。
(1)本地加载文件创建RDD【textFile(“路径”)】
进入spark shell界面:pyspark
lines = sc.textFile("file:///home/hadoop/word.txt")
type(lines)
lines.foreach(print)#使用行动操作foreach(print)方法遍历查看
for line in lines.collect():#数组(列表)遍历
print(line)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qIhvCdid-1608632057638)(D:\Huawei Share\Screenshot\rdd第一种创建方式.bmp)]
【我的spark地址有问题所以大家不用管,然后文件地址自己可以看着修改一下,不知道为什么foreach(print)打印出来有点小问题,hdfs方式获取打印的没问题,大家不要介意,自己动手试一下】
(2)从HDFS中加载数据创建RDD
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g98c7i5Q-1608632057642)(D:\Huawei Share\Screenshot\hdfs创建rdd.bmp)]
注意:本地创建RDD textFile的文件名参数格式"file://+完整地址";从HDFS加载文件创建RDD直接使用HDFS的路径和文件名即可。
3.通过并行集合(数组)创建RDD(第二种创建方式)
可以调用SparkContext的parallelize方法,在Driver中一个已经存在的集合(数组)上创建RDD。
nums = [1,2,3,4,5]
rdd = sc.parallelize(nums)
for n in rdd.collect():
print(n)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5lDz6ALp-1608632057644)(D:\Huawei Share\Screenshot\parallelize方法创建rdd.bmp)]
4.使用Spark独立应用程序编程完成RDD常见的转换操作和行动操作
正对各个元素的转换操作,先讲解最常用的map(),filter(),flatMap()函数。
【实例1】计算RDD中各值的平方。
from pyspark import SparkContext
sc = SparkContext('local[*]','test1')#第一个参数表示本地cpu资源
nums = sc.parallelize([1,2,3,4,5])#parallelize转换操作,创建RDD
squared = nums.map(lambda x : x * x).collect()#map转换以及collect行动操作返回列表
for num in squared:
print(num,end=' ')
print('')
【实例2】从列表[1,2,3,4]中获得大于2的值。
from pyspark import SparkContext
sc = SparkContext('local[*]','test2')
nums = sc.parallelize([1,2,3,4,5])
squared = nums.filter(lambda x : x > 2).foreach(print)
【实例3】切分单词。
from pyspark import SparkContext
sc = SparkContext('local[*]','test3')
words = sc.textFile('./input/word.txt')
word = words.flatMap(lambda line : line.split(" "))
word.foreach(print)
5.创建键值对RDD
(1).第一种创建方式:从文件中加载
在pyspark shell中输入:
lines = sc.textFile('word.txt')
kvRDD = lines.flatMap(lambda line : line.split(' ')).map(lambda word : (word,1))
kvRDD.foreach(print)
###lines包含了多行文本的内容
###lines.flatMap(lambda line:line.split(" "))会遍历textFile中的每行文本内容,遍历到其中一行时会把文本内容赋值给line,并执行lambda表达式
###line:line.split(" ") ':'左边代表输入参数,右边代表函数里面的执行逻辑
###lines.flatMap()操作就把多个单词集合‘拍扁’,得到一个大的单词集合
###针对这个大的单词集合执行map操作
###最后得到一个RDD 它的每个元素都是k/v形式的tuple
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QtwtAeSB-1608632057646)(D:\Huawei Share\Screenshot\kv分割单词.bmp)]
(2).第二种创建方式:通过并行集合(列表)创建
list = ['spark','hadoop','gu']
rdd = sc.parallelize(list)
kvRDD = rdd.map(lambda word:(word,1))
kvRDD.foreach(print)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dKEyzhIw-1608632057647)(D:\Huawei Share\Screenshot\第二种创建rdd方式切分单词.bmp)]
(3).常用的键值对转换操作
常用的键值对转换操作有:reduceByKey(),groupByKey(),sortByKey(),join(),count()等。
1>.reduceByKey(func)
功能:使用func函数合并具有相同键的值。
#实例4
from pyspark import SparkContext
sc = SparkContext('local[*]','test4')
words = sc.parallelize(['hello word','hadoop','i love hadoop','spark','i love spark','spark is fast then hadoop'])
word = words.flatMap(lambda line : line.split(" ")).map(lambda word : (word,1))
#word.foreach(print)
word.reduceByKey(lambda a,b : a+b).foreach(print)
2>.groupByKey()
功能:对具有相同键的值进行分组。
#实例5
from pyspark import SparkContext
sc = SparkContext('local[*]','test3')
words = sc.textFile('./input/word.txt')
word = words.flatMap(lambda line : line.split(" ")).map(lambda word : (word,1))
#word.foreach(print)
result = word.groupByKey().collect()
res = [(x,sorted(y)) for (x,y) in result]
print('groupbykey:')
word.groupByKey().foreach(print)
print('zc:\n{}'.format(res))
3>.keys(),values(),count()
功能:返回键值对RDD中的键,值,形成一个新的RDD,返回一个int值,RDD的元素个数
#实例6
from pyspark import SparkContext
sc = SparkContext('local[*]','test3')
list = [('spark',1),('hadoop',3),('spark',2),('hadoop',4),('gu',8)]
rdd = sc.parallelize(list)
#rdd.foreach(print)
rdd.keys().foreach(print)
rdd.values().foreach(print)
print(rdd.count())
for n in rdd.mapValues(lambda x:x+1).collect():
print(n)
4>.mapValues(func)
从RDD到DataFrame
Spark SQL 和 DataFrame
1. Spark SQL的简介
Spark SQL是spark套件中一个模板,它将数据的计算任务通过SQL的形式转换成了RDD的计算,类似于Hive通过SQL的形式将数据的计算任务转换成了MapReduce。它是用于结构化数据处理,半结构化数据处理的Spark高级模块,可以先从以上数据源中读取数据,然后在Spark程序中通过SQL语句对数据进行交互式查询,进而实现数据分析,也可以通过标准数据库连接器(JDBC/ODBC)连接传统关系型数据库,取出并转化关系数据库表,利用Spark SQL 进行数据分析。
结构化数据是指记录的内容要有明确的结构信息,且数据集内的每条记录都符合结构规范的数据集合,是由二维表结构来逻辑表达和实现的数据集合。可以类比传统数据库表来理解该定义,‘明确的结构’ 即由预定义的表头(Schema)表示每条记录由哪些字段组成,以及各个字段的名称,类型,属性等信息。
结构化,半结构化数据的来源:
1.json(半结构化)文件。
2.csv文件。
3.orc文件(一种Hive的文件存储格式,可以提高Hive表的读写能力,以及数据处理性能)。
4.Hive表。
5.Parquest文件。
Spark SQL的特点:
1、和Spark Core的无缝集成,可以在写整个RDD应用的时候,配置Spark SQL来完成逻辑实现。
2、统一的数据访问方式,Spark SQL提供标准化的SQL查询。
3、Hive的继承,Spark SQL通过内嵌的hive或者连接外部已经部署好的hive案例,实现了对hive语法的继承和操作。
4、标准化的连接方式,Spark SQL可以通过启动thrift Server来支持JDBC、ODBC的访问,将自己作为一个BI Server使用
Spark SQL数据抽象:
1、RDD(Spark1.0)->DataFrame(Spark1.3)->DataSet(Spark1.6)
2、Spark SQL提供了DataFrame和DataSet的数据抽象
3、DataFrame就是RDD+Schema,可以认为是一张二维表格,劣势在于编译器不进行表格中的字段的类型检查,在运行期进行检查
4、DataSet是Spark最新的数据抽象,Spark的发展会逐步将DataSet作为主要的数据抽象,弱化RDD和DataFrame.DataSet包含了DataFrame所有的优化机制。除此之外提供了以样例类为Schema模型的强类型
5、DataFrame=DataSet[Row]
6、DataFrame和DataSet都有可控的内存管理机制,所有数据都保存在非堆上,都使用了catalyst进行SQL的优化。
Spark SQL客户端查询:
1、可以通过Spark-shell来操作Spark SQL,spark作为SparkSession的变量名,sc作为SparkContext的变量名
2、可以通过Spark提供的方法读取json文件,将json文件转换成DataFrame
3、可以通过DataFrame提供的API来操作DataFrame里面的数据。
4、可以通过将DataFrame注册成为一个临时表的方式,来通过Spark.sql方法运行标准的SQL语句来查询。
2. SparkSQL 的实现途径--------------->DataFrame
与RDD类似,DataFrame也是一个分布式数据容器。然而DataFrame更像传统数据库的二维表格,除了数据以外,还记录数据的结构信息,即schema(表头)。同时,与Hive类似,DataFrame也支持嵌套数据类型(struct、array和map)。从API易用性的角度上 看,DataFrame API提供的是一套高层的关系操作,比函数式的RDD API要更加友好,门槛更低。由于与R和Pandas的DataFrame类似,Spark DataFrame很好地继承了传统单机数据分析的开发体验。
若需要处理的数据集是典型的结构化数据源,可以在Spark程序中引入Spark SQL模块,先读取待处理数据并将其转化为Spark SQL的核心数据抽象---->DataFrame,再调用DataFrame API对数据进行分析处理。也可以将DataFrame注册成表,直接使用SQL语句进行交互式查询。
3.DataFrame与RDD的区别
RDD和DataFrame均为Spark平台对数据的一种抽象,是一种组织方式,但是两者的地位或者说是设计目的截然不同。RDD是Spark平台存储,计算及任务调度的逻辑基础,更具有通用性,适用于各类数据源;然而DataFrame只针对结构化数据源的高层数据抽象,在DataFrame对象的创建过程中必须指定数据集的结构信息(Schema),所以DataFrame具有专用性的数据抽象,只能读取具有鲜明结构的数据集。
创建样例数据文件
1.json样例数据文件:people.json
{'name':'Michael'}
{'name':'Andy','age':30}
{'name':'Justin','age':19}
2.创建文本样例文件:people.txt
张三,29,78.82
李四,30,89.9
王五,19,92.34
3.创建csv格式样例文件:people.csv[以utf-8格式保存]
4.上传样例文件到hdfs
start-dfs.sh#启动hdfs
hdfs dfs -put people.json ./input
读取json与csv文件生成DatFrame
1.从本地读取json与csv文件生成DataFrame并显示数据
从Spark2.0开始,Spark使用全新的SparkSession接口代替Spark1.6中的SQLContext及HiveContext接口,以实现数据加载,转换,处理等功能。
#from pyspark.sql.session import SparkSession #独立编程时需要导入这个,在SparkShell下不必导入
spark = SparkSession.builder.getOrCreate()#获取SparkSession,创建SparkSession对象spark
dfJSON = spark.read.json("file:///home/hadoop/test/people.json") #json ---> DataFrame
dfCSV = spark.read.csv("file:///home/hadoop/test/people.csv") #csv ---> DataFrame
dfJSON.show() #显示DataFrame数据
dfCSV.show(2) #显示前两行
#依据DataFrame创建临时视图people
dfCSV.createOrReplaceTempView("people") #在临时视图上可进行SQL操作
2.从hdfs读取json与csv文件生成DataFrame并显示数据
#from pyspark.sql.session import SparkSession #独立编程时需导入
spark = SparkSession.builder.getOrCreate()
dfJSON = spark.read.json("./input/people.json") #json ---> DataFrame
dfCSV = spark.read.csv("./input/people.csv") #csv ---> DataFrame
dfJSON.show() #显示DataFrame数据
dfCSV.show(2) #显示前两行
#依据DataFrame创建临时视图people
dfCSV.createOrReplaceTempView("people") #在临时视图上可进行SQL操作
3.常见的DataFrame操作
dfCSV.print()#打印图表信息,以树结构显示表结构信息
dfCSV.select(df.name,df.age+2).show()#选择多列,对于数值型列可以进行算术操作之后输出相应结果。
dfCSV.filter(df.age>20)#条件过滤
dfCSV.groupBy('age').count().show()#按列分组聚合
dfCSV.sort(dfCSV.age.desc()).show()#排序 desc()降序 asc()升序
dfCSV.sort(dfCSV.age.desc(),dfCSV.name.asc()).show()#多列排序
dfCSV.select(dfCSV.name.alias("username"),df.age).show()#对列进行重命名
普通文本文件生成DataFrame
普通文本文件是指不带表头(Schema)的文本文件
有两种方法:(1).利用反射来推断包含特定类型对象的RDD的schema(已知表结构模式),这种方法适用于已知数据结构的RDD转换;(2).使用编程接口构造一个schema,并将其应用在已知的RDD上。以下代码均为第二种。
1.导入软件支持包
from pyspark.sql.types import Row
from pyspark.sql.types import StructType
from pyspark.sql.types import StructField
from pyspark.sql.types import StringType
from pyspark.sql.types import IntegerType
from pyspark.sql.types import DoubleType
from pyspark.sql.types import LongType
from pyspark.sql.types import FloatType
2.生成RDD
#单独程序 还需导入下列包 并生成SparkContext对象sc
from pyspark import SparkContext
sc = SparkContext('local[*]','程序名称')#从定义SparkContext开始编程 第一个参数表示本地cpu资源
#spark shell中不需要上面
peopleRDD = sc.textFile("./input/people.txt")#确保启动hadoop 文件在该目录下
peopleRDD.foreach(print)#查看该RDD
3.设定schema(表头或者结构信息)
设定DataFrame 各列类型信息,必须知道RDD所有类型的信息才可以。该文本的内容我们已经知到,而RDD对象是由该文件转换过来的,所以schema 定义如下:
schema = StructType([
StructField('name',StringType()),
StructField('age',IntegerType()),
StructField('score',DoubleType())
])
#可以用df.printSchema()方法查看schema模式中字段集群类型的定义
4.将RDD按字段拆分转换为新的RDD
rowRDD = peopleRDD.map(lambda line : line.split(',')).map(lambda zd : Row(zd[0],int(zd[1]),float(zd[2]))#注意整型与浮点数的强制转换
经map()转换获得新的RDD对象rowRDD,可以用foreach()查看该对象。我们对peopleRDD的每行数据以逗号为分隔符进行拆分,得到的列表元素按原有的属性定义数据类型。
5.将RDD转换为DataFrame
#单独程序中需要定义SparkSession对象spark
from pyspark.sql.session import SparkSession
spark = SparkSession.builder.getOrCreate()
#spark shell中不需要上面代码
df = spark.createDataFrame(rowRDD,schema) #将RDD配上表头
6.显示结果与结构
df.show()
df.printSchema()
7.注册为临时表,供spark.sql查询使用
df.createOrReplaceTempView('people') #创建临时视图people
results = spark.sql('select * from people') #定义SparkSQL语句
#转换为RDD
results.rdd.map(lambda ar : "name:" + ar[0] + "," + "age:" + str(ar[1]) + "," + "score:" + str(ar[2])).foreach(print)
8.读取文件的独立Spark应用程序
from pyspark import SparkContext #创建sc支持
from pyspark.sql import SparkSession #创建SparkSession和spark支持
from pyspark.sql.types import Row
from pyspark.sql.types import StructType
from pyspark.sql.types import StructField
from pyspark.sql.types import IntegerType
from pyspark.sql.types import StringType
from pyspark.sql.types import DoubleType
from pyspark.sql.types import LongType
from pyspark.sql.types import FloatType
sc = SparkContext('local','people') #创建sc支持
peopleRDD = sc.textFile("./people.txt") #转换RDD
schema = StructType([
StructField('name',StringType()),
StructField('age',IntegerType()),
StructField('score',DoubleType())
]) #设置表头
#定义表头结构
rowRDD = peopleRDD.map(lambda line : line.split(',')).map(lambda zd : Row(zd[0],int(zd[1]),float(zd[2])))
#----------spark 读取文件------------
#配置spark(服务器)
#spark = SparkSession.builder.master('master').appName('people_test_script').getOrCreate()
#配置spark(本机)
spark = SparkSession.builder.master('local').appName('people').getOrCreate()
#spark = SparkSession.builder.getOrCreate() #创建spark对象
df = spark.createDataFrame(rowRDD,schema) #RDD--->DataFrame
df.show() #展示
df.printSchema() #显示Schema的信息
df.createOrReplaceTempView("people") #创建临时视图
results = spark.sql('select * from people') #创建sparksql
results.rdd.map(lambda ar : "name:" + ar[0] + "," + "age:" + str(ar[1]) + "," + "score:" + str(ar[2])).foreach(print) #DataFrame----->RDD并遍历输出
#运行spark程序
python3 people.py
Spark综合编程与python数据可视化
Spark综合编程
分析网站日志文件:data.log
启动hadoop,上传data.log文件到hdfs
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from pyspark import SparkContext #导入SparkContext支持软件类,用来配置sc
from pyspark.sql import SparkSession
from pyspark.sql.types import Row
from pyspark.sql.types import StructType
from pyspark.sql.types import StructField
from pyspark.sql.types import StringType
from pyspark.sql.types import IntegerType
from pyspark.sql.types import DoubleType
from pyspark.sql.types import LongType
from pyspark.sql.types import FloatType
#配置本地sc,它是文件转换为RDD的入口,第一个参数为Spark Master 主机ip或映射主机名,第二个是程序名称,在spark shell 里面直接用sc,不用配置
sc = SparkContext('local','log')
logRDD = sc.textFile('./input/spark/data.log')#从hdfs上读取文件并生成RDD
#表头信息,注意写法
schema = StructType([
StructField('session_id',StringType()),
StructField('cookie_id',StringType()),
StructField('visit_time',StringType()),
StructField('use_id',StringType()),
StructField('age',IntegerType()),
StructField('sex',StringType()),
StructField('visit_url',StringType()),
StructField('visit_os',StringType()),
StructField('browser_name',StringType()),
StructField('visit_ip',StringType()),
StructField('province',StringType()),
StructField('city',StringType()),
StructField('page_id',StringType()),
StructField('goods_id',StringType()),
StructField('shop_id',StringType()),
StructField('flag_id',IntegerType())])
#对文件生成的RDD按行进行处理,便于和schema组合生成DataFrame
rowRDD=logRDD.rdd.map(lambda line:line.split(',')).map(lambda zd:Row(zd[0],zd[1],zd[2],zd[3],int(zd[4]),zd[5],zd[6],zd[7],zd[8],zd[9],zd[10],zd[11],zd[12],zd[13],zd[14],int(zd[15])))
#配置spark,创建SparkSession对象为spark,spark是将RDD转换为DataFrame的入口,主机名,程序名
spark = SparkSession.builder.master('local').appName('log').getOrCreate()
rdd_df = spark.createDataFrame(rowRDD,schema) #生成DataFrame
rdd_df.createOrReplaceTempView('log') #生成临时视图
#spark sql语句查询视图 distinct去重
results = spark.sql("select count(distinct visit_ip) as Count_1,province,city from log group by province,city")
#将临时视图转为RDD输出
rdd = results.map(lambda ar:"省:" + ar[1] + "," + "市:" + ar[2] + "," + "IP个数:" + str(ar[0]))
for i in rdd.collect():
print(i)
#RDD的内存占用大时,可以使用take(n)代替collect()方法,仅查看一部分。
#可视化部分
rdd1 = results.rdd.map(lambda ar : [ar[1]+ar[2],ar[0]])
line1 = rdd1.collect() #以数组的形式返回数据集中的元素 take(n)与collect()方法差不多,一个可以限制数量
py_df = pd.DataFrame(line1,columns=['省市','ip数']) #形成python中的DataFrame,并打印查看
print(py_df)
#plt绘图显示汉字
import matplotlib as mpl
zhfont = mpl.font_manager.FontProperties(fname='/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc')#查看字体
#设置画布编号,大小,颜色
plt.figure(num = 1, figsize = (8, 5), facecolor = '#eeeeff')
#定义x,y轴标题,字号,旋转角度
plt.ylabel('This is Y', fontsize=14)
plt.xlabel('This is X', fontsize=14,rotation=0)
#定义标题
plt.title(u'各省市IP数统计',fontproperties=zhfont,fontsize=25,color='#34546ff')
#添加网格线
plt.grid(True,alpha=0.1,color='#ff0000',linewidth=1)
#配置x,y轴的显示角度和中文显示
plt.xticks(rotation=30,fontproperties=zhfont)
plt.yticks(fontproperties=zhfont)
#绘图:配置图形样式 以及x,y轴的显示内容
#plot:折线图
plt.plot(py_df['省市'],py_df['IP数'])
#bar:竖条形图
#plt.bar(py_df['省市'],py_df['IP数'])
#barh:横条形图
#plt.barh(py_df['省市'],py_df['IP数'])
#scatter:散点图
#plt.scatter(py_df['省市'],py_df['IP数'],s=80,c='red')
#pie:饼图
#plt.pie(py_df['IP数'])
#绘图显示
plt.show()
=zhfont,fontsize=25,color=’#34546ff’)
#添加网格线
plt.grid(True,alpha=0.1,color=’#ff0000’,linewidth=1)
#配置x,y轴的显示角度和中文显示
plt.xticks(rotation=30,fontproperties=zhfont)
plt.yticks(fontproperties=zhfont)
#绘图:配置图形样式 以及x,y轴的显示内容
#plot:折线图
plt.plot(py_df[‘省市’],py_df[‘IP数’])
#bar:竖条形图
#plt.bar(py_df[‘省市’],py_df[‘IP数’])
#barh:横条形图
#plt.barh(py_df[‘省市’],py_df[‘IP数’])
#scatter:散点图
#plt.scatter(py_df[‘省市’],py_df[‘IP数’],s=80,c=‘red’)
#pie:饼图
#plt.pie(py_df[‘IP数’])
#绘图显示
plt.show()
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201222181545240.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNjM2NzA5,size_16,color_FFFFFF,t_70#pic_center)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ivhGw2Vy-1608632057651)(C:\Users\顾念思成\OneDrive\图片\屏幕快照\data.log文件转换rdd.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HjIdPFRm-1608632057652)(C:\Users\顾念思成\OneDrive\图片\屏幕快照\字体位置.png)]