Spark經過修改DataFrame的schema給表字段添加註釋(轉載)

轉載自:https://www.jianshu.com/p/e4c90dc08935sql

一、需求背景

經過Spark將關係型數據庫(以Oracle爲例)的表同步的Hive表,要求用Spark建表,有字段註釋的也要加上註釋。Spark建表,有兩種方法:shell

  • 用Spark Sql,在程序裏組建表語句,而後用Spark.sql("建表語句")建表,這種方法麻煩的地方在於你要讀取Oracle表的詳細的表結構信息,且要進行Oracle和Hive的字段類型進行一一對應
  • 用DataFrame 的saveAsTable方法,這種方法若是對應的數據庫裏沒有表,則Spark會根據DataFrame的schema自動建表,比較簡單,不用考慮字段類型匹配轉化問題,可是這種方法有一個問題,Spark讀取Oracle的表爲DataFrame時,並不能將表字段的註釋讀進來,因此就有了如標題所示的需求。(一開始覺得DataFrame不能加註釋,通過研究,發現是能夠的!)

二、如何查看DataFrame是否有註釋

前面講到DataFrame裏沒有Oracle的註釋信息,可是若是數據源爲Hive的話,是能夠將註釋獲取到的。數據庫

2.1 新建Hive測試表(帶註釋)

create table `test` ( `id` string comment 'ID', `Name` string comment '名字' ) comment '測試';

2.2 Spark讀取hive表並打印註釋(在spark-shell裏執行)

首先看一下df.printSchema裏並無註釋信息apache

sql("use test") val df = spark.table("test") df.printSchema
root |-- id: string (nullable = true) |-- name: string (nullable = true)

用下面這行代碼即可以打印註釋信息:oracle

df.schema.foreach(s=>println(s.name,s.metadata))
(id,{"comment":"ID","HIVE_TYPE_STRING":"string"}) (name,{"comment":"名字","HIVE_TYPE_STRING":"string"})

三、讀取Oracle表並打印DataFrmae的元數據信息

3.1 新建Oracle測試表(帶註釋)

CREATE TABLE ORA_TEST ( ID VARCHAR2(100), NAME VARCHAR2(100) ); COMMENT ON COLUMN ORA_TEST.ID IS 'ID'; COMMENT ON COLUMN ORA_TEST.NAME IS '名字'; COMMENT ON TABLE ORA_TEST IS '測試';
  • 注:上面的註釋語句和建表語句須要分開執行,或者也能夠在數據庫工具執行腳本,好比我用的DBeaver用快捷鍵Alt+x便可。固然也能夠在工具的界面直接建表都可。

3.2 讀取Oracle表,並打印元數據

代碼:app

package com.dkl.leanring.spark.sql.Oracle import org.apache.spark.sql.SparkSession object OracleSchemaDemo { def main(args: Array[String]): Unit = { val spark = SparkSession.builder().appName("OracleSchemaDemo").master("local").getOrCreate() val df = spark.read .format("jdbc") .option("url", "jdbc:oracle:thin:@192.168.44.128:1521:orcl") .option("dbtable", "ORA_TEST") .option("user", "bigdata") .option("password", "bigdata") .option("driver", "oracle.jdbc.driver.OracleDriver") .load() df.schema.foreach(s => println(s.name, s.metadata)) spark.stop } }
(ID,{"name":"ID","scale":0}) (NAME,{"name":"NAME","scale":0})

注:Spark2.3.0和Spark2.2.1的元數據不太同樣,上面的結果是Spark2.2.1(也是我寫博客測試用的),項目中用的Spark2.3.0,2.3.0的元數據是空的,以下工具

(ID,{})
(NAME,{})

可見並無註釋信息測試

3.3 給DataFrame添加註釋

import org.apache.spark.sql.types._ val commentMap = Map("ID" -> "ID", "NAME" -> "名字") val schema = df.schema.map(s => { s.withComment(commentMap(s.name)) }) //根據添加了註釋的schema,新建DataFrame
val new_df = spark.createDataFrame(df.rdd, StructType(schema)).repartition(160) new_df.schema.foreach(s => println(s.name, s.metadata))
(ID,{"comment":"ID","name":"ID","scale":0}) (NAME,{"comment":"名字","name":"NAME","scale":0})

四、 測試寫到Hive表有沒有註釋

需將前面代碼中的spark改成支持hive,即加上enableHiveSupport()ui

spark.sql("use test") new_df.write.mode("overwrite").saveAsTable("ORA_TEST")

而後在hive裏看一下,是否有註釋url

能夠看到,成功的把註釋也保存到裏hive裏

五、附錄

附上在Eclipse運行的完整代碼

package com.dkl.leanring.spark.sql.Oracle import org.apache.spark.sql.SparkSession import org.apache.spark.sql.types._ object OracleSchemaDemo { def main(args: Array[String]): Unit = { val spark = SparkSession.builder().appName("OracleSchemaDemo").master("local").enableHiveSupport().getOrCreate() val df = spark.read .format("jdbc") .option("url", "jdbc:oracle:thin:@192.168.44.128:1521:orcl") .option("dbtable", "ORA_TEST") .option("user", "bigdata") .option("password", "bigdata") .option("driver", "oracle.jdbc.driver.OracleDriver") .load() df.schema.foreach(s => println(s.name, s.metadata)) val commentMap = Map("ID" -> "ID", "NAME" -> "名字") val schema = df.schema.map(s => { s.withComment(commentMap(s.name)) }) //根據添加了註釋的schema,新建DataFrame
    val new_df = spark.createDataFrame(df.rdd, StructType(schema)).repartition(160) new_df.schema.foreach(s => println(s.name, s.metadata)) spark.sql("use test") //保存到hive
    new_df.write.mode("overwrite").saveAsTable("ORA_TEST") spark.stop } }
相關文章
相關標籤/搜索