SparkSQL外部数据源

本文详细介绍SparkSQL如何处理各种外部数据源,包括HDFS、MySQL、Parquet等,涵盖数据加载、转换、JDBC操作及Perdicate PushDown优化策略。

场景介绍:

    大数据MapReduce,Hive,Spark作业,首先需要加载数据,数据的存放源可能是HDFS、HBase、S3、OSS mongoDB;数据格式也可能为json、text、csv、parquet、jdbc..或者数据格式经过压缩,不同格式文件需要不同的解析方式,

    如果需要HDFS关联MySQL数据,可以通过sqoop进行一些列转换到,如果使用External Data Source API直接加载为DF拿到数据, 简单的说可以通过SparkSQL拿到外部数据源数据加载成DF。


加载方式:

build-in :内置加载外部数据如 json、text、parquet、jdbc、HDFS;


third-party:第三方加载外部数据如HBase、S3、OSS mongoDB

    第三方JAR地址:https://spark-packages.org/  

    Maven工程需要导入gav

    spark-shell:需要外部导入--package g:a:v  

 

    SPARK_HOME/bin/spark-shell --packages com.databricks:spark-csv_2.11:1.5.0

         优势:下载依赖包到本地

缺点:内网环境没有网络无法下载


一、外部数据源读取parquet文件:

Spark context Web UI available at http://hadoop001:4040

Spark context available as 'sc' (master = local[2], app id = local-1536244013147).

Spark session available as 'spark'.

