The Linux Foundation Projects
Delta Lake

开源自托管 Delta Sharing 服务器

作者:Shingo Okawa

我叫 Shingo,是 Kotosiro Sharing 的创建者。我很高兴地宣布发布 Kotosiro Sharing,这是一个极简的 Rust 实现的 Delta Sharing 服务器,旨在帮助工程师轻松托管自己的 Delta Sharing 服务。在本文中,我将提供如何使用自托管的 Kotosiro Sharing 服务器与技术背景各异的同事(从数据工程师到商业智能分析师)共享数据的说明。这些说明非常简单明了,您可以轻松地与具有不同技术水平的同事共享数据。该实现目前处于测试阶段,因此尚未提供图形用户界面。但是,此功能将在不久的将来添加。下图描绘了系统工作流程。让我们来看看当您想与同事共享宝贵数据时 Kotosiro Sharing 是如何工作的。

Delta 表结构

您的 Delta 表在 AWS S3 上存储了美国多个市场的鳄梨价格和销售量的历史数据。您的同事来到您的办公桌前,询问他们是否可以使用这些数据进行进一步的数据分析。该表的结构如下:

avocado-table
├── _delta_log
│   ├── 00000000000000000000.json
│   ├── 00000000000000000001.json
│   ├── 00000000000000000002.json
│   └── 00000000000000000003.json
├── part-00000-04d10a18-acde-4d66-bb3b-39f5d0feb689-c000.snappy.parquet
├── part-00000-c5135c42-2c15-4da5-8cd6-f0fc527dff9c-c000.snappy.parquet
├── part-00000-c6c1e092-bef3-41a0-8a05-826a33ecff6f-c000.snappy.parquet
└── part-00000-d7afaec2-4373-4865-ab48-e9f60495b41e-c000.snappy.parquet

每个 parquet 文件都按顺序附加。因此,该表有四个不同的版本

通过 Kotosiro Sharing API 共享您的 Delta 表

登录 Kotosiro Sharing Server 并获取管理员访问令牌

现在让我们开始有趣的部分。作为数据所有者和 Kotosiro Sharing 服务器的管理员,您需要登录系统并获取管理员访问令牌。此令牌将使您能够创建共享。以下是获取令牌的方法:

 $ curl -s -X POST https://:8080/admin/login \
        -H "Content-Type: application/json" \
        -d '{"account": "kotosiro", "password": "password"}' \
        | jq '.'
{
  "profile": {
    "shareCredentialsVersion": 1,
    "endpoint": "http://127.0.0.1:8080",
    "bearerToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoia290b3Npcm8iLCJlbWFpbCI6ImtvdG9zaXJvQGVtYWlsLmNvbSIsIm5hbWVzcGFjZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNjgxOTM3NzMyfQ.rVjA6S7EWq7CakpB0IHik0mvxl58ynZNxNM3a3RJibY",
    "expirationTime": "2023-04-19 20:55:32 UTC"
  }
}

注册新共享

接下来,您需要注册一个新的共享,这只是一个用于与接收者共享的逻辑分组。例如,您可以将共享命名为 share1。请注意,此共享目前为空,这意味着您尚未向其中添加任何数据。以下是创建共享的方法:

 $ curl -s -X POST "https://:8080/admin/shares" \
        -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoia290b3Npcm8iLCJlbWFpbCI6ImtvdG9zaXJvQGVtYWlsLmNvbSIsIm5hbWVzcGFjZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNjgxOTM3NzMyfQ.rVjA6S7EWq7CakpB0IHik0mvxl58ynZNxNM3a3RJibY" \
        -H "Content-Type: application/json" \
        -d '{ "name": "share1" }' \
        | jq '.'
{
  "share": {
    "id": "78f84b5e-29e7-4adf-8df5-c40487a8da43",
    "name": "share1"
  }
}

注册新表

到目前为止一切顺利。现在是时候通过 API 将 AWS S3 上的 Delta 表注册到您的 Kotosiro Sharing 服务了。它与其他操作一样相当简单。只需发布指定 Delta 表的 S3 存储桶对象路径以及表名称的 JSON 数据即可。例如,您可以将表命名为 table1。以下是注册的方法:

 $ curl -s -X POST "https://:8080/admin/tables" \
        -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoia290b3Npcm8iLCJlbWFpbCI6ImtvdG9zaXJvQGVtYWlsLmNvbSIsIm5hbWVzcGFjZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNjgxOTM3NzMyfQ.rVjA6S7EWq7CakpB0IHik0mvxl58ynZNxNM3a3RJibY" \
        -H "Content-Type: application/json" \
        -d '{ "name": "table1", "location": "s3://kotosiro-sharing-example/avocado" }' \
        | jq '.'
{
  "table": {
    "id": "8a040c74-4505-44e5-aeda-9db662f338eb",
    "name": "table1",
    "location": "s3://kotosiro-sharing-example/avocado"
  }
}

