1.Spark SQL出现的 原因是什么?
Spark SQL是Spark用来处理结构化数据的一个模块,它提供了一个叫作Data Frame的编程抽象结构数据模型(即带有Schema信息的RDD),Spark SQL作为分布式SQL查询引擎,让用户可以通过SQL、DataFrame API和Dataset API三种方式实现对结构化数据的处理。但无论是哪种API或者是编程语言,都是基于同样的执行引擎,因此可以在不同的API之间随意切换。
Spark SQL的前身是 Shark,Shark最初是美国加州大学伯克利分校的实验室开发的Spark生态系统的组件之一,它运行在Spark系统之上,Shark重用了Hive的工作机制,并直接继承了Hive的各个组件, Shark将SQL语句的转换从MapReduce作业替换成了Spark作业,虽然这样提高了计算效率,但由于 Shark过于依赖Hive,因此在版本迭代时很难添加新的优化策略,从而限制了Spak的发展,在2014年,伯克利实验室停止了对Shark的维护,转向Spark SQL的开发。
2.用spark.read 创建DataFrame
3.观察从不同类型文件创建DataFrame有什么异同?
3.1 利用反射机制推断RDD模式
- sc创建RDD
- 转换成Row元素,列名=值
- spark.createDataFrame生成df
- df.show(), df.printSchema()
3.2 使用编程方式定义RDD模式
- 生成“表头”
- fields = [StructField(field_name, StringType(), True) ,...]
- schema = StructType(fields)
- 生成“表中的记录”
- 创建RDD
- 转换成Row元素,列名=值
- 把“表头”和“表中的记录”拼装在一起
- = spark.createDataFrame(RDD, schema)
4. DataFrame保存为文件
df.write.json(dir)
预练习:
读 学生课程分数文件chapter4-data01.txt,创建DataFrame。并尝试用DataFrame的操作完成实验三的数据分析要求。
4.观察Spark的DataFrame与Python pandas的DataFrame有什么异同?
| Pandas | Spark |
工作方式 | 单机single machine tool,没有并行机制parallelism 不支持Hadoop,处理大量数据有瓶颈 | 分布式并行计算框架,内建并行机制parallelism,所有的数据和操作自动并行分布在各个集群结点上。以处理in-memory数据的方式处理distributed数据。 支持Hadoop,能处理大量数据 |
延迟机制 | not lazy-evaluated | lazy-evaluated |
内存缓存 | 单机缓存 | persist() or cache()将转换的RDDs保存在内存 |
DataFrame可变性 | Pandas中DataFrame是可变的 | Spark中RDDs是不可变的,因此DataFrame也是不可变的 |
创建 | 从spark_df转换:pandas_df = spark_df.toPandas() | 从pandas_df转换:spark_df = SQLContext.createDataFrame(pandas_df) 另外,createDataFrame支持从list转换spark_df,其中list元素可以为tuple,dict,rdd |
list,dict,ndarray转换 | 已有的RDDs转换 | |
CSV数据集读取 | 结构化数据文件读取 | |
HDF5读取 | JSON数据集读取 | |
EXCEL读取 | Hive表读取 | |
| 外部数据库读取 | |
index索引 | 自动创建 | 没有index索引,若需要需要额外创建该列 |
行结构 | Series结构,属于Pandas DataFrame结构 | Row结构,属于Spark DataFrame结构 |
列结构 | Series结构,属于Pandas DataFrame结构 | Column结构,属于Spark DataFrame结构,如:DataFrame[name: string] |
列名称 | 不允许重名 | 允许重名 修改列名采用alias方法 |
列添加 | df[“xx”] = 0 | df.withColumn(“xx”, 0).show() 会报错 from pyspark.sql import functions df.withColumn(“xx”, functions.lit(0)).show() |
列修改 | 原来有df[“xx”]列,df[“xx”] = 1 | 原来有df[“xx”]列,df.withColumn(“xx”, 1).show() |
显示 | | df 不输出具体内容,输出具体内容用show方法 输出形式:DataFrame[age: bigint, name: string] |
df 输出具体内容 | df.show() 输出具体内容 | |
没有树结构输出形式 | 以树的形式打印概要:df.printSchema() | |
| df.collect() | |
排序 | df.sort_index() 按轴进行排序 | |
df.sort() 在列中按值进行排序 | df.sort() 在列中按值进行排序 | |
选择或切片 | df.name 输出具体内容 | df[] 不输出具体内容,输出具体内容用show方法 df[“name”] 不输出具体内容,输出具体内容用show方法 |
df[] 输出具体内容, df[“name”] 输出具体内容 | df.select() 选择一列或多列 df.select(“name”) 切片 df.select(df[‘name’], df[‘age’]+1) | |
df[0] df.ix[0] | df.first() | |
df.head(2) | df.head(2)或者df.take(2) | |
df.tail(2) | | |
切片 df.ix[:3]或者df.ix[:”xx”]或者df[:”xx”] | | |
df.loc[] 通过标签进行选择 | | |
df.iloc[] 通过位置进行选择 | | |
过滤 | df[df[‘age’]>21] | df.filter(df[‘age’]>21) 或者 df.where(df[‘age’]>21) |
整合 | df.groupby(“age”) df.groupby(“A”).avg(“B”) | df.groupBy(“age”) df.groupBy(“A”).avg(“B”).show() 应用单个函数 from pyspark.sql import functions df.groupBy(“A”).agg(functions.avg(“B”), functions.min(“B”), functions.max(“B”)).show() 应用多个函数 |
统计 | df.count() 输出每一列的非空行数 | df.count() 输出总行数 |
df.describe() 描述某些列的count, mean, std, min, 25%, 50%, 75%, max | df.describe() 描述某些列的count, mean, stddev, min, max | |
合并 | Pandas下有concat方法,支持轴向合并 | |
Pandas下有merge方法,支持多列合并 同名列自动添加后缀,对应键仅保留一份副本 | Spark下有join方法即df.join() 同名列不自动添加后缀,只有键值完全匹配才保留一份副本 | |
df.join() 支持多列合并 | | |
df.append() 支持多行合并 | | |
缺失数据处理 | 对缺失数据自动添加NaNs | 不自动添加NaNs,且不抛出错误 |
fillna函数:df.fillna() | fillna函数:df.na.fill() | |
dropna函数:df.dropna() | dropna函数:df.na.drop() | |
SQL语句 | import sqlite3 pd.read_sql(“SELECT name, age FROM people WHERE age >= 13 AND age <= 19″) | 表格注册:把DataFrame结构注册成SQL语句使用类型 df.registerTempTable(“people”) 或者 sqlContext.registerDataFrameAsTable(df, “people”) sqlContext.sql(“SELECT name, age FROM people WHERE age >= 13 AND age <= 19″) |
功能注册:把函数注册成SQL语句使用类型 sqlContext.registerFunction(“stringLengthString”, lambda x: len(x)) sqlContext.sql(“SELECT stringLengthString(‘test’)”) | ||
两者互相转换 | pandas_df = spark_df.toPandas() | spark_df = sqlContext.createDataFrame(pandas_df) |
函数应用 | df.apply(f)将df的每一列应用函数f | df.foreach(f) 或者 df.rdd.foreach(f) 将df的每一列应用函数f df.foreachPartition(f) 或者 df.rdd.foreachPartition(f) 将df的每一块应用函数f |
map-reduce操作 | map(func, list),reduce(func, list) 返回类型seq | df.map(func),df.reduce(func) 返回类型seqRDDs |
diff操作 | 有diff操作,处理时间序列数据(Pandas会对比当前行与上一行) | 没有diff操作(Spark的上下行是相互独立,分布式存储的) |