1.通过spark提供的jdbc方式连接代码如下
val spark = SparkSession.builder().master("local").getOrCreate()
val rdd = spark.read.format("jdbc")
.format("jdbc")
.option("driver", "org.apache.hive.jdbc.HiveDriver")
.option("url", "jdbc:hive2://hiveserver2:10000")
.option("user", "hive")
.option("dbtable", "dep.tablename1")
.option("fetchsize", "100")
.load()
rdd.show()
2.执行之后发现读取的数据全为表名数据
3.分析和调试
通过一步步的调试发现代码最终会到JDBCRDD,所以在compute方法打断点,一步步调试发现到下面代码的时候出现问题
通过查看sqlText的值发现sqlText的值为 select "columns1" from dep.tablename1 的值,很显然得到的结果肯定是columns1的值。为什么会出现上面的问题我们跟踪colmnList的值发现代码在下面出现
private val columnList: String = {
val sb = new StringBuilder()
columns.foreach(x => sb.append(",").append(x))
if (sb.isEmpty) "1" else sb.substring(1)
}
继续跟踪columns的值:
val quotedColumns = requiredColumns.map(colName => dialect.quoteIdentifier(colName))
new JDBCRDD(
sc,
JdbcUtils.createConnectionFactory(options),
pruneSchema(schema, requiredColumns),
quotedColumns,
filters,
parts,
url,
options)
问题就显而易见了,主要的问题原因就在JdbcDialect的quoteIdentifier方法。
解决:
实现hive的dialect
package org.apache.spark
import org.apache.spark.sql.jdbc.JdbcDialect
class HiveDialet extends JdbcDialect{
override def canHandle(url: String): Boolean = {
url.startsWith("jdbc:hive2")
}
override def quoteIdentifier(colName: String): String = {
if(colName.contains(".")){
val colName1 = colName.substring(colName.indexOf(".")+1)
return s"`$colName1`"
}
s"`$colName`"
}
}
在代码中注册hiveDialect就可以了
JdbcDialects.registerDialect(new HiveDialet)
后记:通过这种方式得到的dataframe其实还有一些问题,比如表的字段为[table].[column],在后续的操作有很大的影响,如果要解决这个问题就必须要了解
set hive.resultset.use.unique.column.names=false 这个参数,所以只要我们将该参数设置在hive jdbc的url就可以了,用法如下:
jdbc:hive2://ip:10000?hive.resultset.use.unique.column.names=false