多样 | spark数据源特点

1、背景引入:spark SQL的数据源
Spark SQL是Spark的一个模块,用于结构化数据的处理。

使用Spark SQL的方式有2种,可以通过SQL或者Dataset API,这两种使用方式在本文都会涉及。

其中,通过SQL接口使用的方法具体又可分为3种:

在程序中执行

使用命令行

Jdbc/ODBC

Spark关于分布式数据集的抽象原本是RDD,Dataset是其升级版本。DataFrame是特殊的Dataset,它限定元素是按照命名的列来组织的,从这一点看相当于关系型数据库中的表。DataFrame等价于Dataset[Row],而且DataFrame是本文内容的核心。

本文主要和大家讨论一下sparkSQL数据源的多样性,以及每种数据源有什么特点,以及都是怎么使用的。

2、通用加载/保存方法
Spark SQL的DataFrame接口支持多种数据源的操作。一个DataFrame可以进行RDDs方式的操作,也可以被注册为临时表。把DataFrame注册为临时表之后,就可以对该DataFrame执行SQL查询。

Spark SQL的默认数据源为Parquet格式。数据源为Parquet文件时,Spark SQL可以方便的执行所有的操作。修改配置项spark.sql.sources.default,可修改默认数据源格式。

val df = spark.read.load(“examples/src/main/resources/users.parquet”)

df.select(“name”,“favorite_color”).write.save(“namesAndFavColor.parquet”)

当数据源格式不是parquet格式文件时,需要手动指定数据源的格式。数据源格式需要指定全名(例如:org.apache.spark.sql.parquet),如果数据源格式为内置格式,则只需要指定简称定json, parquet, jdbc, orc, libsvm, csv, text来指定数据的格式。

可以通过SparkSession提供的read.load方法用于通用加载数据,使用write和save保存数据。

