SparkSql自定义数据源之读取的实现

一.sparksql读取数据源的过程

1.spark目前支持读取jdbc,hive,text,orc等类型的数据,如果要想支持hbase或者其他数据源,就必须自定义

 2.读取过程

(1)sparksql进行 session.read.text()或者 session.read .format("text") .options(Map("a"->"b")).load("")

 

 

 

 

read.方法:创建DataFrameReader对象

format方法:赋值DataFrameReade数据源类型

options方法:赋值DataFrameReade额外的配置选项

 进入 session.read.text()方法内,可以看到format为“text”

(2)进入load方法

 load原来是:sparkSession.baseRelationToDataFrame这个方法最终创建dataframe

(3进入DataSource的resolveRelation()方法

 

 此段就是:providingClass这个类是哪一个接口的实现类,分为有shema与没有传入schema的两种

(3)providingClass是format传入的数据源类型,也就是前面的source

 

 

 spark提供的所有数据源的map

 4.得出结论只要写一个类,实现RelationProvider下面这个方法,在方法里面返回一个baserelation

1
def createRelation(sqlContext: SQLContext, parameters: Map[String, String]): BaseRelation

 我们在实现baserelation里面的逻辑就可以了

 5.看看spark读取jdbc类

需要一个类,实现xxxScan这中类,这种类有三种,全局扫描tableScan,PrunedFilteredScan(列裁剪与谓词下推),PrunedScan ,

实现buildscan方法返回row类型rdd,结合baserelation有shcame这个变量 ,就凑成了dataframe

 6.jdbcRdd.scanTable方法,得到RDD

7.查看jdbcRDD的compute方法,是通过jdbc查询sql的方式获取数据

RDD的计算是惰性的,一系列转换操作只有在遇到动作操作是才会去计算数据,而分区作为数据计算的基本单位。在计算链中,无论一个RDD有多么复杂,其最终都会调用内部的compute函数来计算一个分区的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
override def compute(thePart: Partition, context: TaskContext): Iterator[InternalRow] = {
    var closed = false
    var rs: ResultSet = null
    var stmt: PreparedStatement = null
    var conn: Connection = null
 
    def close() {
      if (closed) return
      try {
        if (null != rs) {
          rs.close()
        }
      } catch {
        case e: Exception => logWarning("Exception closing resultset", e)
      }
      try {
        if (null != stmt) {
          stmt.close()
        }
      } catch {
        case e: Exception => logWarning("Exception closing statement", e)
      }
      try {
        if (null != conn) {
          if (!conn.isClosed && !conn.getAutoCommit) {
            try {
              conn.commit()
            } catch {
              case NonFatal(e) => logWarning("Exception committing transaction", e)
            }
          }
          conn.close()
        }
        logInfo("closed connection")
      } catch {
        case e: Exception => logWarning("Exception closing connection", e)
      }
      closed = true
    }
 
    context.addTaskCompletionListener{ context => close() }
 
    val inputMetrics = context.taskMetrics().inputMetrics
    val part = thePart.asInstanceOf[JDBCPartition]
    conn = getConnection()
    val dialect = JdbcDialects.get(url)
    import scala.collection.JavaConverters._
    dialect.beforeFetch(conn, options.asProperties.asScala.toMap)
 
    // H2's JDBC driver does not support the setSchema() method.  We pass a
    // fully-qualified table name in the SELECT statement.  I don't know how to
    // talk about a table in a completely portable way.
 
//坐上每个分区的Filter条件
    val myWhereClause = getWhereClause(part)
 
  //最終查询sql语句
    val sqlText = s"SELECT $columnList FROM ${options.table} $myWhereClause"
//jdbc查询
    stmt = conn.prepareStatement(sqlText,
        ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)
    stmt.setFetchSize(options.fetchSize)
    rs = stmt.executeQuery()
 
    val rowsIterator = JdbcUtils.resultSetToSparkInternalRows(rs, schema, inputMetrics)
//返回迭代器
    CompletionIterator[InternalRow, Iterator[InternalRow]](
      new InterruptibleIterator(context, rowsIterator), close())
  }

  

posted @   夜半钟声到客船  阅读(3373)  评论(4编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
历史上的今天:
2019-03-04 kafka消费者实时消费数据存入hdfs java scalca 代码
点击右上角即可分享
微信分享提示