十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Apache Arrow 开发者实战:向 PyArrow compute 模块贡献新特性的完整流程

Apache Arrow 开发者实战:向 PyArrow compute 模块贡献新特性的完整流程 数据工程数据分析大数据【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址https://gitcode.com/gh_mirrors/arrow12/arrow点击查看免费下载导读本文基于 Apache Arrow 官方开发者指南中的 Python 教程完整走一遍从零向 PyArrow 贡献一个新计算函数的真实流程从 Fork 仓库、构建 PyArrow、创建 Issue到研究pc.min_max的实现链路、编写pc.tutorial_min_max新函数、补充单元测试、通过 Archery 检查代码风格最终提交 Pull Request。读完本文你将掌握 Arrow 开源协作的标准工作流理解 PyArrow 中 Python 层与 C 计算内核的衔接方式并能独立完成一个简单的功能贡献或 Bug 修复。本文档对应的原始教程位于 docs/source/developers/guide/tutorials/python_tutorial.rst读者可结合 开发者指南总览 与 分步指南 对照阅读。本教程要贡献的新特性模仿arrow.compute模块中已有的min_max函数但把返回区间在两侧各扩大 1——最小值减 1、最大值加 1。这是一个专为教程虚构的函数实际项目中并不存在用于演示完整的贡献流程。教程的定位与前置阅读本教程不是一份从头到尾的逐步操作手册而是针对一个具体案例的实战演示。它遵循 快速参考指南 中规定的步骤并与更详细的 分步指南 相配套——当你在本教程中遇到信息缺失时应前往分步指南查找补充资料。特性贡献的目标模块是PyArrow 的 compute 模块但你也可以按照完全相同的步骤来修复一个 Bug或新增一个绑定binding。教程中涉及到的各个子环节都有对应的详细章节环节详细指南环境搭建Git 安装等set_up.rst构建 Arrow 与 PyArrowbuilding.rst查找/创建 Issuefinding_issues.rst测试规范testing.rst代码风格检查styling.rstPull Request 生命周期pr_lifecycle.rst环境搭建Fork、Clone 并配置 upstreamArrow 使用 Git 进行版本控制贡献流程基于 Pull Request。开始之前请确保 Git 已安装安装说明见 set_up.rst。首先在代码托管平台GitHub上ForkApache Arrow 仓库然后在本地克隆你自己的 Fork并把官方仓库添加为upstream远程地址$ git clone https://github.com/your username/arrow.git $ cd arrow $ git remote add upstream https://github.com/apache/arrow此后origin指向你自己 Fork 的仓库用于推送新分支upstream指向官方仓库用于同步最新代码。从源码结构看这个arrow目录同时包含 C 核心实现cpp/src、Python 绑定python/pyarrow、Javajava、Gogo等多个语言模块。本教程的操作只涉及 Python 目录下的两个文件python/pyarrow/compute.py和python/pyarrow/tests/test_compute.py。构建 PyArrow构建 PyArrow 的脚本因操作系统而异本教程不赘述具体构建命令只给出指引构建流程的入门介绍参见 building.rst构建 PyArrow 的具体说明参见分步指南中 PyArrow 构建部分build_pyarrow小节以及仓库中的 python/README.md 和 python/setup.py。构建成功后在仓库的python目录下即可导入并实验pyarrow。后续所有 Python 交互都默认在arrow/python目录下进行。为新特性创建 GitHub Issue在动手写代码之前先要创建或认领一个 Issue理由很实际让社区其他人知道你在做这件事避免重复劳动。在 Arrow 项目的 GitHub Issue 面板中点击New issue创建新 Issue创建后把自己指派给该 Issue——在 Issue 下添加一条take评论即可认领任务。有关查找合适 Issue、了解 Issue 规范的更多信息参见 finding_issues.rst。本教程对应的 Issue 编号为ARROW-14977该编号在后续分支名、提交信息、PR 标题中都会用到。从更新的 main 分支创建新工作分支在改动任何代码之前必须先创建新的 Git 分支。从已同步的main分支出发$ git checkout main $ git fetch upstream $ git pull --ff-only upstream main $ git checkout -b ARROW-14977这里有两个值得注意的细节--ff-only只允许快进fast-forward合并如果 upstream 与本地有分叉会直接报错而不是自动产生合并提交从而保证本地main与官方main严格一致分支名直接使用 Issue 编号ARROW-14977这是 Arrow 社区的命名惯例让分支与 Issue 一一对应。研究代码库pc.min_max 的 Python 与 C 链路在写新函数之前先弄清楚已有的pc.min_max是怎么定义的、Python 层如何与 C 计算内核连接。教程推荐直接在 GitHub 仓库中搜索函数引用。搜索结果指向python/pyarrow/tests/test_compute.py该文件在本仓库中确实存在既然该函数有测试那么它一定在compute.py中被定义并导出。进一步查看 python/pyarrow/compute.py 可以发现文件通过_make_global_functions()机制见compute.py中_wrap_function、_decorate_compute_function等辅助函数把 C 计算函数批量包装成 Python 函数与此同时 python/pyarrow/_compute.pyx 以 Cython 形式封装了 C 侧的函数注册表与call_function调用入口。在 python/pyarrow/_compute.pyx 中还能看到 Arrow 计算函数的分类体系——min_max属于scalar_aggregate标量聚合类函数它对输入做降维归约同类函数还有sum、mode等与之并列的还有hash_aggregate如hash_sum、hash_min_max、scalar、vector、meta等类别。这解释了为什么min_max的调用方式是传入一个数组 聚合选项。在 Python 控制台中研究 pc.min_max从arrow/python目录进入 Python 控制台实验pc.min_max的行为$ cd python $ python Python 3.9.7 (default, Oct 22 2021, 13:24:00) [Clang 13.0.0 (clang-1300.0.29.3)] on darwin Type help, copyright, credits or license for more information. import pyarrow.compute as pc data [4, 5, 6, None, 1] data [4, 5, 6, None, 1] pc.min_max(data) pyarrow.StructScalar: [(min, 1), (max, 6)] pc.min_max(data, skip_nullsFalse) pyarrow.StructScalar: [(min, None), (max, None)]两个关键观察pc.min_max接受一个普通 Python 列表返回一个pyarrow.StructScalar其结构包含(min, ...)与(max, ...)两个字段默认参数skip_nullsTrue会忽略空值所以None不影响结果当skip_nullsFalse时只要输入含空值结果就整体为None。skip_nulls正是ScalarAggregateOptions的成员——在 python/pyarrow/compute.py 的导入列表中可以看到ScalarAggregateOptions从 Cython 层导出而底层的选项定义位于 C 源码中。我们会在新函数里复用这一选项类。第一版实现直接调用 C 的 min_max我们的新函数命名为pc.tutorial_min_max。目标行为输入同样的数据[4, 5, 6, None, 1]默认返回[(min-, 0), (max, 7)]即最小值减 1、最大值加 1当skip_nullsFalse空值纳入计算时结果与pc.min_max一致为[(min, None), (max, None)]。先在 python/pyarrow/compute.py 末尾添加第一版代码验证能否从 Python 侧成功调用 C 的min_max内核def tutorial_min_max(values, skip_nullsTrue): Add docstrings Parameters ---------- values : Array Returns ------- result : TODO Examples -------- import pyarrow.compute as pc data [4, 5, 6, None, 1] pc.tutorial_min_max(data) pyarrow.StructScalar: [(min-, 0), (max, 7)] options ScalarAggregateOptions(skip_nullsskip_nulls) return call_function(min_max, [values], options)这段代码揭示了 PyArrow compute 模块的标准写法构造一个 Options 对象ScalarAggregateOptions再通过call_function(min_max, [values], options)按名称调用 C 计算内核。call_function的第一个参数是 C 侧注册的函数名字符串这与 python/pyarrow/_compute.pyx 中封装 CFunctionRegistry的实现一一对应。重新导入并测试 import pyarrow.compute as pc data [4, 5, 6, None, 1] pc.tutorial_min_max(data) pyarrow.StructScalar: [(min, 1), (max, 6)]调用成功返回的仍是原样的(min, 1), (max, 6)。接下来要把它改造成区间外扩的版本。研究 StructScalar 的构造方法要返回[(min-, 0), (max, 7)]这种自定义字段名和字段类型的结构需要学会手工构造pyarrow.StructScalar。教程提示在文档不足的情况下单元测试是最好的代码示例来源——在python/pyarrow/tests/test_scalars.py的test_struct_duplicate_fields测试中可以找到StructScalar的构造范例。在 Python 控制台亲自动手构造一个 import pyarrow as pa ty pa.struct([ ... pa.field(min-, pa.int64()), ... pa.field(max, pa.int64()), ... ]) pa.scalar([(min-, 3), (max, 9)], typety) pyarrow.StructScalar: [(min-, 3), (max, 9)]要点用pa.struct([...])定义一个结构类型pa.field(min-, pa.int64())声明字段名可以包含-、等字符与字段类型用pa.scalar([(min-, 3), (max, 9)], typety)把 Python 值包装成指定类型的StructScalarStructScalar支持下标访问min_max[0]、min_max[1]也支持as_py()转回普通 Python 值。完成最终实现结合StructScalar的构造知识和ScalarAggregateOptions的选项在compute.py末尾完成最终版def tutorial_min_max(values, skip_nullsTrue): Compute the minimum-1 and maximum1 values of a numeric array. This is a made-up feature for the tutorial purposes. Parameters ---------- values : Array skip_nulls : bool, default True If True, ignore nulls in the input. Returns ------- result : StructScalar of min-1 and max1 Examples -------- import pyarrow.compute as pc data [4, 5, 6, None, 1] pc.tutorial_min_max(data) pyarrow.StructScalar: [(min-, 0), (max, 7)] options ScalarAggregateOptions(skip_nullsskip_nulls) min_max call_function(min_max, [values], options) if min_max[0].as_py() is not None: min_t min_max[0].as_py()-1 max_t min_max[1].as_py()1 else: min_t min_max[0].as_py() max_t min_max[1].as_py() ty pa.struct([ pa.field(min-, pa.int64()), pa.field(max, pa.int64()), ]) return pa.scalar([(min-, min_t), (max, max_t)], typety)实现逻辑拆解构造选项并调用 C 内核ScalarAggregateOptions(skip_nullsskip_nulls)控制空值处理策略call_function(min_max, [values], options)拿到原始聚合结果空值分支处理min_max[0].as_py()把StructScalar的第一个字段min转成 Python 值若非None则min_t min - 1、max_t max 1若为None即skip_nullsFalse且输入含空值则保持None与pc.min_max的行为对齐构造结果用pa.structpa.scalar把两个修正后的值包装成字段名为min-、max的StructScalar返回。添加单元测试并运行 pytest功能完成后必须在 python/pyarrow/tests/test_compute.py 中添加单元测试。把测试追加到该文件末尾def test_tutorial_min_max(): arr [4, 5, 6, None, 1] l1 {min-: 0, max: 7} l2 {min-: None, max: None} assert pc.tutorial_min_max(arr).as_py() l1 assert pc.tutorial_min_max(arr, skip_nullsFalse).as_py() l2测试同时覆盖了两条路径默认skip_nullsTrue空值被忽略期望输出{min-: 0, max: 7}skip_nullsFalse空值导致结果整体为None期望输出{min-: None, max: None}。运行单个测试用pytest的-k参数按名称筛选只跑新加的测试$ cd python $ python -m pytest pyarrow/tests/test_compute.py -k test_tutorial_min_max test session starts platform darwin -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 rootdir: /Users/alenkafrim/repos/arrow/python, configfile: setup.cfg plugins: hypothesis-6.24.1, lazy-fixture-0.6.3 collected 204 items / 203 deselected / 1 selected pyarrow/tests/test_compute.py . [100%] 1 passed, 203 deselected in 0.16s 运行整个测试文件确认单个测试通过后运行test_compute.py的完整测试套件确保新代码没有破坏任何既有功能$ python -m pytest pyarrow/tests/test_compute.py test session starts platform darwin -- Python 3.9.7, pytest-6.2.5, py-1.10.0, pluggy-1.0.0 rootdir: /Users/alenkafrim/repos/arrow/python, configfile: setup.cfg plugins: hypothesis-6.24.1, lazy-fixture-0.6.3 collected 204 items pyarrow/tests/test_compute.py ................................... [ 46%] ................................................. [100%] 204 passed in 0.49s 从源码结构看test_compute.py中既有test_tutorial_min_max这样的普通函数测试也大量使用了 Hypothesis 属性测试如搜索min_max时看到的min_max_arrow风格测试其所在目录 python/pyarrow/tests 还配套有conftest.py等测试基础设施。关于测试编写规范的更多内容参见 testing.rst。检查代码风格ArcheryArrow 使用名为Archery的工具链检查代码是否符合 PEP 8 风格指南。运行$ archery lint --python --fix INFO:archery:Running Python formatter (autopep8) INFO:archery:Running Python linter (flake8) /Users/alenkafrim/repos/arrow/python/pyarrow/tests/test_compute.py:2288:80: E501 line too long (88 79 characters)注意两点--fix参数会让 Archery 尝试自动修复风格问题内部依次调用 autopep8 格式化器与 flake8 检查器但部分问题无法自动修复——例如上图中的E501 line too long行超长就需要手工调整。把超长行拆行后再次运行$ archery lint --python --fix INFO:archery:Running Python formatter (autopep8) INFO:archery:Running Python linter (flake8)没有任何输出即表示检查通过。Archery 的相关源码与配置位于 dev/archery其 Python 环境依赖可参考 ci/conda_env_archery.txt。提交、同步与推送检查改动内容提交前先查看哪些文件被修改并 diff 确认没有引入错误$ git status On branch ARROW-14977 Changes not staged for commit: (use git add file... to update what will be committed) (use git restore file... to discard changes in working directory) modified: python/pyarrow/compute.py modified: python/pyarrow/tests/test_compute.py no changes added to commit (use git add and/or git commit -a)$ git diff diff --git a/python/pyarrow/compute.py b/python/pyarrow/compute.py index 9dac606c3..e8fc775d8 100644 --- a/python/pyarrow/compute.py b/python/pyarrow/compute.py -774,3 774,45 def bottom_k_unstable(values, k, sort_keysNone, *, memory_poolNone): sort_keys map(lambda key_name: (key_name, ascending), sort_keys) options SelectKOptions(k, sort_keys) return call_function(select_k_unstable, [values], options, memory_pool) def tutorial_min_max(values, skip_nullsTrue): Compute the minimum-1 and maximum-1 values of a numeric array. This is a made-up feature for the tutorial purposes. Parameters ---------- values : Array skip_nulls : bool, default True If True, ignore nulls in the input. Returns ------- result : StructScalar of min-1 and max1 Examples -------- import pyarrow.compute as pc data [4, 5, 6, None, 1] pc.tutorial_min_max(data) pyarrow.StructScalar: [(min-, 0), (max, 7)] options ScalarAggregateOptions(skip_nullsskip_nulls) min_max call_function(min_max, [values], options) ...git diff显示改动正好落在compute.py末尾跟在bottom_k_unstable函数之后与预期一致。提交到分支历史$ git commit -am Adding a new compute feature for tutorial purposes [ARROW-14977 170ef85be] Adding a new compute feature for tutorial purposes 2 files changed, 51 insertions()用git log查看提交历史$ git log commit 170ef85beb8ee629be651e3f93bcc4a69e29cfb8 (HEAD - ARROW-14977) Author: Alenka Frim frim.alenkagmail.com Date: Tue Dec 7 13:45:06 2021 0100 Adding a new compute feature for tutorial purposes commit 8cebc4948ab5c5792c20a3f463e2043e01c49828 (main) Author: Sutou Kouhei kouclear-code.com Date: Sun Dec 5 15:19:46 2021 0900 ARROW-14981: [CI][Docs] Upload built documents ...需要时 rebase 到 upstream main如果分支创建已经有一段时间upstreammain上可能出现了新提交。为避免合并冲突推送前先 rebase 到最新的 upstream$ git pull upstream main --rebase推送到自己的 Forkorigin$ git push origin ARROW-14977 Enumerating objects: 13, done. Counting objects: 100% (13/13), done. Delta compression using up to 8 threads Compressing objects: 100% (7/7), done. Writing objects: 100% (7/7), 1.19 KiB | 1.19 MiB/s, done. Total 7 (delta 6), reused 0 (delta 0), pack-reused 0 remote: Resolving deltas: 100% (6/6), completed with 6 local objects. remote: remote: Create a pull request for ARROW-14977 on GitHub by visiting: remote: https://github.com/AlenkaF/arrow/pull/new/ARROW-14977 remote: To https://github.com/AlenkaF/arrow.git * [new branch] ARROW-14977 - ARROW-14977创建 Pull Request推送成功后打开 Arrow 仓库官方或你自己的 Fork页面会看到一条黄色的通知栏提示你最近推送了ARROW-14977分支——点击Compare pull request即可发起 Pull Request。创建 PR 时注意两个要点标题必须与 Issue 对应。本教程应改为ARROW-14977: [Python] Add a made-up feature for the guide tutorial注意与 Issue 标题保持一致并补充正确的标点。补充说明本教程最初编写时项目还在使用 Jira Issue 追踪系统因此示例标题以ARROW-为前缀当前项目已改用 GitHub Issues标题前缀相应地变为GH-14977: [Python] Add a made-up feature for the guide tutorial编写清晰的描述让别人一眼看懂你想做什么、改了什么。点击Create pull request后代码便以 PR 形式进入官方仓库PR 会自动关联到对应的 Issue同时 CI 开始运行。接下来等待社区评审review根据反馈修改代码、回复评论、解决 conversation直到评审通过合并。有关 PR 评审、合入等完整生命周期的说明参见 pr_lifecycle.rst。小结与延伸阅读本教程通过一个虚构的tutorial_min_max函数完整演示了 Apache Arrow 的功能贡献闭环建 Issue → 开分支 → 研究既有实现 → 编写 Python 包装复用 C 计算内核→ 构造 StructScalar 返回结果 → 补测试 → 风格检查 → 提交推送 → 发起 PR。其中最关键的技术认知是PyArrow 的 compute 函数本质上是 python/pyarrow/compute.py 中通过call_function对 python/pyarrow/_compute.pyx 封装的 C 计算内核的轻量包装理解这条链路后你就能举一反三地扩展更多计算函数。建议的延伸阅读路径若要把新特性深入 C 层而非仅仅包装既有内核可阅读 cpp/src/arrow/compute 下的内核实现以及 python/pyarrow/_compute.pyx 中FunctionKind分类体系想参与更多语言绑定可参照同系列的 r_tutorial.rstR 语言教程了解 R 侧绑定流程想深入了解 Arrow 的整体架构可阅读 architectural_overview.rst。赞分享数据工程数据分析大数据【免费下载链接】arrowApache Arrow is a multi-language toolbox for accelerated data interchange and in-memory processing项目地址https://gitcode.com/gh_mirrors/arrow12/arrow点击查看免费下载相关推荐Apache Arrow 贡献实战从零为 PyArrow compute 模块添加新功能的完整教程Apache Arrow 贡献实战从零为 PyArrow compute 模块添加新功能的完整教程 本文以 Apache Arrow 官方开发者指南中的 Py大数据数据分析数据工程序列化Apache Arrow 开发者与贡献者指南从开发入口、协作流程到代码评审的完整地图Apache Arrow 开发者与贡献者指南从开发入口、协作流程到代码评审的完整地图 Apache Arrow 是一个跨语言的大型开源项目仓库同时维护 C大数据数据分析数据工程序列化Apache Arrow 贡献者实战指南从环境搭建到提交第一个 PR 的完整流程Apache Arrow 贡献者实战指南从环境搭建到提交第一个 PR 的完整流程 本篇指南基于 Apache Arrow 官方开发者文档中的 Steps i大数据数据分析数据工程序列化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表