【问题标题】:sqlContext HiveDriver error on SQLException: Method not supportedSQLException 上的 sqlContext HiveDriver 错误:不支持方法
【发布时间】:2018-06-13 17:48:01
【问题描述】:

我一直在尝试使用 sqlContext.read.format("jdbc").options(driver="org.apache.hive.jdbc.HiveDriver") 将 Hive 表导入 Spark,但没有成功。我做了研究并阅读以下内容:

How to connect to remote hive server from spark

Spark 1.5.1 not working with hive jdbc 1.2.0

http://belablotski.blogspot.in/2016/01/access-hive-tables-from-spark-using.html

我使用了最新的 Hortonworks Sandbox 2.6,并在那里向社区提出了同样的问题:

https://community.hortonworks.com/questions/156828/pyspark-jdbc-py4jjavaerror-calling-o95load-javasql.html?childToView=156936#answer-156936

我想做的很简单,通过pyspark:

df = sqlContext.read.format("jdbc").options(driver="org.apache.hive.jdbc.HiveDriver", url="jdbc:hive2://localhost:10016/default", dbtable="sample_07",user="maria_dev", password="maria_dev").load()

这给了我这个错误:

17/12/30 19:55:14 INFO HiveConnection: Will try to open client transport with JDBC Uri: jdbc:hive2://localhost:10016/default
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/hdp/current/spark-client/python/pyspark/sql/readwriter.py", line 139, in load
    return self._df(self._jreader.load())
  File "/usr/hdp/current/spark-client/python/lib/py4j-0.9-src.zip/py4j/java_gateway.py", line 813, in __call__
  File "/usr/hdp/current/spark-client/python/pyspark/sql/utils.py", line 45, in deco
    return f(*a, **kw)
  File "/usr/hdp/current/spark-client/python/lib/py4j-0.9-src.zip/py4j/protocol.py", line 308, in get_return_value
py4j.protocol.Py4JJavaError: An error occurred while calling o119.load.
: java.sql.SQLException: Method not supported
at org.apache.hive.jdbc.HiveResultSetMetaData.isSigned(HiveResultSetMetaData.java:143)
at org.apache.spark.sql.execution.datasources.jdbc.JDBCRDD$.resolveTable(JDBCRDD.scala:136)
at org.apache.spark.sql.execution.datasources.jdbc.JDBCRelation.<init>(JDBCRelation.scala:91)
at org.apache.spark.sql.execution.datasources.jdbc.DefaultSource.createRelation(DefaultSource.scala:57)
at org.apache.spark.sql.execution.datasources.ResolvedDataSource$.apply(ResolvedDataSource.scala:158)
at org.apache.spark.sql.DataFrameReader.load(DataFrameReader.scala:119)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:231)
at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:381)
at py4j.Gateway.invoke(Gateway.java:259)
at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:133)
at py4j.commands.CallCommand.execute(CallCommand.java:79)
at py4j.GatewayConnection.run(GatewayConnection.java:209)
at java.lang.Thread.run(Thread.java:748)

使用直线,效果很好

beeline> !connect jdbc:hive2://localhost:10016/default maria_dev maria_dev
Connecting to jdbc:hive2://localhost:10016/default
Connected to: Spark SQL (version 2.1.1.2.6.1.0-129)
Driver: Hive JDBC (version 1.2.1000.2.6.1.0-129)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://localhost:10016/default> select * from sample_07 limit 2;
+----------+-------------------------+------------+---------+--+
|   code   |       description       | total_emp  | salary  |
+----------+-------------------------+------------+---------+--+
| 00-0000  | All Occupations         | 134354250  | 40690   |
| 11-0000  | Management occupations  | 6003930    | 96150   |
+----------+-------------------------+------------+---------+--+

我也可以这样做:

spark = SparkSession.Builder().appName("testapp").enableHiveSupport().‌​getOrCreate()
spark.sql("select * from default.sample_07").collect()

但这会直接读入 Hive 元数据。我想使用 JDBC 来 Spark Thrift Server 以获得细粒度的安全性。

我可以像这样做 PostgreSQL:

sqlContext.read.format("jdbc").options(driver="org.postgresql.Driver")

我还可以使用 Scala java.sql.{DriverManager, Connection, Statement, ResultSet} 创建 JDBC 连接作为客户端以访问 Spark。但这基本上将所有数据放入内存,然后手动重新创建 Dataframe。

所以问题是:有没有一种方法可以使用 Hive 表数据创建 Spark 数据帧,而无需将数据加载到 Scala 等 JDBC 客户端的内存中,而不像上面的示例那样使用 SparkSession.Builder()?我的用例是我需要处理细粒度的安全性。

【问题讨论】:

  • 提出三个不同的问题显然表明您的问题过于宽泛,请进行编辑以将其限制为一个问题,并为其他问题发布单独的问题。
  • 我更新了问题
  • 对于不使用 Hortonworks 的人 - 可以包括 Spark 版本吗?
  • beeline 只安装在本地。即使它安装在本地,你也可以通过提供它的 ip 来尝试。据我所知,直线可能不会通过 localhost 进行连接。请尝试一次,让我知道它是否有效。可能处于纱线客户端模式,它没有获取本地主机。
  • 这是 Spark 2.2。但坦率地说,这并不重要。如果最新最好的版本可以正常工作,我可以更改版本。我试过localhost和FQDN,都是一样的……