将新表注册为 share1 中 schema1 的一部分

您已经创建了一个新的共享并注册了一个新的。现在,您需要通过创建模式共享关联起来。为此,您可以将注册为 share1schema1 的一部分。将表注册到共享的 API 操作非常简单。以下是一个示例:

 $ curl -s -X POST "https://:8080/admin/shares/share1/schemas/schema1/tables" \
        -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoia290b3Npcm8iLCJlbWFpbCI6ImtvdG9zaXJvQGVtYWlsLmNvbSIsIm5hbWVzcGFjZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNjgxOTM3NzMyfQ.rVjA6S7EWq7CakpB0IHik0mvxl58ynZNxNM3a3RJibY" \
        -H "Content-Type: application/json" \
        -d '{ "table": "table1" }' \
        | jq '.'
{
  "schema": {
    "id": "62bf785c-1764-4953-9986-a6708996e72c",
    "name": "schema1"
  }
}

发布新的接收者配置文件

这是与同事共享 Delta 表的最后一步,也是最重要的一步。您需要发布一个新的接收者配置文件,其中包含同事访问共享数据所需的凭据。生成的配置文件 JSON 是凭据,因此您必须安全地与同事共享。作为管理员,您有责任确保配置文件仅与授权的接收者共享。以下是发布配置文件的方法:

 $ curl -s -X GET "https://:8080/admin/profile" \
        -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoia290b3Npcm8iLCJlbWFpbCI6ImtvdG9zaXJvQGVtYWlsLmNvbSIsIm5hbWVzcGFjZSI6ImFkbWluIiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNjgxOTM3NzMyfQ.rVjA6S7EWq7CakpB0IHik0mvxl58ynZNxNM3a3RJibY" \
        -H "Content-Type: application/json" \
        | jq '.'
{
  "profile": {
    "shareCredentialsVersion": 1,
    "endpoint": "http://127.0.0.1:8080",
    "bearerToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoia290b3Npcm8iLCJlbWFpbCI6ImtvdG9zaXJvQGVtYWlsLmNvbSIsIm5hbWVzcGFjZSI6ImFkbWluIiwicm9sZSI6Imd1ZXN0IiwiZXhwIjoxNjgxOTM3ODA1fQ.Pwqa5ylTDnjyivNsyNTi0QNR1oKuHJhCPPxWiznomRE",
    "expirationTime": "2023-04-19 20:56:45 UTC"
  }
}

创建共享客户端

从现在开始,您是共享 Delta 表的接收者。要将共享 Delta 表作为 pandas 数据帧打开,作为共享 Delta 表的接收者,您需要首先安装 delta-sharing 包。安装该包后,您可以使用共享的配置文件创建 delta_sharing.SharingClient 对象。这将允许您访问共享 Delta 表。

import delta_sharing

profile = "../../creds/profile.json"
client = delta_sharing.SharingClient(profile)

列出表格

让我们验证我们是否可以正确访问共享的。以下脚本检索由您的同事提供的共享共享的所有表的列表:

client.list_all_tables()
[Table(name='table1', share='share1', schema='schema1')]

加载表格

现在是时候访问共享数据了。操作非常简单:无需准备麻烦的云服务凭据,也无需担心同事使用什么平台。您所要做的就是指定的路径。路径由配置文件路径,后跟 #的完全限定名称组成:<share-name>.<schema-name>.<table-name>

url = profile + "#share1.schema1.table1"
delta_sharing.load_as_pandas(url)
日期 平均价格 总销量 4046 4225 4770 总袋数 小袋 大袋 超大袋 类型 年份 地区
0 0 2015-12-26 15:00:00 1.33 64236.62 1036.74 54454.85 48.16 8696.87 8603.62 93.25 0.0 传统 2015 奥尔巴尼
1 1 2015-12-19 15:00:00 1.35 54876.98 674.28 44638.81 58.33 9505.56 9408.07 97.49 0.0 传统 2015 奥尔巴尼
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
18247 10 2018-01-13 15:00:00 1.93 16205.22 1527.63 2981.04 727.01 10969.54 10919.54 50.00 0.0 有机 2018 WestTexNewMexico
18248 11 2018-01-06 15:00:00 1.62 17489.58 2894.77 2356.13 224.53 12014.15 11988.14 26.01 0.0 有机 2018 WestTexNewMexico

