如何通过sparksql创建具有指定位置的托管配置单元表?

13z8s7eq  于 2021-06-24  发布在  Hive
关注(0)|答案(3)|浏览(756)

我想通过sparksql在awss3上创建位置为的托管表,但是如果我指定了位置,即使我没有指定这个关键字,它也会创建外部表。

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

为什么他们在这里暗示外部关键字。。。
如果我在配置单元控制台中执行这个查询,它将创建托管表,那么如何在spark中执行同样的操作呢?

cnwbcb6i

cnwbcb6i1#

see docs hive基本上知道两种不同类型的表:
管理(内部)
外部的
托管表:托管表存储在hive.metastore.warehouse.dir path属性下,默认情况下存储在类似于/user/hive/warehouse/databasename.db/tablename/的文件夹路径中。在创建表期间,location属性可以覆盖默认位置。如果删除托管表或分区,则会删除与该表或分区关联的数据和元数据。如果未指定清除选项,则数据将在定义的持续时间内移动到垃圾箱文件夹。
当配置单元应该管理表的生命周期或生成临时表时,请使用托管表。
外部表:外部表描述外部文件上的元数据/模式。外部表文件可以由配置单元外部的进程访问和管理。外部表可以访问存储在诸如azure存储卷(asv)或远程hdfs位置等源中的数据。如果外部表的结构或分区发生更改,则可以使用msck repair table \u 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]
  }
}

更新:如果我在配置单元控制台中执行此查询,它将创建托管表,那么如何在spark中执行相同的操作?
希望您使用的是相同的本地位置(不是不同的专有网络),其中Hive和Spark共存。如果是,则设置
spark.sql.warehouse.dir=hdfs://。。。至s3位置
使用spark conf。。。。您可能需要将访问密钥和机密id凭据设置为spark配置对象以创建spark会话。

7gcisfzg

7gcisfzg2#

看看Hive汇合处的文档,我自己的重点。
本文档列出了两者之间的一些区别,但最根本的区别是hive假设它拥有托管表的数据。这意味着数据、其属性和数据布局将更改,并且只能通过hive命令更改。数据仍然存在于一个正常的文件系统中,没有什么可以阻止您在不告诉hive的情况下更改它。如果你这样做,尽管它违反了不变量和Hive的期望,你可能会看到未定义的行为。
所以本质上,原因 EXTERNAL 假设是因为您正在设置位置,因此,配置单元不拥有/控制数据。
方法,即创建 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 手动设置位置的表。

ozxc1zmp

ozxc1zmp3#

创建外部表后,将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))

相关问题