如何在Databricks中挂载带分区的完整外部Delta表?
存储中有一个按日期分区的外部Delta表,但每个分区目录下都单独存在_delta_log。执行以下SQL尝试挂载完整表时:
CREATE TABLE if not exists profitek.products USING DELTA LOCATION 'dbfs:/mnt/curated-l1/profitek/products'
出现错误:
You are trying to create an external table
spark_catalog.general.products
fromdbfs:/mnt/curated-l1/general/productsusing Databricks Delta, but there is no transaction log present atdbfs:/mnt/curated-l1/general/products/_delta_log. Check the upstream job to make sure that it is writing using
format("delta") and that the path is the root of the table.
表的目录结构如下:
products │ ├── 2022-01-01 │ ├── _delta_log │ ├── part_01.parquet │ └── part_02.parquet ├── 2022-01-02 ├── _delta_log ├── part_01.parquet └── part_02.parquet
目前仅能挂载单个分区,例如:
CREATE TABLE if not exists profitek.products USING DELTA LOCATION 'dbfs:/mnt/curated-l1/profitek/products/2022-01-01'
当前的目录结构并非带分区的单个Delta表,而是多个独立的Delta表(每个日期分区对应一个单独的Delta表)。Delta表要求事务日志_delta_log必须位于表的根目录,用来统一管理全表的事务与分区信息,因此直接挂载根目录会报错。要挂载包含所有分区的完整Delta表,需先合并这些独立的Delta表为一个带分区的标准Delta表,步骤如下:
读取所有独立分区的Delta数据
如果数据本身包含日期字段(如date),直接读取所有路径:df = spark.read.format("delta").load("dbfs:/mnt/curated-l1/profitek/products/*")如果数据中没有日期字段,需从文件路径提取日期:
from pyspark.sql.functions import input_file_name, regexp_extract df = spark.read.format("delta").load("dbfs:/mnt/curated-l1/profitek/products/*") \ .withColumn("date", regexp_extract(input_file_name(), r"products/(\d{4}-\d{2}-\d{2})", 1))写入为标准分区Delta表
将读取到的数据写入根目录,指定按日期字段分区,这会在根目录生成统一的_delta_log:df.write.format("delta") \ .partitionBy("date") \ .mode("overwrite") \ .save("dbfs:/mnt/curated-l1/profitek/products")执行后,原分区目录下的
_delta_log会被替换为根目录的统一日志,数据仍按日期分区存储,但结构符合标准Delta表要求。挂载完整Delta表
再次执行最初的SQL语句,即可成功挂载包含所有分区的完整表:CREATE TABLE if not exists profitek.products USING DELTA LOCATION 'dbfs:/mnt/curated-l1/profitek/products'
内容的提问来源于stack exchange,提问作者Andrés Bustamante