Welcome to

      ____              __

     / __/__  ___ _____/ /__

    _\ \/ _ \/ _ `/ __/  '_/

   /___/ .__/\_,_/_/ /_/\_\   version 2.3.1

      /_/

         

Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45)

Type in expressions to have them evaluated.

Type :help for more information.


scala> spark.read.load("file:///home/hadoop/app/spark--bin-2.6.0-cdh5.7.0/examples/src/main/resources/people.txt").show

提示错误:/people.txt is not a Parquet file


注意:spark.read.load()底层默认读取Parquet file

scala> spark.read.load("file:///home/hadoop/app/spark--bin-2.6.0-cdh5.7.0/examples/src/main/resources/users.parquet").show

18/09/06 10:32:29 WARN ObjectStore: Failed to get database global_temp, returning NoSuchObjectException

+------+--------------+----------------+                                        
|  name|favorite_color|favorite_numbers|
+------+--------------+----------------+
|Alyssa|          null|  [3, 9, 15, 20]|
|   Ben|           red|              []|
+------+--------------+----------------+

scala> val users = spark.read.load("file:///home/hadoop/app/spark--bin-2.6.0-cdh5.7.0/examples/src/main/resources/users.parquet")

users: org.apache.spark.sql.DataFrame = [name: string, favorite_color: string ... 1 more field]


scala> users.printSchema

root

 |-- name: string (nullable = true)

 |-- favorite_color: string (nullable = true)

 |-- favorite_numbers: array (nullable = true)

 |    |-- element: integer (containsNull = true)



scala> users.show

+------+--------------+----------------+
|  name|favorite_color|favorite_numbers|
+------+--------------+----------------+
|Alyssa|          null|  [3, 9, 15, 20]|
|   Ben|           red|              []|
+------+--------------+----------------+


-- 查看列,常规操作

scala> users.select("name").show

+------+
|  name|
+------+
|Alyssa|
|   Ben|
+------+


二、转换操作


-- 转成json格式输出

scala> users.select("name","favorite_color").write.format("json").save("file:////home/hadoop/data/parquet/")

[hadoop@hadoop001 parquet]$ cat *
{"name":"Alyssa"}
{"name":"Ben","favorite_color":"red"}


-- 不采取压缩

.option("compression","none")  


-- 转成text格式输出

scala> users.select("name").write.format("text").save("file:////home/hadoop/data/parquet2/")

[hadoop@hadoop001 parquet2]$ cat *

Alyssa


-- Save Modes

用法:.mode("")

1、default   -- 目标目录存在,抛出异常

2、append   -- 目标目录存在,重跑数据+1,无法保证数据幂等

3、overwrite -- 目标目录存在,覆盖原文件

4、ignore -- 忽略你的模式,目标纯在将不保存


三、spark-shell操作JDBC数据

-- 读取外部MySQL数据为DF

val jdbcDF = spark.read.format("jdbc").option("url", "jdbc:mysql://hadoop001:3306/ruozedata").option("driver","com.mysql.jdbc.Driver").option("dbtable", "city_info").option("user","root").option("password", "root").load()


-- 查看表信息

jdbcDF.show()


-- 获取本地数据 

val deptDF = spark.table("dept") 


-- join关联使用

deptDF.join(jdbcDF,deptDF.col("deptid") === jdbcDF.col("deptid"))



-- DF写入MySQL本地,数据类型有变化,重复写入需要加上.mode("overwrite")

jdbcDF.write.format("jdbc").option("url", "jdbc:mysql://hadoop001:3306/hive_data").option("driver","com.mysql.jdbc.Driver").option("dbtable", "city_info_bak").option("user","root").option("password", "root").save()

mysql> show tables

+---------------------------+
| Tables_in_hive_data       |
+---------------------------+
| bucketing_cols            |
| cds                       |
| city_info_bak             |
+---------------------------+


-- 如果想类型不发生变化指定option指定字段类型

.option("createTableColumnTypes", "name CHAR(64), comments VARCHAR(1024)")



四、spark-sql操作JDBC数据

-- SQL创建临时表视图,单session

CREATE TEMPORARY VIEW emp_sql
USING org.apache.spark.sql.jdbc
OPTIONS (
  url "jdbc:mysql://hadoop001:3306/ruozedata",
  dbtable "city_info",
  user 'root',
  password 'root'
)

show tbales;

INSERT INTO TABLE emp_sql

SELECT * FROM emp_sql



五、Perdicate Push Down(PPD)

               disk         network                  CPU

外部数据外(1T)------->获取本地磁盘(1T)---------->提交到集群(1T)--------->结果(1G)


               disk        network                   CPU

外部数据外(1T)------->经过列裁剪(10G)----------->提交到集群(10G)----------->传结果(1g)


               disk          CPU                 network

外部数据外(1T)------->经过列裁剪(10G)---------->进过计算(1G)----------->传输结果



六、SparkSQL外部数据源实现机制

-- 0.有效的读取外部数据源的数据的


-- 1.buildScan扫描整张表,变成一个RDD[ROW]

trait TableScan {

def buildScan (): RDD[Row]  

}

-- 2.PrunedScan获取表的裁剪列

trait PrunedScan {

def buildScan (requiredColumns: Array[String]): RDD[Row] 


-- 3.PrunedFilteredScan列裁剪,行过滤

trait PrunedFilteredScan {

def buildScan (requiredColumns: Array[String], filters: Array[Filter]): RDD[Row]


-- 4.加载外部数据源的数据,定义数据的schema信息

abstract class BaseRelation {


-- 5.Relation产生BaseRelation使用

trait RelationProvider

}



总归:


-- 查询类操作

trait PrunedScan {

  def buildScan (requiredColumns: Array[String]): RDD[Row]

}  

 

-- 列裁剪,行过滤

trait PrunedFilteredScan {

  def buildScan(requiredColumns: Array[String], filters: Array[Filter]): RDD[Row]

}  

-- 写入类操作

trait InsertableRelation {

  def insert (data: DataFrame, overwrite: Boolean): Unit

}


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31441024/viewspace-2213714/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/31441024/viewspace-2213714/

### Spark SQL 数据源配置与读取方式 Spark SQL 支持多种数据源的读写操作,这些数据源包括但不限于 Parquet、JSON、CSV 和 JDBC 等。以下是关于如何配置和读取不同数据源的具体方法。 #### 配置 SparkSession 在使用 Spark SQL 处理任何数据之前,都需要初始化 `SparkSession` 对象。这是 Spark 应用程序的主要入口点,用于执行所有的 DataFrame 或 Dataset 操作。通过启用 Hive 支持,还可以访问存储在 Hive 中的元数据和表结构[^3]。 ```scala import org.apache.spark.sql.SparkSession val spark: SparkSession = SparkSession.builder() .appName("Data Source Example") .config("spark.some.config.option", "some-value") // 可选配置项 .enableHiveSupport() // 如果需要支持 Hive 表,则需调用此函数 .getOrCreate() ``` #### JSON 文件读取 对于 JSON 格式的文件,可以通过指定路径直接加载为 DataFrame。默认情况下,Spark 能够自动推断 JSON 的 Schema 结构[^1]。 ```scala // 加载本地或 HDFS 上的 JSON 文件 val jsonDF = spark.read.json("/path/to/json/file") jsonDF.printSchema() // 查看 Schema jsonDF.show() // 显示前几条记录 ``` #### CSV 文件读取 类似于 JSON 文件,也可以轻松地从 CSV 文件创建 DataFrame。需要注意的是,在大多数场景下,建议手动定义 Schema 来提高性能并减少错误风险。 ```scala // 使用逗号分隔符,默认不带 Header val csvDFWithoutHeader = spark.read.format("csv").option("sep", ",").load("/path/to/csv/without_header.csv") // 带有 Header 的 CSV 文件 val csvDFFromFileWithHeader = spark.read.format("csv").option("header", "true").load("/path/to/csv/with_header.csv") ``` #### Parquet 文件读取 Parquet 是一种高效的列式存储格式,广泛应用于大数据处理领域。它不仅压缩率高而且查询速度快,非常适合大规模数据分析任务。 ```scala val parquetDF = spark.read.parquet("/path/to/parquet/files") parquetDF.createOrReplaceTempView("temp_parquet_view") // 创建临时视图以便后续 SQL 查询 ``` #### Hive 表读取 当启用了 Hive 支持之后,可以直接利用现有的 Hive Metastore 进行表管理以及复杂 ETL 流程开发工作[^2]。 ```scala // 访问已存在的 Hive 表 val hiveTableDF = spark.table("hive_database.hive_table_name") hiveTableDF.show() // 执行自定义 SQL 查询语句返回结果集作为一个新的 Dataframe 实例对象 val resultFromSQLQueryOnHiveTables = spark.sql(""" SELECT column_a, COUNT(*) AS count_b FROM another_hive_table GROUP BY column_a ORDER BY count_b DESC LIMIT 10; """) resultFromSQLQueryOnHiveTables.collect().foreach(println(_)) ``` #### 写入外部数据源 除了上述提到的各种输入源之外,还能够很方便地把计算后的中间产物或者最终成果保存回磁盘上成为持久化副本形式存在下来供以后再次重复利用[^4]。 ```scala df.write.mode(SaveMode.Overwrite).format("orc").save("/output/path/orc") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值