SparkSQL基于DataSourceV2自定义数据源

本文介绍了Spark 2.3版本之后的DataSourceV2,旨在解决DataSourceV1的不足,如不依赖上层API、易于扩展、支持列存储和流式计算等。并详细阐述了如何基于DataSourceV2实现自定义数据源,包括创建CustomDataSourceV2、CustomDataSourceV2Reader、DataReaderFactory及DataReader类,并通过REST接口获取JSON数据生成DataFrame的示例。
摘要由CSDN通过智能技术生成

SparkSQL基于DataSourceV2自定义数据源
版本说明:Spark 2.3

前言:之前在SparkSQL数据源操作文章中整理了一些SparkSQL内置数据源的使用,总的来说SparkSQL支持的数据源还是挺丰富的,但业务上可能不拘束于这几种数据源,比如将HBase作为SparkSQL的数据源,REST数据源等。这里主要讲一下在Spark2.3版本之后推出的DataSourceV2,基于DataSourceV2实现自定义数据源

1 DataSourceV1 VS DataSourceV2
自Spark1.3版本之后,引入了数据源API,我们可以实现自定义数据源。2.3版本之后又引入的新版API,关于V1与V2的区别以及使用可以参考https://blog.csdn.net/zjerryj/article/details/84922369与https://developer.ibm.com/code/2018/04/16/introducing-apache-spark-data-sources-api-v2/这两篇文章。这里简单的总结一下V1的缺点,以及V2的新特性。

1.1 DataSourceV1缺点
依赖上层API
难以添加新的优化算子
难以传递分区信息
缺少事务性的写操作
缺少列存储和流式计算支持
1.2 DataSourceV2优点
DataSourceV2 API使用Java编写
不依赖于上层API(DataFrame/RDD)
易于扩展,可以添加新的优化,同时保持向后兼容
提供物理信息,如大小、分区等
支持Streamin Source/Sink
灵活、强大和事务性的写入API
1.3 Spark2.3中V2的功能
支持列扫描和行扫描
列裁剪和过滤条件下推
可以提供基本统计和数据分区
事务写入API
支持微批和连续的Streaming Source/Sink
2 基于DataSourceV2实现输入源
SparkSQL的DataSourceV2的实现与StructuredStreaming自定义数据源如出一辙,思想是一样的,但是具体实现有所不同,主要步骤如下:

第一步:继承DataSourceV2和ReadSupport创建XXXDataSource类,重写ReadSupport的creatReader方法,用来返回自定义的DataSourceReader类,如返回自定义XXXDataSourceReader实例

第二步:继承DataSourceReader创建XXXDataSourceReader类,重写DataSourceReader的readSchema方法用来返回数据源的schema,重写DataSourceReader的createDataReaderFactories用来返回多个自定义DataReaderFactory实例

第三步:继承DataReaderFactory创建DataReader工厂类,如XXXDataReaderFactory,重写DataReaderFactory的createDataReader方法,返回自定义DataRader实例

第四步:继承DataReader类创建自定义的DataReader,如XXXDataReader,重写DataReader的next()方法,用来告诉Spark是否有下条数据,用来触发get()方法,重写DataReader的get()方法获取数据,重写DataReader的close()方法用来关闭资源

2.1 继承DataSourceV2和ReadSupport创建XXXDataSource类
这里以创建CustomDataSourceV2类为例

2.1.1 创建CustomDataSourceV2类
/**
  * 创建DataSource提供类
  * 1.继承DataSourceV2向Spark注册数据源
  * 2.继承ReadSupport支持读数据
  */
class CustomDataSourceV2 extends DataSourceV2
  with ReadSupport {
      // todo
}
1
2
3
4
5
6
7
8
9
2.1.2 重写ReadSupport的createReader方法
该方法用来返回一个用户自定义的DataSourceReader实例

  /**
    * 创建Reader
    *
    * @param options 用户定义的options
    * @return 自定义的DataSourceReader
    */
  override def createReader(options: DataSourceOptions): DataSourceReader = new CustomDataSourceV2Reader(options)
1
2
3
4
5
6
7
2.2 继承DataSourceReader创建XXXDataSourceReader类
该类用来自定义DataSourceReader,需要继承DataSourceReader,并重写readSchema和createDataReaderFactories方法。

2.2.1 创建CustomDataSourceV2Reader类
/**
  * 自定义的DataSourceReader
  * 继承DataSourceReader
  * 重写readSchema方法用来生成schema
  * 重写createDataReaderFactories,用来根据条件,创建多个工厂实例
  *
  * @param options options
  */
class CustomDataSourceV2Reader(options: DataSourceOptions) extends DataSourceReader {
    // Override some functions
}
1
2
3
4
5
6
7
8
9
10
11
2.2.2 重写DataSourceReader的readSchema方法
该方法用来返回数据源的schema

/**
  * 生成schema
  *
  * @return schema
  */
override def readSchema(): StructType = ???
1
2
3
4
5
6
2.2.3 重写DataSourceReader的createDataReaderFactories方法
实现该方法,可以根据不同的条件,创建多个createDataReader工厂实例,用来并发获取数据?(暂且这么理解的,或者是按照分区获取数据?)

  /**
    * 创建DataReader工厂实例
    *
    * @return 多个工厂类实例
    */
  override def createDataReaderFactories(): util.List[DataReaderFactory[Row]] = {
    import collection.JavaConverters._
    Seq(
      new CustomDataSourceV2ReaderFactory().asInstanceOf[DataReaderFactory[Row]]
    ).asJava
  }
1
2
3
4
5
6
7
8
9
10
11
2.3 继承DataReaderFactory创建DataReader工厂类
该类是DataReader的工厂来,用来返回DataReader实例

2.3.1 创建CustomDataSourceV2Factory类
/**
  * 自定义DataReaderFactory类
  */
class CustomDataSourceV2ReaderFactory extends DataReaderFactory[Row] {
   // Override some functions
}

1
2
3
4
5
6
7
2.3.2 重写DataReaderFactory的createDataReader方法
该方法用来实例化自定义的DataReader

  /**
    * 重写createDataReader方法,用来实例化自定义的DataReader
    *
    * @return 自定义的DataReader
    */
  override def createDataReader(): DataReader[Row] = new CustomDataReader
1
2
3
4
5
6
2.4 继承DataReader类创建自定义的DataReader
该类为重点实现部分,用来自定义获取数据的方式

2.4.1 创建CustomDataReader类
/**
  * 自定义DataReader类
  */
class CustomDataReader extends DataReader[Row] {
    // Override some functions
}
1
2
3
4
5
6
2.4.2 重写CustomDataReader的next()方法
该方法返回一个布尔值,来告诉Spark是否含有下条数据,以便触发get()方法获取数据

  /**
    * 是否有下一条数据
    *
    * @return boolean
    */
  override def next(): Boolean = ???
1
2
3
4
5
6
2.4.3 重写CustomDataReader的get()方法
该方法用来获取数据,返回类型是在继承DataReader时指定的泛型

  /**
    * 获取数据
    * 当next为true时会调用get方法获取数据
    *
    * @return Row
    */
  override def get(): Row = ???
1
2
3
4
5
6
7
2.4.4 重写CustomDataReader的close()方法
该方法用来关闭相应的资源

  /**
    * 关闭资源
    */
  override def close(): Unit = ???
1
2
3
4
2.5 以REST为例,实现自定义的数据源
这里主要是从REST接口里获取JSON格式的数据,然后生成DataFrame数据源

2.5.1 创建RestDataSource类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值