如何使用 Spark 对象获取 Hive 表的位置值?

Posted

技术标签:

【中文标题】如何使用 Spark 对象获取 Hive 表的位置值?【英文标题】:How to get the value of the location for a Hive table using a Spark object? 【发布时间】:2019-01-06 10:27:21 【问题描述】:

我有兴趣在给定 Spark 对象 (SparkSession) 的情况下检索 Hive 表的 location 值。获取此值的一种方法是通过以下 SQL 查询解析位置的输出:

describe formatted <table name>

我想知道是否有另一种方法来获取 location 值而无需解析输出。如果上述命令的输出在 Hive 版本之间发生变化,API 会很棒。如果需要外部依赖,它会是什么?是否有一些可以获取位置值的示例 spark 代码?

【问题讨论】:

【参考方案1】:

您也可以在desc formatted table 上使用.toDF 方法,然后从数据帧中过滤。

DataframeAPI:

scala> :paste
spark.sql("desc formatted data_db.part_table")
.toDF //convert to dataframe will have 3 columns col_name,data_type,comment
.filter('col_name === "Location") //filter on colname
.collect()(0)(1)
.toString

Result:

String = hdfs://nn:8020/location/part_table

(or)

RDD Api:

scala> :paste
spark.sql("desc formatted data_db.part_table")
.collect()
.filter(r => r(0).equals("Location")) //filter on r(0) value
.map(r => r(1)) //get only the location
.mkString //convert as string
.split("8020")(1) //change the split based on your namenode port..etc

Result:

String = /location/part_table

【讨论】:

感谢您的粘贴模式:)【参考方案2】:

第一种方法

您可以将input_file_name 与数据框一起使用。

它将为您提供零件文件的绝对文件路径。

spark.read.table("zen.intent_master").select(input_file_name).take(1)

然后从中提取表路径。

第二种方法

你可以说它更像是 hack。

package org.apache.spark.sql.hive

import java.net.URI

import org.apache.spark.sql.catalyst.catalog.InMemoryCatalog, SessionCatalog
import org.apache.spark.sql.catalyst.parser.ParserInterface
import org.apache.spark.sql.internal.SessionState, SharedState
import org.apache.spark.sql.SparkSession

class TableDetail 
  def getTableLocation(table: String, spark: SparkSession): URI = 
    val sessionState: SessionState = spark.sessionState
    val sharedState: SharedState = spark.sharedState
    val catalog: SessionCatalog = sessionState.catalog
    val sqlParser: ParserInterface = sessionState.sqlParser
    val client = sharedState.externalCatalog match 
      case catalog: HiveExternalCatalog => catalog.client
      case _: InMemoryCatalog => throw new IllegalArgumentException("In Memory catalog doesn't " +
        "support hive client API")
    

    val idtfr = sqlParser.parseTableIdentifier(table)

    require(catalog.tableExists(idtfr), new IllegalArgumentException(idtfr + " done not exists"))
    val rawTable = client.getTable(idtfr.database.getOrElse("default"), idtfr.table)
    rawTable.location
  

【讨论】:

hive 表没有文件怎么办?如何获取它的位置值? @codeshark 我已经用第二种方法更新了答案,希望这对你有用。 什么是“input_file_name”? 这是一个火花函数。您可以使用import org.apache.spark.sql.functions._ 您可以查找文档以获取更多详细信息。 spark.apache.org/docs/2.0.0/api/scala/…【参考方案3】:

正确答案如下:

import org.apache.spark.sql.catalyst.TableIdentifier

lazy val tblMetadata = spark.sessionState.catalog.getTableMetadata(new TableIdentifier(tableName,Some(schema)))

【讨论】:

@GuilhermedeLazari 这里是spark._jsparkSession.sessionState().catalog().getTableMetadata(spark.sparkContext._jvm.org.apache.spark.sql.catalyst.TableIdentifier('table', spark.sparkContext._jvm.scala.Some('database'))).storage().locationUri().get()【参考方案4】:

这是在 PySpark 中的操作方法:

 (spark.sql("desc formatted mydb.myschema")
       .filter("col_name=='Location'")
       .collect()[0].data_type)   

【讨论】:

【参考方案5】:

在你的 scala 项目中使用它作为可重用函数

  def getHiveTablePath(tableName: String, spark: SparkSession):String =
    
       import org.apache.spark.sql.functions._
      val sql: String = String.format("desc formatted %s", tableName)
      val result: DataFrame = spark.sql(sql).filter(col("col_name") === "Location")
      result.show(false) // just for debug purpose
      val info: String = result.collect().mkString(",")
      val path: String = info.split(',')(1)
      path
    

调用者是

    println(getHiveTablePath("src", spark)) // you can prefix schema if you have

结果(我在本地so文件中执行:/如果它的hdfs hdfs://会来):

+--------+------------------------------------+-------+
|col_name|data_type                           |comment|
+--------+--------------------------------------------+
|Location|file:/Users/hive/spark-warehouse/src|       |
+--------+------------------------------------+-------+

file:/Users/hive/spark-warehouse/src

【讨论】:

【参考方案6】:

使用外部目录

scala> spark
res15: org.apache.spark.sql.SparkSession = org.apache.spark.sql.SparkSession@4eba6e1f

scala> val metastore = spark.sharedState.externalCatalog
metastore: org.apache.spark.sql.catalyst.catalog.ExternalCatalog = org.apache.spark.sql.hive.HiveExternalCatalog@24b05292

scala> val location = metastore.getTable("meta_data", "mock").location
location: java.net.URI = hdfs://10.1.5.9:4007/usr/hive/warehouse/meta_data.db/mock

【讨论】:

以上是关于如何使用 Spark 对象获取 Hive 表的位置值?的主要内容,如果未能解决你的问题,请参考以下文章

Spark SQL 未返回 HDP 上 HIVE 事务表的记录

使用 Spark Scala 将 Sql Server 数据类型转换为 Hive 数据类型

使用 Spark 查询 hive 表

黑猴子的家:Spark on hive 与 hive on spark 的区别

如何将数据写入 Hive 表?

Spark 广播join 与 Hive map join