Spark

spark 是基于内存的计算框架。
RDD是分区的,保存在不同的工作节点上,本质上是一个只读的分区记录集合,数据片段,rdd转换的过程中,因此通过生成新的RDD来完成一个数据修改的目的。
DAG(directed Acyclic Graph):有向无环图
spark集群模式:mesos,yarn,stando
pyspark命令及其常用的参数如下
pyspark --master # 后面不同的参数,表示可以进入不同的交互式环境(单机还是集群)
spark 的运行模式取决于传递给sparkcontext的master url的值,mastr url可以是一下任意一种形式

  1. local 使用一个Worker线程本地化运行SPARK(完全不并行)
  2. local[*] 使用逻辑cpu个数数量的线程本地化运行spark
  3. local[K]:使用K个Worker线程本地化运行SPARK
  4. spark://HOST:PORT 连结到指定的spark standalone master。默认端口是7077
  5. yarn-client 以客户端模式连结YARN集群,集群的位置可以在HADOOP_CONF_DIR环境变量中找到 程序员调试时应用
  6. yarn-cluster 以集群模式连结YARN集群,集群的位置可以在HADOOP_CONF_DIR环境变量中找到
  7. mesos://HOST:PORT 连结到指定的Mesos集群,默认端口5050

在spark中采用本地模式启动pyspark命令主要包含一下参数
--master:这个参数表示当前的pyspark要连接到哪个master
--jars 这个参数用于把相关的JAR包添加到CLASSPATH中,如果有多个jar包,可以使用逗号分隔符连接它们。

采用本地模式,在4个cpu核心上运行pyspark
cd /usr/local/spark       # spark 安装路径
./bin/pyspark --master local[4]
# ./bin/pyspark --master local[4] --jars code.jar   # 可以在CLASSPATH中添加code.jar

exit() 退出交互式环境,返回到linux环境
通过spark-submit运行程序

#开发spark独立应用程序
wordcount.py

from pyspark import SparkConf,SparkContext
conf=SparkConf().setMaster('local').setAppName('My App')   # 生成上下文配置
sc=SparkContext(conf=conf)                                                 # 生成一个sparkcontext对象
logFile='file:///usr/local/spark/README.md'       # 三个///
logData=sc.textFile(logFile,2).cache()                  #生成一个RDD
numAs=logData.filter(lambda line:'a' in line).count()
numBs=logData.filter(lambda line :'b' in line).count()
print("Lines with a:%s,Lines with b: %s" %(numAs,numBs))

执行程序:
python3 WordCount.py 使用python解释器

#通过spark-submit提交应用程序
spark-submit
--master<master-url>
--deploy-mode <deploy-mode>   #部署模式
....# 其他参数
<application-file> #python代码文件
[application-argyments] # 传递给主类的主方法的参数

通过spark-submit提交应用程序

/usr/local/spark/bin/spark-submit  /usr/local/spark/mycode/python/WordCount.py

为了避免其他多余信息对结果产生干扰 ,可以修改log4j的日志信息显示级别

log4j.rootCategory=INFO,console     ---- > 改为log4j.rootCategory=ERROR,console
在集群中运行应用程JAR包
cd /usr/local/spark/            # 进入spark的安装目录
bin/spark-submit \
--master spark://master:7077 \       # 连结集群模式
/usr/local/spark/examples/src/main/python/pi.py 2>&1| grep "Pi is roughly"  # 代码文件

#在集群中运行pyspark
cd /usr/local/spark/            # 进入spark的安装目录
bin/spark-submit --master spark://master:7077       # 连结集群模式,交互是环境
testFile=sc.textFile('hdfs://master:9000/README.md')     #生成一个RDD,集群式双//,本地式file:///
textFile.count()                                                               
textFile.first()   # 取第一行

运行之后查看应用的运行信息

http://master:8080/  

向Hadoop yarn集群管理器提交应用

cd /usr/local/spark/
bin/spark-submit \
--master yarn-client \
/usr/local/spark/examples/src/main/python/pi.py

查看运行状态:tracking url
RDD 创建
spark 的sparkcontext通过textFile(文件系统地址) 读取数据生成内存中的RDD
生成的RDD,源文件中每一行表示一个RDD元素

textFile() 支持的数据类型:分布式文件系统HDFS,本都文件系统,Amazo S3等等

***交互式环境下,系统默认已经生成了sparkContext对象 sc

从分布式文件系统HDFS中加载数据(以下三种方法全部是等价的,可以使用其中任意一种方式)

lines=sc.textFile("hdfs://localhost:9000/user/hadoop/word.txt")
lines=sc.textFile("/user/hadoop/word.txt")   #生成RDD
lines=sc.textFile("word.txt")

通过并并行集合(数组)创建RDD实例

array=[1,2,3,4,5]
rdd=sc.parallelize(array)         # 生成RDD
rdd.foreach(print)                   # 高阶函数

RDD操作
经常用到的transformation操作

filter(func) 
map(func)  #生成的RDD中每个元素都是一个list
flatMap(func)   flat将上面的结果放在一起,将全部的结果混合在一起 ,将字符串打散为单词
groupBykey()    # 分组的结果用迭代器存放
reduceBykey(func)

常见的行动操作Action

count()
collect()
first()
take(n)    # 切片
reduce(fuc)
foreach(func)

