SparkSession
Spark中所有功能的入口点是SparkSession类。 要创建基本的SparkSession,只需使用SparkSession.builder:
from pyspark.sql import SparkSession
spark = SparkSession \
.builder \
.appName("Python Spark SQL basic example") \
.config("spark.some.config.option", "some-value") \
.getOrCreate()
Spark 2.0中的SparkSession为Hive功能提供内置支持,包括使用HiveQL编写查询,访问Hive UDF以及从Hive表读取数据的功能。 要使用这些功能,您无需拥有现有的Hive设置。
SparkSession类:使用Dataset和DataFrame API编程Spark的入口点。[Source]
SparkSession可以用来创建DataFrames,将DataFrames注册成表,在表,缓存表上执行SQL,以及读取parquet 文件。
>>> spark = SparkSession.builder \
... .master("local") \
... .appName("Word Count") \
... .config("spark.some.config.option", "some-value") \
... .getOrCreate()
builder:具有构建SparkSession实例的Builder的类属性
Class Builder:
1.appName(name):为应用设置一个名字,这个名字会显示在Spark web UI,如果不设置的,将会随机产生一个。(New in version 2.0)
2.config(key=None,value=None,conf=None):设置配置选项。使用此方法设置的选项会自动传播到SparkConf和SparkSession自己的配置。(New in version 2.0)
对于现有的SparkConf,使用conf参数:
>>> from pyspark.conf import SparkConf
>>> SparkSession.builder.config(conf=SparkConf())
<pyspark.sql.session...
对于(key,value)键值对,你可以省略参数名称:
>>>SparkSession.builder.config("spark.some.config.option", "some-value")
<pyspark.sql.session...
3.enableHiveSupport
():启用Hive支持,包括与持久性Hive Metastore的连接,对Hive serdes的支持以及Hive用户定义的功能。(New in version 2.0)
4.getOrCreate
():得到一个存在的SparkSession,如果没有,则依赖bulider的选项配置创建一个新的。这个方法首先检查是否存在一个有效的全局默认的SparkSession,如果存在,则返回这个SparkSession。如果不存在,这个方法就会创建一个新的SaprkSession并将之注册为全局默认。
5.master(master):设置要连接的Spark主URL,例如“本地”以在本地运行,“local [4]”在本地运行4核,或“spark:// master:7077”在Spark独立群集上运行。(New in version 2.0)
......
创建DataFrames
使用SparkSession,程序可以从一个已经存在的RDD,Hive表或者Spark data source(后续将会介绍)
下面使用一个例子,依靠json文件创建一个DataFrame
# spark is an existing SparkSession
df = spark.read.json("examples/src/main/resources/people.json")
# Displays the content of the DataFrame to stdout
df.show()
# +----+-------+
# | age| name|
# +----+-------+
# |null|Michael|
# | 30| Andy|
# | 19| Justin|
# +----+-------+
无类型数据集操作(又名DataFrame[Source]操作)
DataFrames为Scala,Java,Python和R中的结构化数据操作提供特定于域的语言。
如上所述,在Spark 2.0中,DataFrames只是Scala和Java API中Rows的数据集。 与“类型转换”相比,这些操作也称为“无类型转换”,带有强类型Scala / Java数据集。
这里我们包括一些使用数据集进行结构化数据处理的基本示例:
在Python中,可以通过属性(df.age)或索引(df['age'])访问DataFrame的列。虽然前者便于交互式数据探索,但强烈鼓励用户使用后者,这是未来的证明,不会与DataFrame类上的属性列名相冲突。
# spark, df are from the previous example
# Print the schema in a tree format
df.printSchema()
# root
# |-- age: long (nullable = true)
# |-- name: string (nullable = true)
# Select only the "name" column
df.select("name").show()
# +-------+
# | name|
# +-------+
# |Michael|
# | Andy|
# | Justin|
# +-------+
# Select everybody, but increment the age by 1
df.select(df['name'], df['age'] + 1).show()
# +-------+---------+
# | name|(age + 1)|
# +-------+---------+
# |Michael| null|
# | Andy| 31|
# | Justin| 20|
# +-------+---------+
# Select people older than 21
df.filter(df['age'] > 21).show()
# +---+----+
# |age|name|
# +---+----+
# | 30|Andy|
# +---+----+
# Count people by age
df.groupBy("age").count().show()
# +----+-----+
# | age|count|
# +----+-----+
# | 19| 1|
# |null| 1|
# | 30| 1|
# +----+-----+
以编程方式运行SQL查询
SparkSession上的sql函数使应用程序能够以编程方式运行SQL查询并将结果作为DataFrame返回。
# Register the DataFrame as a SQL temporary view
df.createOrReplaceTempView("people")
sqlDF = spark.sql("SELECT * FROM people")
sqlDF.show()
# +----+-------+
# | age| name|
# +----+-------+
# |null|Michael|
# | 30| Andy|
# | 19| Justin|
# +----+-------+
全局临时视图
Spark SQL中的临时视图是会话范围的,如果创建它的会话终止,它将消失。 如果您希望拥有一个在所有会话之间共享的临时视图并保持活动状态,直到Spark应用程序终止,您可以创建一个全局临时视图。 全局临时视图与系统保留的数据库global_temp绑定,我们必须使用限定名称来引用它,例如 SELECT * FROM global_temp.view1。
# Register the DataFrame as a global temporary view
df.createGlobalTempView("people")
# Global temporary view is tied to a system preserved database `global_temp`
spark.sql("SELECT * FROM global_temp.people").show()
# +----+-------+
# | age| name|
# +----+-------+
# |null|Michael|
# | 30| Andy|
# | 19| Justin|
# +----+-------+
# Global temporary view is cross-session
spark.newSession().sql("SELECT * FROM global_temp.people").show()
# +----+-------+
# | age| name|
# +----+-------+
# |null|Michael|
# | 30| Andy|
# | 19| Justin|
# +----+-------+
创建Datasets
数据集与RDD类似,但是,它们不使用Java序列化或Kryo,而是使用专门的编码器来序列化对象以便通过网络进行处理或传输。 虽然编码器和标准序列化都负责将对象转换为字节,但编码器是动态生成的代码,并使用一种格式,允许Spark执行许多操作,如过滤,排序和散列,而无需将字节反序列化为对象。(java语言)
import java.util.Arrays;
import java.util.Collections;
import java.io.Serializable;
import org.apache.spark.api.java.function.MapFunction;
import org.apache.spark.sql.Dataset;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.Encoder;
import org.apache.spark.sql.Encoders;
public static class Person implements Serializable {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//创建一个Bean实例
Person person = new Person();
person.setName("Andy");
person.setAge(32);
//为Java beans 创建编码器
Encoder<Person> personEncoder = Encoders.bean(Person.class);
Dataset<Person> javaBeanDS = spark.createDataset(
Collections.singletonList(person),
personEncoder
);
javaBeanDS.show();
// +---+----+
// |age|name|
// +---+----+
// | 32|Andy|
// +---+----+
// 类编码器中提供了大多数常见类型的编码器
Encoder<Integer> integerEncoder = Encoders.INT();
Dataset<Integer> primitiveDS = spark.createDataset(Arrays.asList(1, 2, 3), integerEncoder);
Dataset<Integer> transformedDS = primitiveDS.map(
(MapFunction<Integer, Integer>) value -> value + 1,
integerEncoder);
transformedDS.collect(); // Returns [2, 3, 4]
//依靠基于名称的class.Mapping可以将DataFrames转化为Datasets
String path = "examples/src/main/resources/people.json";
Dataset<Person> peopleDS = spark.read().json(path).as(personEncoder);
peopleDS.show();
// +----+-------+
// | age| name|
// +----+-------+
// |null|Michael|
// | 30| Andy|
// | 19| Justin|
// +----+-------+