我想通过spark sql在AWS上创建带有location的托管表,但是如果我指定了位置,即使我没有指定这个关键字,它也会创建外部表。
CREATE TABLE IF NOT EXISTS database.tableOnS3(name string)
LOCATION 's3://mybucket/';
为什么他们在这里暗示外部关键字...
如果我在hive控制台中执行这个查询,它正在创建托管表,那么如何在spark中执行相同的操作呢?
发布于 2020-07-04 04:00:49
创建外部表后,将tableType更改为MANAGED。
导入org.apache.spark.sql.catalyst.catalog.CatalogTableType导入org.apache.spark.sql.catalyst.TableIdentifier
spark.sessionState.catalog.alterTable(spark.sessionState.catalog.getTableMetadata(identifier).copy(tableType标识符= TableIdentifier(yourTableName,Some(yourDatabaseName) val =CatalogTableType.MANAGED)
发布于 2019-06-07 00:55:49
参见docs配置单元基本上知道两种不同类型的表:
托管(内部)
外部
管理表:默认情况下,托管表存储在类似于/user/hive/warehouse/databasename.db/tablename/.的文件夹路径中的hive.metastore.warehouse.dir path属性下在创建表的过程中,默认位置可以由location特性覆盖。如果删除托管表或分区,则与该表或分区关联的数据和元数据也会被删除。如果未指定清除选项,数据将在定义的持续时间内移动到回收站文件夹。
当配置单元应该管理表的生命周期时,或者在生成临时表时,请使用托管表。
外部表:外部表描述外部文件上的元数据/模式。外部表文件可以由配置单元外部的进程访问和管理。外部表可以访问存储在Azure存储卷(ASV)或远程HDFS位置等源中的数据。如果外部表的结构或分区发生更改,则可以使用MSCK REPAIR table table_name语句刷新元数据信息。
当文件已经存在或位于远程位置时,请使用外部表,即使删除了表,也应保留文件。
结论:
由于您使用的是外部的s3位置,因此它的显示方式是这样的。
此外,您还想了解代码是如何工作的,请参阅:in this 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共存的本地位置(不是不同的vpc)。如果是,则设置
Spark.sql.warehouse.dir=hdfs:/...至s3位置
使用spark conf...您可能需要将访问密钥和密钥id凭据设置为spark配置对象以创建spark会话。
发布于 2020-08-21 18:59:44
查看Hive Confluence中的文档,强调我自己的文档。
本文档列出了两者之间的一些区别,但的根本区别在于,配置单元假定它拥有托管表的数据。这意味着数据、其属性和数据布局将且只能通过配置单元命令进行更改。数据仍然存在于正常的文件系统中,没有什么可以阻止您在不通知Hive的情况下更改它。如果你这样做了,那么它就违反了Hive的不变量和期望,你可能会看到未定义的行为。
因此,从本质上讲,假定EXTERNAL
的原因是因为您正在设置位置,因此Hive并不拥有/拥有数据的控制权。
执行此操作的方法是,首先创建一个设置了位置的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
表。
https://stackoverflow.com/questions/56481930
复制相似问题