RDD持久化

1. persist(MEMORY_ONLY) # 内存不足,替换内容,先进先出
2. persist(MEMORY_AND_DISK)   # 内存不足,存放磁盘

使用unpersist() 手动地把持久化的RDD从缓存中移除

list=['hadoop','spark','hive']
rdd=sc.parallelize(list)

rdd.cache() # 会调用persist(MEMORY_ONLY),但是,语句执行到这并不会缓存rdd,因为
这是的rdd还没有被计算生成
print(rdd.count()) # 第一次行动操作,触发一次真正从头到尾的计算。这是上面的rdd.cache()才会被执行
,把这个rdd存放到缓存中
print(' '.join(rdd.collect())) # 第二次行动操作,不需要触发从头到尾的计算,只需要rdd.cache()才会被
执行,把这个rdd存放到缓存中
分区:rdd分区被保存到不存的节点上
RDD分区的作用,原则,设置分区的方法
增加并行度,减少通讯开销

spark.default.parallelism()
sc.textFile(path,partitionNum)  #partitionNum 用于指定分区个数

可以通过转换操作得到新的rdd时,直接调用repartition方法集合。

len(data.glom().collect())  # 显示data这个rdd的分区数量
rdd=data.reparttition(1)   # 对data这个rdd进行重新分区
#自定义分区方法:
from  pyspark import SparkConf,SparkContext

