是否可以使用 SQLAlchemy 创建 Kudu table?

Is it possible to create a Kudu table using SQLAlchemy?

我在Impala中有一个数据库,我需要在其中使用Kudu tables。 我想在我的 Python 代码中使用 SQLAlchemy 来与数据库交互。 尽管 Impala 在 SQLALchemy 中不受支持,但我已经能够访问数据并在我现有的 Kudu 和非 Kudu table 中进行基本修改。

我已阅读 this 问题及其答案以及那里链接的 GitHub 页面,但它们是关于连接到 Impala 数据库的,我设法做到了。

(我也考虑过使用Kudu Python Client instead of SQLAlchemy, but that doesn't work because my code will run on Ubuntu 18.04 and it is not supported。)

我的问题具体是关于使用 SQLAlchemy 创建 Kudu tables 的。 当我使用纯 SQL 时,它看起来像这样:

CREATE TABLE my_table (
    id INT,
    message STRING,
    PRIMARY KEY (id)
  )
  STORED AS KUDU

有两件事表明这是 Kudu table:主键的存在,Impala 中不存在,当然还有最后一行。

在 SQLAlchemy 中将列标记为主键不是问题。但是有没有办法在 table 创建调用中包含 STORED AS KUDU

存在 Kudu 支持,但有问题(截至 2021 年 10 月 1 日)

首先:Impala SQLAlchemy 的方言 已实现,但在 impyla 包中。

Impyla 应该也支持 Kudu,请参阅 this issue 和与之相关的提交。但是,从版本 0.17a8 开始,包中省略了对主键约束的支持,这削弱了 Kudu 支持,因为 Kudu 表需要至少有一个主键。

因此,为了回答这个问题,可以使用 impyla 0.17a7 创建 Kudu 表,但不适用于任何更高版本 - 同样,截至 2021 年 10 月。我提交了关于此事的 this 问题。

功能使用

Kudu 支持是通过向 Table() 构造函数添加两个关键字参数实现的,即 impala_stored_asimpala_partition_by。当采用命令式方法并直接调用 Table() 时,用法很明显。然而,参数也可以很容易地通过声明方式传递,使用 __table_args__ (也适用于 mixin)。

有关命令式和声明式映射的解释,请参阅 SQLAlchemy 文档的 this page。 有关工作示例,请参阅下一节。

例子

命令式示例,取自here,但具有固定的参数名称和主键:

>>> import sqlalchemy
>>> engine = sqlalchemy.create_engine('impala://node-1.cluster')
>>> table = sqlalchemy.Table('sweet_new_table', sqlalchemy.MetaData(), sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True), impala_stored_as='KUDU')
>>> print(str(sqlalchemy.schema.CreateTable(table, bind=engine)))

CREATE TABLE sweet_new_table (
    id INTEGER,
    PRIMARY KEY (id)
)
STORED AS KUDU

我对声明性 (ORM) 示例的工作解决方案:

import sqlalchemy
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, String

Base = declarative_base()

class MyTable(Base):
    __tablename__ = "my_table_name"
    __table_args__ = {"impala_stored_as": "KUDU"}

    id = Column(String, primary_key=True)


if __name__ == "__main__":
    engine = sqlalchemy.create_engine("impala://node-1.cluster")
    Base.metadata.create_all(engine)