本文spark为2.0.0 编程语言为java
Spark SQL 是 Spark 用来处理结构化数据的一个模块。与基础的 Spark RDD API 不同,Spark SQL 提供了更多数据与要执行的计算的信息。在其实现中,会使用这些额外信息进行优化。可以使用 SQL 语句和 Dataset API 来与 Spark SQL 模块交互。无论你使用哪种语言或 API 来执行计算,都会使用相同的引擎。这让你可以选择你熟悉的语言(现支持 Scala、Java、R、Python)以及在不同场景下选择不同的方式来进行计算
Spark SQL的一种用法是执行SQL查询。Spark SQL也可以用于从已安装的Hive中读取数据。当从内部其他编程语言执行SQL,结果将以Dataset/DataFrame形式返回。你也可以通过command-line或者JDBC/ODBC与SQL接口进行交互。
Dataset 是一个分布式数据集合。Dataset 是自 Spark 1.6开始提供的新接口,能同时享受到 RDDs 的优势(强类型,能使用强大的 lambda 函数)以及 Spark SQL 优化过的执行引擎。Dataset 可以从 JVM 对象(s)创建而来并且可以使用各种 transform 操作(比如 map,flatMap,filter 等)。目前 Dataset API 支持 Scala 和 Java。Python 暂不支持 Dataset API。不过得益于 Python 的动态属性,可以享受到许多 DataSet API 的益处。R 也是类似情况。
DataFrame 是具有名字的列。概念上相当于关系数据库中的表或 R/Python 下的 data frame,但有更多的优化。DataFrames(Dataset 亦是如此) 可以从很多数据中构造,比如:结构化文件、Hive 中的表,数据库,已存在的 RDDs。DataFrame API 可在 Scala、Java、Python 和 R 中使用。在 Scala 和 Java 中,DataFrame 由一个元素为 Row 的 Dataset 表示。在 Scala API 中,DataFrame 只是 Dataset[Row] 的别名。在 Java API 中,类型为 Dataset。
Language | Main Abstraction |
---|---|
Scala | Dataset[T] & DataFrame (alias for Dataset[Row]) |
Java | Dataset |
Python* | DataFrame |
R* | DataFrame |
在本文剩余篇幅中,会经常使用 DataFrame 来代指 Scala/Java 元素为 Row 的 Dataset。
SparkSession是spark2.0所有功能的新入口点,代替了原来的SparkContext和其他扩展入口,只需调用
sparkSession.builder()
即可创建
SparkSession spark= SparkSession.builder()
.master("local")
.appName("Json")
.config("spark.sql.warehouse.dir", "file:///E:\\apache\\jartest\\mvndatabase")
//此处需要将spark.sql.warehouse.dir指定到本地正确的仓库地址
.getOrCreate();
使用 SparkSession,可以从已经在的 RDD、Hive 表以及 Spark 支持的数据格式创建。
下面这个例子就是读取一个 Json 文件来创建一个 DataFrames
Dataset df=spark.read().json("D://test.json");
df.show();
//结果如下所示
+--------------------+--------------------+--------------------+--------------------+
| _corrupt_record| description| link| title|
+--------------------+--------------------+--------------------+--------------------+
| [| null| null| null|
| // ActiveRecord...| null| null| null|
| null|Sets attributes t...|http://api.rubyon...| create_with(value)|
| null|Specifies whether...|http://api.rubyon...|distinct(value = ...|
| null|Forces eager load...|http://api.rubyon...| eager_load(*args)|
| null|Used to extend a ...|http://api.rubyon...|extending(*module...|
| null|Specifies table f...|http://api.rubyon...|from(value, subqu...|
| null|Allows to specify...|http://api.rubyon...| group(*args)|
| null|Allows to specify...|http://api.rubyon...| having(opts, *rest)|
| null|Specify relations...|http://api.rubyon...| includes(*args)|
| null|Performs a joins ...|http://api.rubyon...| joins(*args)|
| null|Specifies a limit...|http://api.rubyon...| limit(value)|
| null|Specifies locking...|http://api.rubyon...| lock(locks = true)|
| null|Returns a chainab...|http://api.rubyon...| none()|
| null|Specifies the num...|http://api.rubyon...| offset(value)|
| null|Allows to specify...|http://api.rubyon...| order(*args)|
| null|Allows preloading...|http://api.rubyon...| preload(*args)|
| null|Sets readonly att...|http://api.rubyon...|readonly(value = ...|
| null|Use to indicate t...|http://api.rubyon...|references(*table...|
| null|Replaces any exis...|http://api.rubyon...| reorder(*args)|
+--------------------+--------------------+--------------------+--------------------+
only showing top 20 rows
DataFrame在Scala、Java、Python和R中为结构化数据操作提供了一个特定领域语言支持。 就像网文提到的,在Spark2.0中,在Scala和Java的API中,DataFrame仅仅是Dataset的RowS表示。与Scala/Java中的强类型的“带类型转换操作”相比,这些操作也可以看做“无类型转换操作”。这里我们提供了一些使用Dataset进行结构化数据处理的基本示例:
df.select("title").show();
//结果如下
+--------------------+
| title|
+--------------------+
| null|
| null|
| create_with(value)|
|distinct(value = ...|
| eager_load(*args)|
|extending(*module...|
|from(value, subqu...|
| group(*args)|
| having(opts, *rest)|
| includes(*args)|
| joins(*args)|
| limit(value)|
| lock(locks = true)|
| none()|
| offset(value)|
| order(*args)|
| preload(*args)|
|readonly(value = ...|
|references(*table...|
| reorder(*args)|
+--------------------+
only showing top 20 rows
df.groupBy("title").count().show();
//结果如下
+--------------------+-----+
| unscope(*args)| 1|
| order(*args)| 1|
| preload(*args)| 1|
| eager_load(*args)| 1|
| uniq(value = true)| 1|
| having(opts, *rest)| 1|
| null| 4|
| limit(value)| 1|
| select(*fields)| 1|
| reverse_order()| 1|
| PHP����õ�����| 1|
|readonly(value = ...| 1|
|references(*table...| 1|
|distinct(value = ...| 1|
| none()| 1|
| offset(value)| 1|
| joins(*args)| 1|
|extending(*module...| 1|
| rewhere(conditions)| 1|
| create_with(value)| 1|
+--------------------+-----+
only showing top 20 rows
Sparksession中的sql函数使得应用可以编程式执行SQL查询语句并且已DataFrame形式返回:
df.createOrReplaceTempView("test");
Dataset sqlDF=spark.sql("SELECT*FROM test");
sqlDF.show();
+--------------------+--------------------+--------------------+--------------------+
| _corrupt_record| description| link| title|
+--------------------+--------------------+--------------------+--------------------+
| [| null| null| null|
| // ActiveRecord...| null| null| null|
| null|Sets attributes t...|http://api.rubyon...| create_with(value)|
| null|Specifies whether...|http://api.rubyon...|distinct(value = ...|
| null|Forces eager load...|http://api.rubyon...| eager_load(*args)|
| null|Used to extend a ...|http://api.rubyon...|extending(*module...|
| null|Specifies table f...|http://api.rubyon...|from(value, subqu...|
| null|Allows to specify...|http://api.rubyon...| group(*args)|
| null|Allows to specify...|http://api.rubyon...| having(opts, *rest)|
| null|Specify relations...|http://api.rubyon...| includes(*args)|
| null|Performs a joins ...|http://api.rubyon...| joins(*args)|
| null|Specifies a limit...|http://api.rubyon...| limit(value)|
| null|Specifies locking...|http://api.rubyon...| lock(locks = true)|
| null|Returns a chainab...|http://api.rubyon...| none()|
| null|Specifies the num...|http://api.rubyon...| offset(value)|
| null|Allows to specify...|http://api.rubyon...| order(*args)|
| null|Allows preloading...|http://api.rubyon...| preload(*args)|
| null|Sets readonly att...|http://api.rubyon...|readonly(value = ...|
| null|Use to indicate t...|http://api.rubyon...|references(*table...|
| null|Replaces any exis...|http://api.rubyon...| reorder(*args)|
+--------------------+--------------------+--------------------+--------------------+
only showing top 20 rows
Spark SQL通过DataFrame接口,可以支持对多种数据源的操作。DataFrame可以使用关系转换来进行操作,而且可以用来创建临时视图。将DataFrame注册为临时视图可以允许你在数据上运行SQL查询语句。本节讲解使用SparkData Source加载数据和保存数据的通用方法,然后详细讲述内部支持的数据源可用的特定操作。
最简单的,默认的数据源(parquet,除非使用spark.sql.sources.default进行了配置)将被用于所有的操作
Dataset usersDF = spark.read().load("examples/src/main/resources/users.parquet");
usersDF.select("name", "favorite_color").write().save("namesAndFavColors.parquet");
你可以手动指定数据源以及数据源附带的额外选项。数据源被他们的完全限定名来指定(如,org.apache.spark.sql.parquet),但对于内部支持的数据源,你可以使用短名(json,parquet,jdbc)。DataFrame可以使用这种语法从任何可以转换为其他类型的数据源加载数据。
Dataset peopleDF =
spark.read().format("json").load("examples/src/main/resources/people.json");
peopleDF.select("name", "age").write().format("parquet").save("namesAndAges.parquet");
除了使用读取API加载一个文件到SATAFrame然后查询它的方式,你同样可以通过SQL直接查询文件。
Dataset sqlDF
=spark.sql("SELECT * FROM parquet.`examples/src/main/resources/users.parquet`");
Spark SQL可以自动推断JSON数据集的schema并且加载为Dataset[Row]。可以对String类型的RDD或者JSON文件使用SparkSession.read.json()来实现这种转换。
注意这里的JSON文件不是通常意义的JSON文件。每一行必须包含分离的,完整有效的JSON对象。因此,不支持常用的多行式JSON文件。
1.读入JSON文件
Dataset people = spark.read().json("examples/src/main/resources/people.json");
people.createOrReplaceTempView("people");
Dataset namesDF = spark.sql("SELECT name FROM people WHERE age BETWEEN 13 AND 19");
namesDF.show();
2.手动创建JSON格式的数组
List jsonData = Arrays.asList(
"{\"name\":\"Yin\",\"address\":{\"city\":\"Columbus\",\"state\":\"Ohio\"}}");
Dataset anotherPeopleDataset = spark.createDataset(jsonData, Encoders.STRING());
Dataset anotherPeople = spark.read().json(anotherPeopleDataset);
anotherPeople.show();