1
votes

Comment créer une table de ruche gérée avec un emplacement spécifié via Spark SQL?

Je souhaite créer une table gérée avec un emplacement sur AWS S3 via spark sql, mais si je spécifie l'emplacement, cela crée une table EXTERNAL même si je n'ai pas spécifié ce mot clé.

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

Pourquoi impliquent-ils un mot-clé EXTERNAL ici ...

Si j'exécute cette requête dans la console Hive, cela crée une table gérée, alors comment faire la même chose dans spark?


1 commentaires

mis à jour ma réponse ...


3 Réponses :


1
votes

Voir documents Hive connaît fondamentalement deux types de tables différents:

Géré (interne)
Externe


Tables gérées : une table gérée est stockée sous le propriété de chemin hive.metastore.warehouse.dir, par défaut dans un dossier chemin similaire à /user/hive/warehouse/databasename.db/tablename/. Le l'emplacement par défaut peut être remplacé par la propriété location pendant création de table. Si une table ou une partition gérée est supprimée, les données et les métadonnées associées à cette table ou partition sont supprimées. Si l'option PURGE n'est pas spécifiée, les données sont déplacées vers un dossier corbeille pour une durée définie.

Utilisez des tables gérées lorsque Hive doit gérer le cycle de vie de la table, ou lors de la génération de tables temporaires.

Tables externes : une table externe décrit les métadonnées / schémas sur fichiers externes. Les fichiers de table externes sont accessibles et gérés par processus en dehors de Hive. Les tables externes peuvent accéder aux données stockées dans sources telles que Azure Storage Volumes (ASV) ou emplacements HDFS distants. Si la structure ou le partitionnement d'une table externe est modifié, un L'instruction nom_table MSCK REPAIR TABLE peut être utilisée pour actualiser les métadonnées informations.

Utilisez des tables externes lorsque les fichiers sont déjà présents ou à distance emplacements, et les fichiers doivent rester même si la table est supprimée.

Conclusion:


puisque vous utilisez l'emplacement s3 qui est externe à son affichage comme ça.

En outre, vous voulez comprendre comment le code fonctionne voir CreateTableLikeCommand em > : dans ce val tblType = if (location.isEmpty) CatalogTableType.MANAGED else CatalogTableType.EXTERNAL est l'endroit où il décide dynamiquement ...

/**
 * 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]
  }
}

Mise à jour: Si j'exécute cette requête dans la console hive, cela crée une table gérée, alors comment faire de même dans spark?

j'espère que vous utilisez le même emplacement local (pas un vpc différent) où hive et l'étincelle coexiste. si c'est le cas, définissez

spark.sql.warehouse.dir = hdfs: /// ... sur l'emplacement s3

en utilisant spark conf .... vous devrez peut-être définir l'accès les informations d'identification de la clé et de l'ID secret pour déclencher l'objet de configuration pour créer une session Spark.



4 commentaires

Si j'utilise la console hive et que je fais de même, c'est créer une table gérée, c'est exactement ce que je veux faire dans spark. Ma question est donc de savoir comment faire cela?


ok où house dir est l'emplacement où il décide ... quand vous exécutez avec la ligne de commande c'est local où comme quand vous utilisez spark alors ce n'est pas local (externe). c'est la raison. essayez de définir l'emplacement de votre répertoire d'entrepôt sur l'emplacement s3 et voyez


merci pour l'aide, mais je sais de cette façon et malheureusement je ne peux pas le faire dans ma situation, car c'est un cluster de production et il est hébergé sur hdfs. Les travaux Spark doivent également lire à partir de hdfs, je ne peux donc pas simplement le définir dans les paramètres du travail


d'accord. si vous obtenez une solution élégante, veuillez la poster ici. Vous voulez voir quelles sont les alternatives pour cela.



3
votes

changez le tableType en MANAGED une fois la table externe créée.

importer org.apache.spark.sql.catalyst.TableIdentifier import org.apache.spark.sql.catalyst.catalog.CatalogTableType

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


1 commentaires

Votre réponse ne contient pas la déclaration nécessaire pour accomplir cela, ne répond pas au Q sur le mot-clé EXTERNAL et ne montre pas non plus comment accomplir cela dans Spark. Pensez à mettre à jour / améliorer votre réponse, vous pouvez le faire!



0
votes

Consulter la documentation de la Confluence a>, je souligne le mien.

Ce document répertorie certaines des différences entre les deux, mais la différence fondamentale est que Hive suppose qu'il possède les données des tables gérées . Cela signifie que les données, leurs propriétés et la disposition des données seront et ne peuvent être modifiées que via la commande Hive. Les données vivent toujours dans un système de fichiers normal et rien ne vous empêche de les modifier sans en parler à Hive. Si vous le faites, cela viole les invariants et les attentes de Hive et vous pourriez voir un comportement indéfini.

Donc, essentiellement, la raison pour laquelle EXTERNAL est supposé est que vous définissez l'emplacement et par conséquent, Hive ne possède / n'a pas le contrôle des données.

La façon de faire cela, c'est-à-dire de créer une table MANAGED avec un emplacement personnalisé, est de créer d'abord une table EXTERNAL avec l'emplacement défini. Cela ne peut pas être évité pour les raisons mentionnées ci-dessus, puis en modifiant les métadonnées de la table en MANAGED . Notez que, comme l'indique la documentation, cela peut conduire à un comportement indéfini.

// 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)

Et maintenant vous avez une table MANAGED avec l'emplacement défini manuellement.


0 commentaires