1.要编写SparkSQL程序,必须通SparkSession对象
pyspark.sql.SparkSession(sparkContext, jsparkSession=None)
在spark1.x之前的版本中,SparkSQL程序的编程入口是
pyspark.sql.SQLContext(sparkContext, sparkSession=None, jsqlContext=None)
这个是需要大家知道的,Spark1.x和Spark2.x在API方面变化还是挺大的!
还有一个pyspark.sql.HiveContext(sparkContext, jhiveContext=None),用于整合Hive数据仓库的,读取Hive表格需要借助HiveContext。
2.在SparkSession这个类中,有builder,通过builder去构建SparkSession实例,用法如下。
from pyspark.sql import SparkSession
spark = SparkSession.builder.master("spark://hadoopmaste:
7077").appName("test").config("spark.xxxx.conf", "some-value")
.getOrCreate()
master用于指定spark集群地址
appName用于设置app的名称
config中以key,value的形式进行一些配置
config可以以链式编程的方式多次调用,每次调用可设置一组key,value配置。而且conf中还可以传入一个关键字参数conf,指定外部的SparkConf配置对象getOrCreate,若存在sparksession实例直接返回,否则实例化一个sparksession返回
enableHiveSupport()启用对hive的支持
这些配置可以通过SparkSession上的conf属性来获取,这个conf实际上就是
RuntimeConfig对象,通过conf上的get方法获取对应的配置和通过spark.sparkContext.getConf().get获取配置是类似的。
3.创建DataFrame的几种常见方式
createDataFrame(data, schema=None, samplingRatio=None, verifySchema=True)这个方法。可以使用RDD或则python list获取pandas.DataFrame来创建。
当schema被指定的时候,每个列的类型将会通过列来进行推断。
samplingRatio指定用于类型推断的样本的比例
verifySchema验证每行的数据类型是否符合schema的定义。
使用tuple创建DataFrame,注意对比有schema和没有指定schema的区别
l = [('liko',14,32),('alan',20,32)]
print(spark.createDataFrame(l).collect())
print(spark.createDataFrame(l, schema=['name','weight','age']).collect())
输出结果:
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
[Row(_1='liko', _2=14, _3=32), Row(_1='alan', _2=20, _3=32)]
[Row(name='liko', weight=14, age=32), Row(name='alan', weight=20, age=32)]
通过使用dict字典创建DataFrame,通过字典不用指定schema,因为字典中的key就是schema
l = [{'name':'liko','age':14},{'name':'alan','age':20}]
print(spark.createDataFrame(l, schema=['name','age']).collect())
运行结果:
[Row(name='liko', age=14), Row(name='alan', age=20)]
通过RDD来创建DataFrame
l = [('liko', 14),('alan',20)]
rdd = sc.parallelize(l,3)
df = spark.createDataFrame(rdd)
df1 = spark.createDataFrame(rdd,schema=['name','age'])
df.show()
df1.show()
运行结果:
+----+---+
| _1| _2|
+----+---+
|liko| 14|
|alan| 20|
+----+---+
|name|age|
+----+---+
|liko| 14|
|alan| 20|
+----+---+
通过在RDD上构建Row对象来构建DataFrame
from pyspark.sql import Row
Person = Row('name', 'age')
l = [('liko', 14),('alan',20)]
rdd = sc.parallelize(l,3)
person = rdd.map(lambda r: Person(*r))
df2 = spark.createDataFrame(person)
df2.show()
运行结果:
+----+---+
|name|age|
+----+---+
|liko| 14|
|alan| 20|
+----+---+
通过传入RDD和schema信息来构建DataFrame
from pyspark.sql.types import *
schema = StructType([StructField("name", StringType(),
True),StructField("age", IntegerType(), True)])
l = [('liko', 32),('alan',20)]
rdd = sc.parallelize(l,3)
df3 = spark.createDataFrame(rdd, schema)
df3.show()
+----+---+
|name|age|
+----+---+
|liko| 32|
|alan| 20|
+----+---+
通过Pandas中的DataFrame来创建DataFrame
import pandas as pd
pandas_df = pd.DataFrame([{'name':'liko','age':32},{'name':'alan','age':20}])
pandas_df.head()
spark.createDataFrame(pandas_df).show()
+---+----+
|age|name|
+---+----+
| 32|liko|
| 20|alan|
+---+----+
schema还可以用字符串“名字:类型”多个列用逗号分隔表示
l = [('liko', 23),('alan',20)]
rdd = sc.parallelize(l,3)
spark.createDataFrame(rdd, "a: string, b: int").show()
+----+---+
| a| b|
+----+---+
|liko| 23|
|alan| 20|
+----+---+
通过schema还可以指定字段类型,当指定的字段类型和自动推断出来的类型不一致时,会报错。
l = [('liko', 23), ('alan', 20)]
rdd = sc.parallelize(l, 3)
rdd = rdd.map(lambda row: row[1])
spark.createDataFrame(rdd, "int").show()
+-----+
|value|
+-----+
| 23|
| 20|
+-----+
实际类型为int类型,却指定为boolean
l = [('liko', 23), ('alan', 20)]
rdd = sc.parallelize(l, 3)
rdd = rdd.map(lambda row: row[1])
#spark.createDataFrame(rdd, "int").show()
spark.createDataFrame(rdd, "boolean").show()
TypeError: field value: BooleanType can not accept object 23 in type
4.DataFrame和rdd一样可以通过读取文件,或者通过transformation转化得到。在
sparksession的read模块中有非常多的读取文件的方法,稍后后详细讲解,
transformation也会在后面讲解到。
通过read模块可以读取csv/jdbc/json/parquet/text等格式的文件。
print(dir(spark.read))
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_df', '_jreader', '_set_opts', '_spark', 'csv', 'format', 'jdbc', 'json', 'load', 'option', 'options', 'orc', 'parquet', 'schema', 'table', 'text']
5.newSession()这个方法会返回一个新的SparkSession,他们公用一个sparkcontext,但是注册的临时表,UDF这些是彼此隔离的。
spark1 = spark.newSession()
print(spark1 == spark)
conf = spark.conf
conf1 = spark1.conf
print(conf == conf1)
context = spark.sparkContext
context1 = spark1.sparkContext
print(context == context1)
udf = spark.udf
udf1 = spark1.udf
print(udf == udf1)
False
False
True
False
6.range(start, end=None, step=1, numPartitions=None)该方法创建的DataFrame,列标签为id,类型为pyspark.sql.types.LongType,numPartitions用于指定分区数
df = spark.range(100,1000,37,3)
df.rdd.getNumPartitions()
df.show()
+---+
| id|
+---+
|100|
|137|
|174|
|211|
|248|
|285|
|322|
|359|
|396|
|433|
|470|
|507|
|544|
|581|
|618|
|655|
|692|
|729|
|766|
|803|
+---+
only showing top 20 rows
7.read 该方法返回 DataFrameReader对象,通过这个对象可以读取外部文件来创建
8.readStream 该方法返回DataStreamReader对象,该对象用于读取stream数据
9.sparkContext 返回底层的sparkContext对象
sc1 = spark.sparkContext
print(sc1.master)
local
10.sql(sqlQuery),使用SQL语句从表格或者视图中查询数据
df = spark.range(10,18,1,3)
df.show(8)
df.createOrReplaceTempView('test')
spark.sql('select * from test where id >= 13').show(5)
+---+
| id|
+---+
| 10|
| 11|
| 12|
| 13|
| 14|
| 15|
| 16|
| 17|
+---+
+---+
| id|
+---+
| 13|
| 14|
| 15|
| 16|
| 17|
+---+
11.stop()停止底层的sparkcontext
12.streams 返回StreamingQueryManager,该对象管理着在该sparksession中的所有StreamingQuery对象
13.table(tableName),使用一个表格的名字,返回该表格对应的DataFrame对象
df = spark.range(20)
df.createOrReplaceTempView('A')
spark.sql('select * from A where id > 10').show()
df1 = spark.table('A')
print(df.collect() == df1.collect())
| id|
+---+
| 11|
| 12|
| 13|
| 14|
| 15|
| 16|
| 17|
| 18|
| 19|
+---+
True
14.udf 返回UDFRegistration用于UDF函数的注册
print(spark.udf)
15.pyspark.sql.UDFRegistration(sqlContext),这个类正是用来注册用户自定义函数的类。这个类里面有一个最主要的方法,
register(name, f, returnType=StringType),第一个参数为自定义函数的名字,第二个参数f表示要传入的自定义的函数,函数里面定义了处理的逻辑,第三个关键字参数returnType用于定义返回值的类型,默认为StringType。
下面我们定义一个求n次方的方法,方法名字叫pow1(m,n),接收两个参数m,n。要在pow方法中实现m的n次方的计算,返回值为DoubleType.
from pyspark.sql.types import *
def pow1(m,n):
return float(m)**float(n)
udf = spark.udf
udf.register('pow1',pow1,returnType=DoubleType())
df = spark.range(0,10,2,3)
df.createOrReplaceTempView('A')
spark.sql('select pow1(id,2) from A').show()
spark.sql('select pow1(id,3) from A').show()
+-----------+
|pow1(id, 2)|
+-----------+
| 0.0|
| 4.0|
| 16.0|
| 36.0|
| 64.0|
+-----------+
|pow1(id, 3)|
+-----------+
| 0.0|
| 8.0|
| 64.0|
| 216.0|
| 512.0|
+-----------+