【问题标题】:How to create managed hive table with specified location through Spark SQL?如何通过 Spark SQL 创建具有指定位置的托管配置单元表?
【发布时间】:2019-10-22 05:30:51
【问题描述】:

我想通过 spark sql 在 AWS S3 上创建带有位置的托管表,但是如果我指定了位置,即使我没有指定此关键字,它也会创建 EXTERNAL 表。

CREATE TABLE IF NOT EXISTS database.tableOnS3(name string)
LOCATION 's3://mybucket/';

为什么他们在这里暗示 EXTERNAL 关键字...

如果我在 hive 控制台中执行此查询,它正在创建托管表,那么如何在 spark 中执行相同操作?

【问题讨论】:

  • 更新了我的答案...

标签: apache-spark amazon-s3 hive apache-spark-sql


【解决方案1】:

创建外部表后,将 tableType 更改为 MANAGED。

导入 org.apache.spark.sql.catalyst.TableIdentifier 导入 org.apache.spark.sql.catalyst.catalog.CatalogTableType

val identifier = TableIdentifier(yourTableName, Some(yourDatabaseName) spark.sessionState.catalog.alterTable(spark.sessionState.catalog.getTableMetadata(identifier).copy(tableType = CatalogTableType.MANAGED))

【讨论】:

  • 您的答案缺少实际完成此操作所需的语句,没有回答关于 EXTERNAL 关键字的 Q,也没有显示如何在 spark 中完成此操作。考虑更新/增强您的答案,您可以做到!
【解决方案2】:

docs Hive 从根本上知道两种不同类型的表:

托管(内部)
外部


托管表:托管表存储在 hive.metastore.warehouse.dir 路径属性,默认在文件夹中 路径类似于 /user/hive/warehouse/databasename.db/tablename/。这 默认位置可以被 location 属性覆盖 表创建。如果删除了托管表或分区,则数据 并且与该表或分区关联的元数据将被删除。如果 未指定 PURGE 选项,数据被移动到垃圾文件夹 在定义的持续时间内。

当 Hive 应该管理表的生命周期时使用托管表, 或在生成临时表时。

外部表:外部表描述了元数据/架构 外部文件。外部表文件可以通过以下方式访问和管理 Hive 之外的进程。外部表可以访问存储在 Azure 存储卷 (ASV) 或远程 HDFS 位置等来源。 如果外部表的结构或分区发生更改,则 MSCK REPAIR TABLE table_name 语句可用于刷新元数据 信息。

当文件已经存在或远程时使用外部表 位置,即使删除表,文件也应保留。

结论:


因为您使用的是外部的 s3 位置,所以它的显示方式是这样的。

如果您想进一步了解代码的工作原理,请参阅 CreateTableLikeCommand :在此 val tblType = if (location.isEmpty) CatalogTableType.MANAGED else CatalogTableType.EXTERNAL 是它动态决定的地方...

/**
 * A command to create a table with the same definition of the given existing table.
 * In the target table definition, the table comment is always empty but the column comments
 * are identical to the ones defined in the source table.
 *
 * The CatalogTable attributes copied from the source table are storage(inputFormat, outputFormat,
 * serde, compressed, properties), schema, provider, partitionColumnNames, bucketSpec.
 *
 * The syntax of using this command in SQL is:
 * {{{
 *   CREATE TABLE [IF NOT EXISTS] [db_name.]table_name
 *   LIKE [other_db_name.]existing_table_name [locationSpec]
 * }}}
 */
case class CreateTableLikeCommand(
    targetTable: TableIdentifier,
    sourceTable: TableIdentifier,
    location: Option[String],
    ifNotExists: Boolean) extends RunnableCommand {

  override def run(sparkSession: SparkSession): Seq[Row] = {
    val catalog = sparkSession.sessionState.catalog
    val sourceTableDesc = catalog.getTempViewOrPermanentTableMetadata(sourceTable)

    val newProvider = if (sourceTableDesc.tableType == CatalogTableType.VIEW) {
      Some(sparkSession.sessionState.conf.defaultDataSourceName)
    } else {
      sourceTableDesc.provider
    }

    // If the location is specified, we create an external table internally.
    // Otherwise create a managed table.
    val tblType = if (location.isEmpty) CatalogTableType.MANAGED else CatalogTableType.EXTERNAL

    val newTableDesc =
      CatalogTable(
        identifier = targetTable,
        tableType = tblType,
        storage = sourceTableDesc.storage.copy(
          locationUri = location.map(CatalogUtils.stringToURI(_))),
        schema = sourceTableDesc.schema,
        provider = newProvider,
        partitionColumnNames = sourceTableDesc.partitionColumnNames,
        bucketSpec = sourceTableDesc.bucketSpec)

    catalog.createTable(newTableDesc, ifNotExists)
    Seq.empty[Row]
  }
}

更新: 如果我在 hive 控制台中执行此查询,它会创建托管表,那么如何在 spark 中执行相同的操作?

希望您使用的是 hive 和 spark 共存的相同本地位置(不是不同的 vpc)。 如果是,那么设置

spark.sql.warehouse.dir=hdfs:///... 到 s3 位置

使用 spark conf.... 您可能需要设置访问密钥和秘密 id 凭据以触发配置对象以创建 spark 会话。


【讨论】:

  • 如果我使用 hive 控制台并做同样的事情,它会创建托管表,这正是我想要在 spark 中做的事情。所以我的问题是如何做到这一点?
  • ok 其中 house dir 是它决定的位置...当您使用命令行运行时,它是本地的,而当您使用 spark 时,它不是本地的(外部)。这就是原因。尝试将仓库目录的位置设置为 s3 位置并查看
  • 感谢您的帮助,但我知道这种方式,不幸的是,在我的情况下我不能这样做,因为它是一个 prod 集群并且它托管在 hdfs 上。 Spark作业也需要从hdfs读取,所以不能只在作业参数中设置
  • 好的。如果您得到优雅的解决方案,请在此处发布。想看看有什么替代方案。
【解决方案3】:

查看 Hive Confluence 中的文档,强调我自己的。

本文档列出了两者之间的一些区别,但根本区别在于 Hive 假定它拥有托管表的数据。这意味着数据、其属性和数据布局将并且只能通过 Hive 命令进行更改。数据仍然存在于正常的文件系统中,没有什么能阻止您在不告诉 Hive 的情况下更改它。如果这样做违反了 Hive 的不变量和期望,您可能会看到未定义的行为。

所以本质上,假设 EXTERNAL 的原因是因为您正在设置位置,因此 Hive 不拥有/控制数据。

执行此操作的方法,即创建具有自定义位置的MANAGED 表,是首先创建具有位置集的EXTERNAL 表。由于上面提到的原因,这是无法避免的,然后将表元数据修改为MANAGED。请注意,正如文档所述,这可能会导致未定义的行为。

// Following your example Hive statement creates an EXTERNAL table
CREATE TABLE IF NOT EXISTS database.tableOnS3(name string) LOCATION 's3://mybucket/';

// Change table type from within Hive, changing from EXTERNAL to MANAGED
ALTER TABLE database.tableOnS3 SET TBLPROPERTIES('EXTERNAL'='FALSE');

// Or from within spark
import org.apache.spark.sql.catalyst.TableIdentifier
import org.apache.spark.sql.catalyst.catalog.CatalogTable
import org.apache.spark.sql.catalyst.catalog.CatalogTableType

// Get External Catalog
val catalog = spark.sharedState.externalCatalog

// Identify the table in question
val identifier = TableIdentifier("tableOnS3", Some("database"))

// Get its current metadata
val tableMetadata = catalog.getTableMetadata(identifier)

// Clone the metadata while changing the tableType to MANAGED
val alteredMetadata = tableMetadata.copy(tableType = CatalogTableType.MANAGED)

// Alter the table using the new metadata
catalog.alterTable(alteredMetadata)

现在您有了一个手动设置位置的MANAGED 表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-14
    • 2019-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多