val peopleDF =spark.read.format(“json”).load("examples/src/main/resources

/people.json")

peopleDF.write.format(“parquet”).save(“hdfs://master01:9000/namesAndAges.parquet”)

除此之外,可以直接运行SQL在文件上:

val sqlDF = spark.sql("SELECT * FROM parquet.`hdfs://master01:9000/

namesAndAges.parquet`")

sqlDF.show()

scala> val peopleDF = spark.read.format(“json”).load(“examples/src/main/resources/people.json”)

peopleDF: org.apache.spark.sql.DataFrame = [age: bigint, name: string]

scala> peopleDF.write.format(“parquet”).save(“hdfs://master01:9000/namesAndAges.parquet”)

scala> peopleDF.show()

±—±------+

| age| name|

±—±------+

|null|Michael|

| 30| Andy|

| 19| Justin|

±—±------+

scala> val sqlDF = spark.sql(“SELECT * FROM parquet.hdfs://master01:9000/namesAndAges.parquet”)

17/09/05 04:21:11 WARN ObjectStore: Failed to get database parquet, returning NoSuchObjectException

sqlDF: org.apache.spark.sql.DataFrame = [age: bigint, name: string]

scala> sqlDF.show()

±—±------+

| age| name|

±—±------+

|null|Michael|

| 30| Andy|

| 19| Justin|

±—±------+

可以采用SaveMode执行存储操作,SaveMode定义了对数据的处理模式。需要注意的是,这些保存模式不使用任何锁定,不是原子操作。此外,当使用Overwrite方式执行时,在输出新数据之前原数据就已经被删除。SaveMode详细介绍如下表:

SaveMode.ErrorIfExists(default):“error”(default),如果文件存在,则报错.

SaveMode.Append:“append”,追加。

SaveMode.Overwrite:“overwrite”,覆写。

SaveMode.Ignore:“ignore”,数据存在,则忽略。

3、Parquet文件
Parquet是一种流行的列式存储格式,可以高效地存储具有嵌套字段的记录。

Parquet格式经常在Hadoop生态圈中被使用,它也支持Spark SQL的全部数据类型。Spark SQL 提供了直接读取和存储 Parquet 格式文件的方法。

import spark.implicits._

val peopleDF = spark.read.json(“examples/src/main/resources/people.json”)

// DataFrames can be saved as Parquet files, maintaining the schema information

peopleDF.write.parquet(“hdfs://master01:9000/people.parquet”)

// Read in the parquet file created above

// Parquet files are self-describing so the schema is preserved

// The result of loading a Parquet file is also a DataFrame

val parquetFileDF = spark.read.parquet("hdfs://master01:9000

/people.parquet")

// Parquet files can also be used to create a temporary view and then used in SQL statements

parquetFileDF.createOrReplaceTempView(“parquetFile”)

val namesDF = spark.sql(“SELECT name FROM parquetFile WHERE age BETWEEN 13 AND 19”)

namesDF.map(attributes => "Name: " + attributes(0)).show()

// ±-----------+

// | value|

// ±-----------+

// |Name: Justin|

// ±-----------+

对表进行分区是对数据进行优化的方式之一。在分区的表内,数据通过分区列将数据存储在不同的目录下。Parquet数据源现在能够自动发现并解析分区信息。例如,对人口数据进行分区存储,分区列为gender和country。

通过传递path/to/table给 SQLContext.read.parquet或SQLContext.read.load,Spark SQL将自动解析分区信息。

需要注意的是,数据的分区列的数据类型是自动解析的。当前,支持数值类型和字符串类型。自动解析分区类型的参数为:

spark.sql.sources.partitionColumnTypeInference.enabled,默认值为true。如果想关闭该功能,直接将该参数设置为disabled。此时,分区列数据格式将被默认设置为string类型,不再进行类型解析。

像ProtocolBuffer、Avro和Thrift那样,Parquet也支持Schema evolution(Schema演变)。用户可以先定义一个简单的Schema,然后逐渐的向Schema中增加列描述。通过这种方式,用户可以获取多个有不同Schema但相互兼容的Parquet文件。现在Parquet数据源能自动检测这种情况,并合并这些文件的schemas。

因为Schema合并是一个高消耗的操作,在大多数情况下并不需要,所以Spark SQL从1.5.0开始默认关闭了该功能。可以通过下面两种方式开启该功能:

当数据源为Parquet文件时,将数据源选项mergeSchema设置为true

设置全局SQL选项spark.sql.parquet.mergeSchema为true

示例如下:

import spark.implicits._

// Create a simple DataFrame, stored into a partition directory

val df1 = sc.makeRDD(1 to 5).map(i => (i, i * 2)).toDF(“single”, “double”)

df1.write.parquet(“hdfs://master01:9000/data/test_table/key=1”)

// Create another DataFrame in a new partition directory,

// adding a new column and dropping an existing column

val df2 = sc.makeRDD(6 to 10).map(i => (i, i * 3)).toDF(“single”, “triple”)

df2.write.parquet(“hdfs://master01:9000/data/test_table/key=2”)

// Read the partitioned table

val df3 = spark.read.option(“mergeSchema”, “true”).parquet("hdfs://

master01:9000/data/test_table")

df3.printSchema()

// The final schema consists of all 3 columns in the Parquet files together

// with the partitioning column appeared in the partition directory paths.

// root

// |-- single: int (nullable = true)

// |-- double: int (nullable = true)

// |-- triple: int (nullable = true)

// |-- key : int (nullable = true)

4、Hive数据库
Apache Hive是Hadoop上的SQL引擎,Spark SQL编译时可以包含Hive支持,也可以不包含。包含Hive支持的Spark SQL可以支持Hive表访问、UDF(用户自定义函数)以及 Hive 查询语言(HiveQL/HQL)等。需要强调的 一点是,如果要在Spark SQL中包含Hive的库,并不需要事先安装Hive。一般来说,最好还是在编译Spark SQL时引入Hive支持,这样就可以使用这些特性了。如果你下载的是二进制版本的 Spark,它应该已经在编译时添加了 Hive 支持。

若要把Spark SQL连接到一个部署好的Hive上,你必须把hive-site.xml复制到 Spark的配置文件目录中($SPARK_HOME/conf)。即使没有部署好Hive,Spark SQL也可以运行。需要注意的是,如果你没有部署好Hive,Spark SQL会在当前的工作目录中创建出自己的Hive 元数据仓库,叫作 metastore_db。此外,如果你尝试使用 HiveQL 中的 CREATE TABLE (并非 CREATE EXTERNAL TABLE)语句来创建表,这些表会被放在你默认的文件系统中的 /user/hive/warehouse 目录中(如果你的 classpath 中有配好的 hdfs-site.xml,默认的文件系统就是 HDFS,否则就是本地文件系统)。

import java.io.File

import org.apache.spark.sql.Row
import org.apache.spark.sql.SparkSession

case class Record(key: Int, value: String)

// warehouseLocation points to the default location for managed databases and tables
val warehouseLocation = new File(“spark-warehouse”).getAbsolutePath

val spark = SparkSession
.builder()
.appName(“Spark Hive Example”)
.config(“spark.sql.warehouse.dir”, warehouseLocation)
.enableHiveSupport()
.getOrCreate()

import spark.implicits._
import spark.sql

sql(“CREATE TABLE IF NOT EXISTS src (key INT, value STRING)”)
sql(“LOAD DATA LOCAL INPATH ‘examples/src/main/resources/kv1.txt’ INTO TABLE src”)

// Queries are expressed in HiveQL
sql(“SELECT * FROM src”).show()
// ±–±------+
// |key| value|
// ±–±------+
// |238|val_238|
// | 86| val_86|
// |311|val_311|
// …

// Aggregation queries are also supported.
sql(“SELECT COUNT(*) FROM src”).show()
// ±-------+
// |count(1)|
// ±-------+
// | 500 |
// ±-------+

// The results of SQL queries are themselves DataFrames and support all normal functions.
val sqlDF = sql(“SELECT key, value FROM src WHERE key < 10 ORDER BY key”)

// The items in DataFrames are of type Row, which allows you to access each column by ordinal.
val stringsDS = sqlDF.map {
case Row(key: Int, value: String) => s"Key: $key, Value: $value"
}
stringsDS.show()
// ±-------------------+
// | value|
// ±-------------------+
// |Key: 0, Value: val_0|
// |Key: 0, Value: val_0|
// |Key: 0, Value: val_0|
// …

// You can also use DataFrames to create temporary views within a SparkSession.
val recordsDF = spark.createDataFrame((1 to 100).map(i => Record(i, s"val_$i")))
recordsDF.createOrReplaceTempView(“records”)

// Queries can then join DataFrame data with data stored in Hive.
sql(“SELECT * FROM records r JOIN src s ON r.key = s.key”).show()
// ±–±-----±–±-----+
// |key| value|key| value|
// ±–±-----±–±-----+
// | 2| val_2| 2| val_2|
// | 4| val_4| 4| val_4|
// | 5| val_5| 5| val_5|
// …

如果你使用的是内部的Hive,在Spark2.0之后,spark.sql.warehouse.dir用于指定数据仓库的地址,如果你需要是用HDFS作为路径,那么需要将core-site.xml和hdfs-site.xml 加入到Spark conf目录,否则只会创建master节点上的warehouse目录,查询时会出现文件找不到的问题,这是需要向使用HDFS,则需要将metastore删除,重启集群。

如果想连接外部已经部署好的Hive,需要通过以下几个步骤。

1)将Hive中的hive-site.xml拷贝或者软连接到Spark安装目录下的conf目录下。

2)打开spark shell,注意带上访问Hive元数据库的JDBC客户端。

5、JSON数据集
Spark SQL 能够自动推测 JSON数据集的结构,并将它加载为一个Dataset[Row]. 可以通过SparkSession.read.json()去加载一个 Dataset[String]或者一个JSON 文件.注意,这个JSON文件不是一个传统的JSON文件,每一行都得是一个JSON串。

val path = “examples/src/main/resources/people.json”

val peopleDF = spark.read.json(path)

6、JDBC
Spark SQL可以通过JDBC从关系型数据库中读取数据的方式创建DataFrame,通过对DataFrame一系列的计算后,还可以将数据再写回关系型数据库中。

注意,需要将相关的数据库驱动放到spark的类路径下。

7、JDBC/ODBC服务器
Spark SQL也提供JDBC连接支持,这对于让商业智能(BI)工具连接到Spark集群上以 及在多用户间共享一个集群的场景都非常有用。JDBC 服务器作为一个独立的 Spark 驱动 器程序运行,可以在多用户之间共享。任意一个客户端都可以在内存中缓存数据表,对表 进行查询。集群的资源以及缓存数据都在所有用户之间共享。

Spark SQL的JDBC服务器与Hive中的HiveServer2相一致。由于使用了Thrift通信协议,它也被称为“Thrift server”。

服务器可以通过 Spark 目录中的 sbin/start-thriftserver.sh 启动。这个 脚本接受的参数选项大多与 spark-submit 相同。默认情况下,服务器会在 localhost:10000 上进行监听,我们可以通过环境变量(HIVE_SERVER2_THRIFT_PORT 和 HIVE_SERVER2_THRIFT_BIND_HOST)修改这些设置,也可以通过 Hive配置选项(hive. server2.thrift.port 和 hive.server2.thrift.bind.host)来修改。你也可以通过命令行参 数–hiveconf property=value来设置Hive选项。

交流qq群:1022901775,获取课件、代码,技术交流,问题反馈;

为方便学习,请关注"百数云课"官方公众号。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值