目标
针对播放日志引入spark,提升问题分析效率。
spark概述
Apache Spark是用于大规模数据处理的统一分析引擎。它提供Java,Scala,Python和R的高级API,以及支持常规执行图的优化引擎。它还支持一组丰富的更高级别的工具,包括星火SQL用于SQL和结构化数据的处理,MLlib机器学习,GraphX用于图形处理,以及结构化流的增量计算和流处理。
官方文档:https://spark.apache.org/docs/latest/
RDD(Resilient Distributed Dataset)弹性分布式数据集
RDD支持两种类型的操作:转换(从现有操作创建新的数据集)和动作(操作)。
详细文档:https://www.cnblogs.com/qingyunzong/p/8899715.html
DF(DataFrame)数据帧
api文档:https://spark.apache.org/docs/latest/api/python/pyspark.sql.html#pyspark.sql.DataFrame
步骤
1、与spark连接
(1)spark程序
首先创建SparkContext对象,spark如何访问集群,下面例子master传’local’以本地模式运行spark
from pyspark import SparkContext, SparkConf
# conf = SparkConf().setAppName(appName).setMaster(master)
# sc = SparkContext(conf=conf)
conf=SparkConf().setAppName("spark.master").setMaster("local[*]")
# 先获取,没有则创建
sc=SparkContext.getOrCreate(conf)
(2)pyspark shell启动
pyspark启动会自动创建两个对象spark(SparkSession)和sc(SparkContext),并自动引入相关模块。
2、创建RDD
创建RDD的方法有两种:并行化 驱动程序中的现有集合,或引用外部存储系统中的数据集。根据我们分析日志的需求,主要使用外部数据源创建。
PySpark可以从Hadoop支持的任何存储源创建分布式数据集,包括本地文件系统,HDFS,Cassandra,HBase,Amazon S3等。Spark支持文本文件,SequenceFiles和任何其他Hadoop InputFormat。
可以使用SparkContext的textFile方法创建文本文件RDD 。此方法需要一个URI的文件(本地路径的机器上,或一个hdfs://,s3a://等URI),并读取其作为行的集合。
Spark的所有基于文件的输入法(包括textFile)都支持在目录,压缩文件和通配符上运行。例如,你可以使用textFile("/my/directory"),textFile("/my/directory/*.txt")和textFile("/my/directory/*.gz")。
rdd = sc.textFile(path)
3、RDD转换
此时的rdd只有一列,每一行的数据对应日志里的每一行,我们需要对rdd的每一行进行解析,转换成多列存储,以便使用sql查询。
主要用到个三个方法filter()、map()和flatMap(),通过这三个方法可以过滤出想要的日志行,并将过滤出的每一行日志转换成json格式,key作为列名,value作为行值。
https://www.cnblogs.com/qingyunzong/p/8899715.html
import json
import copy
from pyspark import SparkContext, SparkConf
def parse(line):
i = line.find('{')
j = line.rfind('}')
s = {
}
if i < 0 or j < 0 or i > j:
return s
try:
s = json.loads(line[i:j+1])
e = line[:i].split(',')
if len(e) > 1:
s['client_ip'] = e[1]
except Exception as excp:
print("json load excp: ", excp)
return s
def parse_list(line):
s = parse(line)
its = s.get('list', None)
if not its:
return
for it in its:
res = copy.deepcopy(s)
res['video_action'] = it
if 'video_info' in it:
res['video_action'].pop('video_info')
res['video_action'] = json.dumps(res['video_action'])
res.pop('list')
ls = it.get('video_loading_info', None)
if not ls:
yield res
continue
try:
ls = json.loads(ls)
except:
yield res
continue
for load in ls:
res['video_loading_info'] = json.dumps(load)
yield res
return
conf=SparkConf().setAppName("spark.master").setMaster("local[*]")
sc=SparkContext.getOrCreate(conf)
rdd = sc.textFile(path)
parseRdd = rdd.filter(lambda s: 'list' in s).flatMap(parse_list)
4、RDD转成DF
因为RDD支持的查询操作有限,为了使查询更方便,需要将RDD转成DF,DF可调用的方法更加丰富。
from pyspark import SparkContext, SparkConf
from pyspark.sql