def Mypartitioner(key):
       print('MyPartitioner is running')
      print(''The key is %d "%key)
	return key %d

def main():
    conf=SparkConf().setMaster('local'.setAppNqme('MyApp'))
    sc=SparkContext(conf=conf)
   data=sc.parallelize(range(10),5)
   data.map(lambdax:(x,1)).partitonBy(10,Mypartitioner).map(lambda x :x[0]).saveAsTextFile
('file:///usr/local/spark/mycode/rdd/partitioner')

if  __name__=="__main__":
main()

键值对RDD
键值对RDD的创建

lines=sc.textFile("file://usr/local/spark/mycode/pairrdd/word.txt")
pairRDD=lines.flatMap(lambda line:line.split('')).map(lambda word:(word,1))  
pairRDD.foreach(print)

常用键值对RDD转换操作

reduceBykey(func)
groupByKey()
keys   提取key
values  提取value
combineByKey    # 不常用
join 表示内连接,将存在共同key的value存放在一起
mapValues(func)   # 对键值中的value进行操作
sortByKey(False/True)   # 排序操作     sortBy()传入lambda按照key或value进行排序

综合实例:

rdd=sc.parallelize([('spark',2),('hadoop',6),('hadoop',3),('spark',4)])
rdd.mapValues(lambda x:(x,1)).reduceByKey(lambda x,y:(x[0]+y[0],x[1]+y[1])) \
.mapValues(lambda x : x[0]/x[1]).collect()    #mapValue是对最外层的value整体做处理
# mapValues(lambda x:(x,1))   对原键值中的值形成子键值对
# .reduceByKey(lambda x,y:(x[0]+y[0],x[1]+y[1]))       #  先按照最外层的key聚合,形成value_list(这里是子键值list)  

文件数据读写
1.本地文件系统的数据读写

textFile=sc.textFile('file:///usr/local/spark/mycode/rdd/word.txt')
把RDD写入文本文件、
textFile.saveAsTextFile("file:///usr/local/spark/mycode/rdd/writeback")     # 写的时候不指定文件,而是目录(分布式环境)
# 用的时候直接加载,会直接把所有的rdd分区数据加载进来

2.分布式文件系统HDFS的数据读写

textFile=sc.textFile('hdfs://localhost:9000/usr/hadoop/word.txt')  # 简写版等价
textFile.saveAsTextFile("writeback")     # 写的时候不指定文件,而是目录(分布式环境)

Hbase(分布式数据库):行键,列族,列限定符,时间戳

行:每个HBase表由若干行组成,每个行由行键(row key)来标记
列限定符:列簇里的数据通过列限定符(或列)来定位
单元格:在HBase表中,通过行,列族和列限定确定一个“单元格”(cell),单元格中存储的数据没有数据类型
,总被视为字节数组byte[]

表:HBase采用表来组织数据,表由行和列组成,列划分为若干列族

列族:一个Hbase表被分组成许多“列族”(Column Family)的集合,它是基本的访问控制单元

时间戳:每个单元格都保存着同一份数据的多个版本,这些版本通过时间戳进行索引。

读写HBase数据

# 用sparkContext提供的newAPIHadoopRDD API将表中的内容以RDD的形式加载到spark中

# sparkOperateHBase.py
from pyspark import SparkConf,SparkContext
conf=SparkConf().setMaster('local').setAppName('ReadHBase')
sc=SparkContext(conf=conf)
host='localhost'
table='student'
conf={"hbase.zookeeper.quorum":host,'hbase.mapreduce.imputtable':table}         # 指定zookeeper的地址,读取表的名称
# 将hbase表格中的数据转化为需要的字符串格式。
keyConv="org.apache.spark.examples.pythonconverters.ImmutableBytesWritableToStringConverter"     #键转换器的转化类
valueConv="org.apache.spark.examples.pythonconverters.HBaseResultToStringConverter"        #指定值的转换器的转化类

hbase_rdd=sc.newAPIHadoopRDD("org.apach.hadoop.hbase.mapreduce.TableInputFormat",         # 调用api
"org.apache.hadoop.hbase.io.ImmutableBytesWritable",    
"org.apache.hadoop.hbase.client.Result",
jeyConverter=keyConv,
valueConverter=valueConv,conf=conf)

count=hbase_rdd.count()
hbase_rdd.cache()
output=hbase_rdd.collect()
for (k,v) in output:
     print(k,v)

向Hbase表中写入数据

from pyspark import SparkConf,SparkContext
conf=SparkConf().setMaster('local').setAppName('ReadHBase')
sc=SparkContext(conf=conf)
host='localhost'
table='student'
conf={"hbase.zookeeper.quorum":host,'hbase.mapreduce.imputtable':table}         # 指定zookeeper的地址,读取表的名称

keyConv="org.apache.spark.examples.pythonconverters.StringToImmutableBytesWritableConverter"     #转换类
valueConv="org.apache.spark.examples.pythonconverters.StringListToPutConverter"        #转化类
conf={"hbase.zookeeper.quorum":host,
'hbase.mapred.outputtable':table,
"mapreduce.outputformat.class":"org.apache.hadoop.hbase.mapreduce.TableOutputFormat",
"mapreduce.job.output.key.calss":"org.apache.hadoop.hbase.io.ImmutableBytesWritable",
 "mapreduce.job.output.value.calss":"org.apach.hadoop.io.Writable"}   
rawData=
['3,info,name,RongCheng','3,info,gender,M','3,info,age,26','4,info,name,Guanhua','4,info,gender,M',"4,info,age,27"]
# info是列族,name是列名称,
sc.parallelize(raw_dat).map(lambda x:(x[0],x.split(,))).saveAsNewAPIHadoopDataset(
conf=conf,keyConverter=keyConv,valueConverter=valueConv)

求top值top.py

from pyspark import SparkConf,SparkContext
conf=SparkConf().setMaster('local').setAppName('ReadHBase')
sc=SparkContext(conf=conf)
lines=sc.textFile("file:///usr/local/spark/mycode/rdd/file")
result1=lines.filter(lambda line:len(line.strip()>0) and (len(line.split(","))==4))
result2=result1.map(lambda x :x.split(",")[2])
result3=result2.map(lambda x : (int(x),""))
result4=result3.reparttion(1)
result5=result4.sortByKey(False)
result6=result5.map(lambda x:x[0])
result7=result6.take(5)
for a in result7:
 	print(a)

文件排序:(读取不同文件中的所有的整数进行排序)fileSort.py

from pyspark import SparkConf,SparkContext
index=0
def getindex():
    global index
    index+=1
    return index
def main():
     conf=SparkConf().setMaster('local').setAppName('FileSort')
     sc=SparkContext(conf=conf)
     lines=sc.textFile("file:///usr/local/spark/mycode/rdd/filesort/file*.txt")  # 所有的文件
     index=0
    result1=lines.filter(lambda line:len(line.strip())>0)).map(lambda x:(int(x.strip()),''''))     # 通过添加空字符形成键值对
   result2=result.repartition(1).sortByKey(True).map(lambda x :x[0]).map(lambda x :(getindex(),x))  # 充分区,使数据全局有序,
   result2.foreach(print)
   result2.saveAsTextFile("file:///usr/local/spark/mycode/rdd/filesortresult") 

二次排序:对于一个文件,先对数据根据一列进行排序,如果相同,按照第二列进行排序 sortbykey 排序

思路:通过Ordered 和serializable接口实现自定义排序的key secondarySortKey.py

from operator import gt
from pyspark import SparkContext,SparkConf

class SecodarySortKey():                   # 由原来不可排序的对象生成可以排序的对象
    def __inti__(self,k):  #k=(5,3)
        self.column1=k[0]   
        self.column2=k[1]
   def __gt__(self,other):              # 重写原来的比较函数
       if other.column1==self.column1:
	return gt(self.column2,other.column2)
      else:
	return gt(self.column1,other.column1)

def main():
   conf=SparkConf().setAppName('spart_sort').setMaster('local[1]')
  sc=SparkContext(conf=conf)
   file="file:///usr/local/spark/mycode/rdd/secondarysort/file4.txt"

   rdd1=sc.textFile(file).filter(lambda x:len(x.strip())>0))
   rdd2=rdd1.map(lambda x :((int(x.split(" ")[0]),int(x.split(" ")[1])),x)).map(lambda x: (SecondarySortKey(x[0]),x[1]))  # ((5,3),"5 3")
   rdd3=rdd2.sortByKey(False).map(lambda x:x[1] )
   rdd3.foreach(print)

Spark SQL 核心概念dataframe
dataframe的创建:
sparkSession支持从不同的数据源加载数据,并把数据转换成DataFrame,并且支持把DataFrame转换成SQLContext自身中
的表,然后使用SQL语句来操作数据。
1.创建sparkSession

from pyspark import SparkContext,SparkConf
from pyspark.sql import SparkSession
spark=SparkSession.builder.config(conf=SparkConf()).getOrCreate()    #创建SparkSeeion对像

2创建DataFrame

df=spark.read.text("people.txt")   或者 spark.read.format("text").load("people.txt") # 读取文本文件people.txt 创建DataFrame
df=park.read.json("people.json")    或者 spark.read.format("json").load("people.json")   # 读取people.json 创建DataFrame
df=spark.read.parquet("people.parquet")   或者 spark.read.format("parquet").load("people.parquet")   #读取people.parquet文件创建DataFrame

3.dataframe 保存 spark.write操作保存dataframe

df.write.txt("people.txt")    # 并不是文件名称,而是目录名称
df.write.json()
df.write.parquet()
  1. 常用的操作:
df.printSchema()   # 模式信息
df.select(df["name"],df["age"]+1).show()  # 选择列并显示
df.filter(df["age">20]).show
df.groupBy("age").count().show()
df.sort(df["age"].desc().df["name"].asc()).show()

利用反射机制推断RDD模式,将RDD转化为dataframe对像
数据
Andy 29

from pyspark.sql import Row   # Row对像,用封装一行行row对像数据
people=spark.sparkContext.textFile("file:///usr/local/spark/examples/src/main/people.txt").\
map(lambda line :line.split(',')).map(lambda p :Row(name=p[0],age=int(p[1])))

schemaPeople=spark.createDataFrame(people),将rdd转换为df
schemaPeople.createOrReplaceTempView("people")    “people”为临时表的名称     # 必须注册为临时表才能供下面的查询使用,这里创建临时表
personsDF=spark.sql("select name,age from people where age >20")   # spark sql查询
  # DataFrame 中每个原色都是一行记录,包含name和age两个字段,分别用p.name p.age 来获取
personsRDD=personsDf.rdd.map(lambda p:"Name:"+p.name+","+"Age:"+str(p.age))     #再转化为rdd用于显示
personsRDD.foreach(print)

使用编程模式定义RDD模式:当无法提前获取数据结构时,采用编程的方式定义RDD模式
步骤

  1. 制作表头
  2. 制作表中的记录
  3. 把表头和表中的记录拼装在一起
from pyspark.sql.types import *
from pysqark.sql import Row

生成表头(表的字段)

schemaString="name age"
fileds=[StructFiled(filed_name,StringType(),True) for field_name in schemaString.split(" ")]    # structFiled 用于描述字段信息,字段名称,类型,是否为空
schema=StructType(fields)    # 生成表头

制作表中的记录 : 也即是将数据行记录生成row对象

lines=spark.sparkContext.textFile("file:///usr/local/spark/example/people.txt")
parts=lines.map(lambda x x.split(","))   # rdd
people=parts.map(lambda p : Row(p[0],p[1].strip()))  # rdd 元素变成row对象

把表头和表中的记录拼装在一起

schemaPeople=spark.createDataFrame(people,schema)
# 注册一个临时表供下面查询使用

schemaPeople.createOrReplaceTempView("people")  
results=spark.sql("SELECT name ,age FROM people")    # dataframe
results.show()

# 读取mysql中的数据    通过JDBC连结MySQL数据库
jdbcDF=spark.read.format('jdbc') \
.option("driver","com.mysql.jdbc.Driver") \ # 指定驱动
.option("url",'jdbc:mysql://localhost:3306/spark') \    #要访问的数据地址
.option("dbtable","student") \      # 表明
.option("user","root") \
.option("password","123456").load()    # 密码
  
jdbcDF.show()

向mysql中写入数据

from  pyspark.sql import Row
from pyspark.sql.types import *
from pyspark import SparkContext,SparkConf
from pyspark.sql import SparkSession
spark = SparkSession.builder.config(conf=SparkConf()).getOrCreate()           # 生成一个spark sql 对象

#下面设置模式信息
schema=StructType([StructFiled("id",IntegerType(),True),\
StructFiled("name",StringType(),True),\
StructFiled("gender",Stringype(),True),
StructFiled("age",IntegerType(),True)])
# 下面设置两条数据,表示两个学生的信息
studentRDD=spark.saprkContext.parallelize(["3 Rongcheng M 26","4 Guanhua M 27"]).map(lambda x:x.split(" "))
# 下面创建Row对象,每个Row对象都是rowRDD中的一行
rowRDD=studentRDD.map(lambda p :Row(int(p[0].strip(),p[1].strip(),p[2].strip(),int(p[3].strip())))   
# 建立起row对象和模式之间的对应关系,也即是把数据和模式对应起来
studentDF=spark.createDataFrame(rowRDD,schema)              # 创建一个dataframe
#将上面的dataframe 写入数据库

prop={}
prop["user"]="root"
prop["password"]='123456'
prop["driver"]="com.mysql/jdbc.Driver"
studentDF.write.jdbc("jdbc:mysql://localhost:3306/spark","student","append",prop)          # append:表示追加模式

编写sparkstreaming程序固定的步骤:

  1. 创建输入DStream ------定义输入源
  2. DStream应用(转换操作和输出操作)定义--------》流计算
  3. 开始接收数据和处理流程 streamingContext.start()
  4. 等待处理结束:streamingContext.awaitTermination()
  5. 手动结束流计算流程 streamingContext.stop()

要运行一个Spark Streaming程序,就需要先生成一个StreamingContext对象,它是Spark Streaming程序的主入口----->可以从一个SparkConf对象创建一个StreamingContext对象 ------> 在pyspark中的创建方法进入pyspark以后,就可以获得一个默认的SparkContext对象,也就是sc、

创建StreamingContext对象(交互环境)
from pyspark.streaming import StreamingContext
ssc=StreamingContext(sc,1)              

编写独立的Spark Streaming程序
from pyspark import SparkContext ,SparkConf

from pyspark.streaming import StreamingContext
conf = SparkConf()
conf.setAppName("TestDStream")
conf.setMaster('local[2]')
sc=SparkContext(conf=conf)
ssc=StreamingContext(sc,1)

基本数据源:文件流,套接字流 RDD队列流

创建文件流
cd /usr/local/spark/mycode
mkdir streaming
cd streaming
mkdir logfile
cd logfile
交互式环境下  对文件流处理进行词频统计,会将出现新文件分别处理,流处理问就
from pyspark import SparkContext
from pyspark.streaming import StreamingContext
ssc=StreamingContext(sc,10)            #10表示每隔10秒计算一次
lines=ssc.textFileStream('file:///usr/local/spark/mycode/streaming/logfile')   # 定义文件流对象,参数为监控目录
words=lines.flatMap(lambda line:line.split(''))              # 流计算过程
wordCounts=word.map(lambda x : (x,1)).reduceByKey(lambda a,b:a+b)      
wordCounts.pprint()   # 格式化输出
ssc.start()
ssc.awaitTermination()

采用独程序方式创建文件流

cd  /usr/local/spark/mycode
cd streaming
cd logfile
vim  FileStreaming.py
from pyspark import SparkContext,SparkConf
from pyspark.streaming import StreamingContext
conf=SparkConf().setAppNmae("TestDstream").setMaster("local[2]')
sc=SparkContext(conf=conf)            # 创建sparkcontext对象
ssc=StreamingContext(sc,10)            # 生成一个spark  StreamingContext 对象10表示每隔10秒计算一次
lines=ssc.textFileStream('file:///usr/local/spark/mycode/streaming/logfile')   # 定义文件流对象,参数为监控目录
words=lines.flatMap(lambda line:line.split(''))              # 流计算过程
wordCounts=word.map(lambda x : (x,1)).reduceByKey(lambda a,b:a+b)      
wordCounts.pprint()   # 格式化输出
ssc.start()
ssc.awaitTermination()

执行程序

cd  /usr/local/spark/mycode/streaming/logfile/
/usr/local/spark/bin/spark-submit FileStreaming.py

套接字流作为数据源实现spark streaming(使用NC程序产生数据)

socket工作原理:包含TCP客户端和TCP服务器端,客户端向服务端发起请求,超产生数据流

cd  /usr/local/spark/mycode/streaming
mkdir socket
cd socket
vim  NetworkWordCount.py           客户端的角色

from  __future__ import print_function
import sys
from pyspark import SparkContext
from pyspark.streaming import StreamingContext

if __name__ =="__main__":
     if len(sys.argv)!=3:
	print("Usage:NetworkWordCount.py <hostname><port>",file=sys.stderr)
	exit(-1)
    sc=SparkContext(appName="PythonStreamingNetworkWordCount")
    ssc=StreamingContext(sc,1)
    lines=ssc.socketTextStream(sys.argv[1],int(sys.argv[2]))
   counts=lines.flatMap(lambda line:line.split(" ")).map(lambda word :(word,1)).reduceByKey(lambda a,b:a+b)
   counts.pprint()
   ssc.start()
   ssc.awaitTermination()

再新建一个终端,执行如下代码启动流计算
建立nc服务端,linux自带的nc $ nc -lk 9999

cd /usr/local/spark/mycode/streaming/socket
/usr/local/spark/bin/spark-submit NetworkWordCount.py localhost 9999           # 启动客户端

在nc窗口中随意输入单词,监听窗口自动获取单词数据流信息

使用Socket编程实现自定义数据源
cd /usr/local/spark/mycode/streaming/socket
vim DataSourceSocket.py

import scoket  
server=socket.socket() #生成socket对像
server.bind(("localhost",9999))   # 绑定机器ip和端口
server.listen(1)    # 绑定监听端口
while 1:
   print("I am waiting the connect...")   # 为方便识别,打印一个我在等待
   # accept进入阻塞状态
   conn,addr=server.accept()  # 这里用两个值接受,因为连结上之后使用的是客户端发来的请求的这个实例,所以下面的传输要使用coon实例操作
   print("Connect success!Connection is from  %s" %addr[0])
  #打印正在发送数据
   print("sending data...")
   conn.send("I love hadoop I love spark hadoop is good spark is fast".encode())    # 服务端发信息到客户端
   conn.close()
   print("Connection is broken.")

启动DataSourceSocket程序

cd /usr/local/spark/mycode/streaming/socket
/usr/local/spark/bin/spark-submit DataSourceSocket.py

启动客户端,即NetworkWordCount 程序

/usr/local/spark/mycode/streaming/socket
/usr/local/spark/bin/spark-submit NetworkWordCount.py localhost 9999

RDD队列流
可以使用 streamingContext.queueStream(queueofRDD) 创建基于RDD队列的DStream
RDDQueueStream.py 每个一秒创建一个RDD,塞到队列中,每个两秒对数据进行处理

import time
from pyspark import SparkContext
from pyspark.streaming import StreamingContext

if __name__=="__main__":
   sc=SparkContext(appName="PythonStreamingQueueStream")
   ssc =streamingCobtext(sc,2)
   #创建一个队列,通过该队列可以把RDD推给一个RDD队列流
  rddQueue=[]
  for i in range(5):
        rddQueue+=[ssc.sparkContext.parallelize([j for j in range(1,1001)],10)]     # 10代表分区数
       time.sleep(1)
  #创建一个RDD队列流
  inputStream=ssc.queueStream(rddQueue)
  mappedStream=inputStrean.map(lambda x :(x%10,1))
  reduceStream=mappedStream.reduceByKey(lambda a,b:a+b)
  reducedStream.pprint()
   ssc.start()
   ssc.stop(stopSparkContext=True,stopGraceFully=True)

高级数据源kafka:高吞吐量的分布式发布订阅消息系统,可以同时满足在线实时处理和批量离线处理
组件 broker (每个服务器) topic(主题)每条 发布到kafka集群的消息都有一个类别,这个类别被称为topic(物理上不同的Topic的消息分别存放,逻辑上一个Topic的消息,虽然保存于一个或多个broker上,但是用户只需要指定消息的Topic既可生产或者消费数据而不必关心数据存放在何处)partition
Produer:数据的生产者
消费者 Consumer Group

  1. 每个Consumer 只属于某个Consumer Group
  2. 若不指定group name 则属于默认的group

结构:kafka的运行依赖于Zookeeper.Topic,Consumer,Prtiton,Broker等注册信息都存放在zookeeper中

kafkaWordCount.py


from __future__ import print_function
import sys
from pyspark import SparkContext
from pyspark.streaming import StreamingContext
from pyspark.streaming.kafka import KafkaUtils

if __name__=="__main__":
  if len(sys.argv)!=3:   
      print("Usage:KafkaWordCount.py<zk><topic>",file=sys.stderr)
      exit(-1)

  sc=SparkContext(appName="PythonStreamingKafkaWordCount")
  ssc=StreamingContext(sc,1)
 zkQuorum,topic=sys.argv[1:]             # zookeeper地址,和topic。 取数据的地址
  kvs=KafkaUtils.createStream(ssc,zkQuorum,"spark-streaming-consumer",{topic:1})          # 构建kafka数据源对象
  lines=kvs.map(lambda x:x[1])
   counts=line.flatMap(lambda line:line.split(" ")).map(lambda word:(word,1)).reduceByKey(lambda a,b:a+b)
  counts.pprint()
  ssc.start()
  ssc.awaitTermination()

cd /usr/local/spark/mycode/streaming/kafka/
/usr/local/spark/bin/spark-submit  ./KafkaWordCount.py localhost:2181 wordsendertest (topic数据源)

状态转换操作(滑动窗口转换操作)
1.滑动窗口转换操作
事先设定一个滑动窗口的长度(也就是窗口的持续时间)
设定滑动窗口的时间间隔,让窗口按照指定的时间间隔在源DStream上滑动
每次窗口停放的位置,都会有一部分DStream被框入窗口内,形成一个小段的DStream
可以启动对这个小段DStream的计算
参数(windowLength,slideInterval)# 滑动窗口大小,滑动窗口间隔

reduceByKeyAndWindow(func,invFunc,windowLength,slideInterval,[numTasks])更高效的reduceByKeyAndWindow,每个窗口的reduce值,是基于先前窗口的reduce值进行增量计算得到的;它会对进入的滑动窗口的
新数据进行reduce操作,并对离开窗口的老数据进行”逆向reduce“操作。但是,只能用于”可逆reduce函数“,即那些reduce函数都有一个
对应的”逆向reduce函数“,以invFun参数传入
WindowedNetworkWordCount.py

from __future__ import print_function
import sys
from pyspark import SparkContext
from pyspark.streaming import StreamingContext


if __name__=="__main__":
  if len(sys.argv)!=3:   
      print("Usage:WindowedNetworkWordCount.py<hostname><port>",file=sys.stderr)
      exit(-1)

  sc=SparkContext(appName="PythonStreamingWindowedNetworkWordCount")
  ssc=StreamingContext(sc,10)
  ssc.checkpoint("file:///usr/local/spark/mycode/streaming/socket/checkpoint")       # 保存数据,以防丢失
  lines=ssc.socketTextStream(sys.argv[1],int(sys.argv[2]))
  counts=lines.flatMap(lambda line:line.split(" ")).map(lambda word:(word,1)) \
                              .reduceByKeyAndWindow(lambda x,y:x+y,lambda x,y:x-y,30,10)    # 逆函数的作用加x+y后形成的数据再一次x-y后回复源数据,使得新窗口内的函数依然为原始的数据
   # 即是将离开窗口的数据减去,将新加入窗口数据加进来,实现数据的增量操作
  counts.pprint()
  ssc.start()
  ssc.awaitTermination()

2.updateStateByKey操作 在跨批次之间维护状态
对于有状态转换操作而言,本批次的词频统计,会在之前批次的词频统计结果的基础上进行不断累加。所以,最终统计得到的词频,
是所有批次的单词的总的词频统计结果。

历史状态累加

from __future__ import print_function
import sys
from pyspark import SparkContext
from pyspark.streaming import StreamingContext


if __name__=="__main__":
  if len(sys.argv)!=3:   
      print("Usage:WindowedNetworkWordCount.py<hostname><port>",file=sys.stderr)
      exit(-1)

  sc=SparkContext(appName="PythonStreamingWindowedNetworkWordCount")
  ssc=StreamingContext(sc,1)
  ssc.checkpoint("file:///usr/local/spark/mycode/streaming/socket/checkpoint")       # 保存数据,以防丢失
  
 # RDD with initial state(key,value) pairs
   initialStateRDD=sc.parallelize([(u"hello",1),(u"word",1])
  def updataFunc(new_values,last_sum):
     return sum(new_values)+(last_sum or 0)
  lines=ssc.socketTextStream(sys.argv[1],int(sys.argv[2]))
  running_counts=line.flatMap(lambda line:line.split(" ")).map(lambda word:(word,1)).updataStateByKey(updataFunc,initialRDD=initialStateRDD)   # 有状态转换
  running_counts.pprint()
  ssc.start()
  ssc.awaitTermination() 

输出操作:
1.把Dstream输出到文本文件中
2. 把DStream写入到mySQL数据库中

NetworkCountStatefulText.py

from __future__ import print_function
import sys
from pyspark import SparkContext
from pyspark.streaming import StreamingContext
if __name__=="__main__":
  if len(sys.argv)!=3:   
      print("Usage:NetworkCountStatefulText.py<hostname><port>",file=sys.stderr)
      exit(-1)

  sc=SparkContext(appName="NetworkCountStatefulText")
  ssc=StreamingContext(sc,1)
  ssc.checkpoint("file:///usr/local/spark/mycode/stateful")       # 保存数据,以防丢失
  
 # RDD with initial state(key,value) pairs
   initialStateRDD=sc.parallelize([(u"hello",1),(u"word",1])
  def updataFunc(new_values,last_sum):
     return sum(new_values)+(last_sum or 0)
  lines=ssc.socketTextStream(sys.argv[1],int(sys.argv[2]))
  running_counts=line.flatMap(lambda line:line.split(" ")).map(lambda word:(word,1)).updataStateByKey(updataFunc,initialRDD=initialStateRDD)   # 有状态转换
  running_counts.saveAsTextFiles("file:///usr/local/spark/mycode/streaming/stateful/output")
  running_counts.pprint()
  ssc.start()
  ssc.awaitTermination() 

输出到mysql数据库中


from __future__ import print_function
import sys
from pyspark import SparkContext
from pyspark.streaming import StreamingContext


if __name__=="__main__":
  if len(sys.argv)!=3:   
      print("Usage:NetworkCountStatefulText.py<hostname><port>",file=sys.stderr)
      exit(-1)

  sc=SparkContext(appName="NetworkCountStatefulText")
  ssc=StreamingContext(sc,1)
  ssc.checkpoint("file:///usr/local/spark/mycode/stateful")       # 保存数据,以防丢失
  
 # RDD with initial state(key,value) pairs
   initialStateRDD=sc.parallelize([(u"hello",1),(u"word",1])
  def updataFunc(new_values,last_sum):
     return sum(new_values)+(last_sum or 0)
  lines=ssc.socketTextStream(sys.argv[1],int(sys.argv[2]))
  running_counts=line.flatMap(lambda line:line.split(" ")).map(lambda word:(word,1)).updataStateByKey(updataFunc,initialRDD=initialStateRDD)   # 有状态转换
  running_counts.pprint()

  def dbfunc(records):  # 将partition 中的每一条计算插入数据库中
      db=pymysql.connect("localhost","root","123456",'spark')   
       cursor=db.cursor()   # 声明一个指针
     def doinsert(p):  # 插入具体的键值对
        sql="insert into wordcount(word,count) values ("%s","%s")" % (str(p[0]),str(p[1]))
        try: 
            cursor.execute(sql)   # 生成SQL语句
            db.commit()
        except:
	db.rollback()
     for item in records:
       doinsert(item)

   def func(rdd):
       repartitionedRDD=rdd.repartition(3)
       repartitionedRDD.foreachParttion(dbfunc)   #foreachPartition 为每个rdd中的键值元素,每条记录传给dbfunc进行处理
     
   running_counts.foreachRDD(func)
   ssc.start()
   ssc.awaitTermination()
 

Structured Sreaming: 相应比spark streaming更快
概述:Structured Streaming的关键思想是将实时数据流视为一张正在不断添加数据的表。可以把流计算等同于在一个静态表上的批处理查询,
Spark会在不断添加数据的无界输入表上运行计算,并进行增量查询。在无界表上对输入的查询将生成结果表,系统每隔一定的周期会触发对无界表的计算并更新结果表。

Structured Streaming 默认使用微批处理执行模型。这意味着spark流计算引擎会定期检查流数据源,并对自上一批结束后到达的新数据执行流量查询

spark streaming处理的数据抽象是Dstream(本质上是一系列的RDD),Structured Streaming 采用的数据抽象是DataFrame

from pyspark.sql import SparkSession
from pyspark.sql.functions import split    # 拆分字符串
from pyspark.sql .functions import explode       # 展开数组内的所有单词
 
# 创建sparkSession对像
if __name__=="__main__":
    spark=SparkSession.builder.appName("StructuredNetworkwordCount").getOrCreate()
    spark.sparkContext.setLogLevel("WARN")
     
    # 创建一个输入数据源
   lines=spark.readSteam.format("socket").option("host","localhost").option('port',9999).load()

  # 定义流计算的过程
 words=lines.select(explodes(split(lines.value," ")).alias("word"))    #alias 定义单词列
 word.Counts=words.groupBy("word").count()

 #执行流计算
 query =wordCounts.writeStream.outputMode("complete").format("console")\    # console 输出到控制台
.trigger(processingTime="8 seconds").start()
 query.awaitTermination()

数据源:
file源:捕捉文件变化,以文件流的形式读取某个目录中的文件。

spark mllib基于RDD的数据抽象,包含基于RDD的原始算法API
spark.ml 基于DataFrame的数据抽象,则提供基于dataframe高层次的api,可以用来构建机器学习工作流PipLine

机器学习流水线:
transformer(转换器)
比如一个model就是一个Transformer,它可以把一个不包含预测标签的测试数据集dataframe打上标签,转化成一个包含预测标签的dataframe。技术上,Transormer
实现了一个方法transform(),它通过附加一个或多个列将一个DataFrame转换为另一个dataFrame

Estimator评估器(本质上理解为算法)
它是学习算法或者训练数据上的训练方法的概念抽象,在PipLine里通常被用来操作Dataframe数据并生成一个Transformer
从技术上讲,Estimator 实现了一个方法fit(),它接受一个Dataframe并产生一个转换器。比如,一个随机森林算法就是一个Estimator,它可以调用fit(),通过训练户据特征数据而得到一个随机森林模型。

Parameter
被用来设置Transformer或者Estimator的参数。现在,所有的转换器和估计器可共享用于指定参数的公共API,ParamMap是一组(参数,值)对

构建PIpline
1.定义Pipline 中的各个流水线阶段PiplineStage ---->转换器或评估器
2. 转换器和评估器有序地组织起来构建成PipeLine

pipline=Pipline(stages=[stage1,stage2,stage3])
# 把训练数据集作为输入参数,调用fit()方法,返回一个PiplineModel类实例,被用来预测测试集合的标签

#创建sparkSeeion对象
from pyspark.sql import SparkSession
spark=SparkSession.builder.master("local").appName("WordCount").getOrCreate()

from pyspark.ml import Pipline
from pyspark.ml.classification import LogisticRegression
from pysaprk.ml.feature import HashingTF,Tokenizer
# prepare training document from a list of (id,text,lable) tuples
training=spark.createDataFrame([
	(0," a b c spark",1.0),
	(1,"a h",0.0),
	(2,"spark is hg",1.0),
	(3,"hadoop g h k",'0.0')]
,["id","text","label"])
  1. 定义Pipiline中的各个流水线阶段PipelineStage
    转换器
tokenizer=Tokenizer(inputCol="text",outputCol="words")  # 新生成列命名为words   

转换器

hashingTF=HashingTF(inputCol=tokenizer.getOutputCol(),outputCol="features")   # 转化为词向量,生成新的一列,命名为features

评估器

lr=LogisticRegression(maxIter=10,regParam=0.001) 

按照处理逻辑有序地组织PipelineStages,创建Pipeline

pipeline=Pipeline(stages=[tokenizer,hashingTF,lr])

#现在构建的Pipline本质上是一个Estimator,在它的fit()方法运行之后,它将产生一个PipelineModel,它是一个Transformer

model=pipeline.fit(training)

#可以看到,model的类型是一个PipelineModel,这个流水线模型将在测试数据的时候使用。

构建测试数据

training=spark.createDataFrame([
	(4," a b c spark"),
	(5,"a h"),
	(6,"spark is hg"),
	(7,"hadoop g h k")]
,["id","text"])

生成预测结果

prediction=model.transform(test)
selected=prediction.select("id","text","probability","prediction")
for row in selected.collect():
     rid,text,prob,prediction=row
     print("(%d,%s)-->prob=%s,prediction=%f"%(rid,text,str(prob),preduction))

抽取特征:
TF: Hashing TF 是一个Transformer, IDF是一个Estimator,在一个数据集上应用它的fit()方法,产生一个IDFModel

from pyspark.ml.feature import HashingTF,IDF,Tokenizer
#创建一个简单的DataFrame,每一个句子代表一个文档
sentenceData=spark.createDataFrame([(0,"I heard about Spark and I love Spark"),   # 生成一个二维表
                                                      (1,"I wish Java could use case classes")]).toDF("label',"sentence")       # 

tokenizer=Tokenizer(inputCol="sentence",outputCol="words")   # 增加一列words
wordsData=tokenizer.transform(sentenceData)
wordsData.show()
#利用HashingTF的transform()方法把句子哈希成特征数量
hashingTF=HashingTF(inputCol="words",outputCol="rawFeatures",numFeatures=2000)
featurizedData=hashingTF.transform(wordsData)
featurizedData.select("words","features").show(trancate=False)

idf=IDF(inputCol="rawFeatures",outputCol="features")
idfModel=idf.fit(featurizedData)

rescaledData=idfModel.transform(featurizedData)
rescaledData.select("features","label").show()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值