问题
管理Spark表架构的最佳方式是什么?你认为方案2有什么缺点吗?你能提出更好的替代方案吗
我看到的解决方案
选项1:为代码和元存储保留单独的定义
这种方法的缺点是您必须不断地保持它们的同步(容易出错(。另一个缺点是,如果表有500列,就会变得很麻烦。
create_some_table.sql[第一个定义]
-- Databricks syntax (internal metastore)
CREATE TABLE IF NOT EXISTS some_table (
Id int,
Value string,
...
Year int
)
USING PARQUET
PARTITION BY (Year)
OPTIONS (
PATH 'abfss://...'
)
some_job.py[第二个定义]
def run():
df = spark.read.table('input_table') # 500 columns
df = transorm(df)
# this logic should be in `transform`, but anycase it should be
df = df.select(
'Id', 'Year', F.col('Value').cast(StringType()).alias('Value') # actually another schema definition: you have to enumerate all output columns
)
df.write.saveAsTable('some_table')
testrongome_job.py[第三定义]
def test_some_job(spark):
output_schema = ... # another definition
expected = spark.createDataFrame([...], output_schema)
选项2:在代码中只保留一个定义(StructType(
动态生成模式是可能的。这种方法的好处是简单性和在一个地方定义模式你看到缺点了吗
def run(input: Table, output: Table):
df = spark.read.table(input.name)
df = transform(df)
save(df, output)
def save(df: DataFrame, table: Table):
df
.select(table.schema.fieldNames())
.write
.partitionBy(table.partition_by)
.option('path', table.path)
.saveAsTable(table.name)
# In case table doesn't exists, Databricks will automatically generate table definition
class Table(NamedTuple):
name: str
path: str
partition_by: List[str]
schema: StructType
让我先提出几点,然后提出建议。
- 数据的寿命比代码长得多
- 上面描述的代码是创建&写入数据时,还有读取和使用需要考虑的数据的代码
- 还有第三个选项,将数据的定义(模式(与数据一起存储。通常被称为"自我描述格式">
- 数据的结构可能会随着时间的推移而变化
- 此问题标记有
databricks
和aws-glue
- Parquet是在一个文件一个文件的基础上自我描述的
- DeltaLake表使用镶木地板数据文件,但还将模式嵌入到事务日志中,从而对整个表和模式进行版本控制
- 数据需要由广泛的工具生态系统使用,因此数据需要是可发现的,模式不应锁定在一个计算引擎中
推荐:
- 以开放格式存储带有数据的架构
- 使用DeltaLake格式(结合Parquet和事务日志(
- 将
USING PARQUET
更改为USING DELTA
- 将您的元存储指向AWS Glue Catalog,Glue Catalog将存储表名和位置
- 使用者将从DeltaLake表事务日志中解析架构
- 模式可以随着编写器代码的发展而发展
结果:
- 您的编写器创建模式,并可以选择性地演化模式
- 所有使用者都会在DeltaLake中找到架构(与表版本配对((具体为_Delta_log目录(
在我的公司,我们有一个非常小的团队,所以我们构建了一个基于C#模板的生成器,它从SQL Server数据库中读取信息并生成我们所有的笔记本。为我们的整个系统生成DDL模式和处理代码所需的所有信息都在该数据库中。我们现在唯一手动编码的是Dims和Facts的加载过程的一部分。所有的锅炉板代码都被抽象掉了。对于新的表,我们进入元数据库,输入新的表和列信息并运行生成器。这会导致您在生成的代码中所说的重复,但现在我们只是维护元数据库信息,而不必找到所有需要更新的地方。如果你已经建立了一个系统,这种方法将很难适应,而且说服高层管理层可能是一个挑战,因为前面还有很多开发工作。然而,如果你从零开始,就如何使其通用化,你将获得无与伦比的解决问题和稳定平台的能力。我在野外见过的唯一一款能够在大数据领域做类似事情的产品是Wherescape,如果我没记错的话,它每年每个座位3.5万美元,非常昂贵。所以,如果你的口袋很深,我强烈建议你去看看。[https://www.wherescape.com/][1]可能还有其他人,但这是我所知道的唯一一个。
举几个例子说明这种方法是如何带来好处的。
-
我们自己和另一个有两名开发人员,我们能够在4个月内将130个staging和40个Dim and Facts从U-SQL Datalake Analytics完全切换到Databricks。在我们前进的过程中切换出每一个生成的过程。
-
比方说,我们在加载暂存表时发现了处理问题,我们更新了流程模板,重新生成了笔记本并重新部署。现在更新了所有130张表的流程,这是日常工作的一半,否则可能需要数周的时间来修复和测试。