18249 行 × 14 列

用于过滤的 SQL 表达式

太棒了!现在您可以从数据湖中访问所需的数据。假设您只对日期范围在 2016-01-012017-12-31 之间的数据感兴趣。在这种情况下,您可以将SQL 片段作为提示发送到共享服务器,以便它过滤掉冗余的 Parquet 文件。以下是请求所需的 Parquet 文件的方法(截至 2023 年 4 月 24 日,此过滤 API 在 Python 客户端库中尚未公开,因此此代码片段基于我的本地补丁。我计划在不久的将来创建拉取请求以将此过滤 API 添加到公开版本中):

url = profile + "#share1.schema1.table1"
delta_sharing.load_as_pandas(
    url,
    predicateHints=['year >= 2016', 'year <= 2017']
)
日期 平均价格 总销量 4046 4225 4770 总袋数 小袋 大袋 超大袋 类型 年份 地区
0 0 2016-12-24 15:00:00 1.52 73341.73 3202.39 58280.33 426.92 11432.09 11017.32 411.83 2.94 传统 2016 奥尔巴尼
1 1 2016-12-17 15:00:00 1.53 68938.53 3345.36 55949.79 138.72 9504.66 8876.65 587.73 40.28 传统 2016 奥尔巴尼
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
11336 49 2017-01-07 15:00:00 1.18 14375.39 1327.98 2617.20 5.75 10424.46 10283.85 140.61 0.00 有机 2017 WestTexNewMexico
11337 50 2016-12-31 15:00:00 1.28 15307.87 867.66 3434.02 37.30 10968.89 10815.88 153.01 0.00 有机 2017 WestTexNewMexico

11338 行 × 14 列

用于过滤的 JSON 谓词

虽然之前使用SQL 过滤predicateHints 很方便,但其逻辑表达能力有点受限,并且根据官方协议规范,建议改用JSON 过滤。需要注意的是,SQL 过滤方法将被弃用。以下是如何使用JSON 过滤请求所需的 Parquet 文件(截至 2023 年 4 月 24 日,此过滤 API 在 Python 客户端库中尚未公开,因此此代码片段基于我的本地补丁。我计划在不久的将来创建拉取请求以将此过滤 API 添加到公开版本中):

url = profile + "#share1.schema1.table1"
delta_sharing.load_as_pandas(
    url,
    jsonPredicateHints={
        "op": "and",
        "children": [
            {
                "op": "greaterThanOrEqual",
                "children": [
                    {"op": "column", "name": "year", "valueType": "int"},
                    {"op": "literal", "value": "2016", "valueType": "int"}
                ]
            },
            {
                "op": "lessThanOrEqual",
                "children": [
                    {"op": "column", "name": "year", "valueType":"int"},
                    {"op": "literal", "value": "2017", "valueType": "int"}
                ]
            }
        ]
    }
)
日期 平均价格 总销量 4046 4225 4770 总袋数 小袋 大袋 超大袋 类型 年份 地区
0 0 2016-12-24 15:00:00 1.52 73341.73 3202.39 58280.33 426.92 11432.09 11017.32 411.83 2.94 传统 2016 奥尔巴尼
1 1 2016-12-17 15:00:00 1.53 68938.53 3345.36 55949.79 138.72 9504.66 8876.65 587.73 40.28 传统 2016 奥尔巴尼
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
11336 49 2017-01-07 15:00:00 1.18 14375.39 1327.98 2617.20 5.75 10424.46 10283.85 140.61 0.00 有机 2017 WestTexNewMexico
11337 50 2016-12-31 15:00:00 1.28 15307.87 867.66 3434.02 37.30 10968.89 10815.88 153.01 0.00 有机 2017 WestTexNewMexico

11338 行 × 14 列

结论

我很高兴宣布 Kotosiro Sharing 项目的发布,感谢您阅读到这里。我希望您喜欢这次短暂的旅程,并看到了 Delta Sharing 如何改变游戏规则。我真正喜欢这个想法的是:

  1. 开放且与云无关的协议。
  2. 易于管理隐私、安全和合规性。
  3. 消除滞后和不一致的数据,以及无需通过电子邮件发送过时数据。
  4. 接收者不需要技术专长,因为他们只需要编写几行 Python 代码。

官方开放协议规范可在此处查看。我也欢迎对我的 Kotosiro Sharing 项目做出贡献。感谢阅读!