标签: apache-spark jdbc hive pyspark hortonworks-data-platform


【解决方案1】:

其实我调查过这个。 Hotornworks 和 cloudera 正在支持通过 Thrift 服务器从 Spark 连接到 hive。

所以你正在做一些不可能的事情。

https://www.cloudera.com/documentation/spark2/latest/topics/spark2_known_issues.html#ki_thrift_server.

链接说节俭已被禁用,但它专门用于从火花中蜂巢。除了 hive,我可以从 spark 连接到所有类型的数据库。

因此,您必须采用不同的授权方式。

由于 spark 对象直接连接到 hive,它们正在移除节俭支持。

从您之前的问题来看,它能够读取数据但读取错误的数据。 Spark 2.2 Thrift server error on dataframe NumberFormatException when query Hive table

代码

>>> df = sqlContext.read.format("jdbc").options(driver="org.apache.hive.jdbc.HiveDriver", url="jdbc:hive2://localhost:10016/default", dbtable="test4",user="hive", password="hive").option("fetchsize", "10").load()
>>> df.select("*").show()
+---+----+
| id|desc|
+---+----+
| id|desc|
| id|desc|
+---+----+

这里的问题出在蜂巢中

默认方言中引用标识符的默认方式是使用双引号。像 SELECT “dw_date” FROM table... 这样的 SQL 查询将由 Hive 解析以选择字符串文字,而不是名为 “dw_date” 的列。通过用反引号替换引号,问题似乎得到了解决。但是,在我的测试中,从 Hive 获取的列名都以 table.dw_date 之类的表名作为前缀。但是你不能像table.dw_date 那样直接用反引号括起来。或者,我们需要单独包装每个部分

代码

import org.apache.spark.sql.jdbc.JdbcDialect
    private case object HiveDialect extends JdbcDialect {
      override def canHandle(url : String): Boolean = url.startsWith("jdbc:hive2")
      override def quoteIdentifier(colName: String): String = {
        colName.split(‘.’).map(part => s”`$part`”).mkString(“.”)
      }
    }

请按照以下帖子实施解决方案。

https://medium.com/@viirya/custom-jdbc-dialect-for-hive-5dbb694cc2bd

https://medium.com/@huaxing/customize-spark-jdbc-data-source-to-work-with-your-dedicated-database-dialect-beec6519af27

注册方言

JdbcDialects.registerDialect(HiveDialect)

然后 hive jdbc 工作。

【讨论】:

  • Cloudera 确实如此,但我怀疑 Hortonworks docs.hortonworks.com/HDPDocuments/HDP2/HDP-2.6.3/… 的情况是否如此,除非您有来自公司内部的可靠来源。不管有什么让我烦恼的是,他们没有在文档中的任何地方明确说明 Spark to Thrift JDBC 不受支持。如果他们真的这么说,我会很高兴并继续前进...... :)
  • 嗨,当我运行上面的代码时,我得到“错误:未找到:键入 JdbcDialect” 这个错误在 spark-shell 中你能帮我解决这个问题吗?
  • @GowthamSB 包括导入
【解决方案2】:

我不确定我是否正确理解了您的问题,但据我了解,您需要将配置单元表放入数据框中,因为在您的示例中您不需要 JDBC 连接链接他们试图连接到不同的数据库 (RDBMS),而不是 Hive。

请参阅下面的方法,使用 hive 上下文可以将表放入数据框中。

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.sql.{DataFrame, SQLContext}

def main(args: Array[String]): Unit = {

val sparkConf = new SparkConf().setAppName("APPName")
    val sc = new SparkContext(sparkConf)
    val hiveContext = new org.apache.spark.sql.hive.HiveContext(sc)
    val sqlContext = new SQLContext(sc)

val hive_df = hiveContext.sql("select * from schema.table").first()

//other way
// val hive_df= hiveContext.table ("SchemaName.TableName")

//Below will print the first line
df.first()
//count on dataframe
df.count()

}

如果您真的想使用 JDBC 连接,我有以下用于 Oracle 数据库的示例,这可能会对您有所帮助。

val oracle_data = sqlContext.load("jdbc", Map("url" -> "jdbc:oracle:thin:username/password//hostname:2134/databaseName", "dbtable" -> "Your query tmp", "driver" -> "oracle.jdbc.driver.OracleDriver"));

【讨论】:

  • 我知道你上面的例子。它基本上是使用 Spark 直接从 Hive Metastore 获取数据。我的要求是使用带有用户/密码的 JDBC 到 Spark Thrift 服务器,因为系统可能具有 LDAP 或 Active Directory 身份验证以实现细粒度安全性(行/列过滤器和屏蔽)。直接进入 Metastore 可以,但这是一个用户访问一个集群。
  • 我有多个用户,所以我需要通过凭据。我的另一个想法是使用 Kerberos 来保护 Hive Metastore,但这并没有给我提供细粒度的安全性(它要么拒绝要么允许访问表级别,而不是行/列级别)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-12
  • 1970-01-01
  • 1970-01-01
  • 2014-12-21
  • 2021-03-12
  • 2021-06-17
  • 2020-05-15
相关资源
最近更新 更多