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

资讯详情

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

如何用 Arrow C 数据接口在同进程内交换 Python 与 Java 的 Arrow 数据

如何用 Arrow C 数据接口在同进程内交换 Python 与 Java 的 Arrow 数据 如何用 Arrow C 数据接口在同进程内交换 Python 与 Java 的 Arrow 数据【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow本文解决的任务是在同一个进程内让 PythonPyArrow和 JavaArrow Java直接交换 Arrow 数据而不经过序列化/反序列化。做法是用 JPype 在 Python 解释器中启动一个 JVM通过 Arrow C 数据接口C Data Interface把 PyArrow 数组的ArrowArray和ArrowSchema引用传给 Java 方法Java 侧拿到后直接按 Arrow 格式读写两边零拷贝。适用的前提在文档中有明确说明Python 环境已正确安装pyarrowJava 环境已安装arrow库且 Arrow Java 必须用mvn -Parrow-c-data编译过以启用 CData 交换支持。注意 C 数据接口的非目标non-goals明确排除了跨进程共享和存储持久化——它只服务于同进程内的数据交换跨进程场景应改用 Arrow IPC 格式。完整操作依据文档 PyArrow 与 Java 集成C 数据接口本身的协议定义见 C 数据接口规范。准备条件按文档说明需要准备两套环境Python 环境已安装pyarrow另外还需要两个库——jpype1在 Python 内启动 JVM 的桥接库和cffi文档指出使用 C Data interface 的 pyarrow 目前需要显式安装$ pip install jpype1 $ pip install cffiJava 环境已安装arrow库并且 Arrow Java 需要用-Parrow-c-dataMaven profile 编译确保 CData 交换支持被启用。Arrow 仓库的构建文档Java 构建指南给出的对应命令是$ cd arrow/java $ mvn -Darrow.c.jni.dist.dirarrow 仓库 java-dist/lib 的绝对路径 -Parrow-c-data clean install其中-Darrow.c.jni.dist.dir是构建 Arrow C JNI 模块时生成的目录需要替换为你本地对应路径的绝对路径。Java 侧编写接收 C 数据引用的类以文档中的FillTen示例为准Java 类提供一个fillCArray静态方法接收 Python 传过来的两个指针ArrowArray和ArrowSchema的地址把它们还原成 Arrow Java 的FieldVector后填充数据。FillTen.java完整示例见文档import org.apache.arrow.c.ArrowArray; import org.apache.arrow.c.ArrowSchema; import org.apache.arrow.c.Data; import org.apache.arrow.memory.RootAllocator; import org.apache.arrow.vector.FieldVector; import org.apache.arrow.vector.BigIntVector; public class FillTen { static RootAllocator allocator new RootAllocator(); public static void fillCArray(long c_array_ptr, long c_schema_ptr) { ArrowArray arrow_array ArrowArray.wrap(c_array_ptr); ArrowSchema arrow_schema ArrowSchema.wrap(c_schema_ptr); FieldVector v Data.importVector(allocator, arrow_array, arrow_schema, null); FillTen.fillVector((BigIntVector)v); } private static void fillVector(BigIntVector iv) { iv.setSafe(0, 1); iv.setSafe(1, 2); iv.setSafe(2, 3); iv.setSafe(3, 4); iv.setSafe(4, 5); iv.setSafe(5, 6); iv.setSafe(6, 7); iv.setSafe(7, 8); iv.setSafe(8, 9); iv.setSafe(9, 10); } }fillCArray的作用是把 C 数据交换格式收到的 Array 和 Schema 还原为FieldVector这样 Arrow Java 就能按普通向量处理它。由于这类依赖了 Arrow 的包单独javac编译不够需要建一个 Maven 工程。把类放在src/main/java/FillTen.javapom.xml收集依赖文档示例使用 Arrow 8.0.0 的构件arrow-c-data是 CData 支持的关键依赖project modelVersion4.0.0/modelVersion groupIdorg.apache.arrow.py2java/groupId artifactIdFillTen/artifactId version1/version properties maven.compiler.source8/maven.compiler.source maven.compiler.target8/maven.compiler.target /properties dependencies dependency groupIdorg.apache.arrow/groupId artifactIdarrow-memory/artifactId version8.0.0/version typepom/type /dependency dependency groupIdorg.apache.arrow/groupId artifactIdarrow-memory-netty/artifactId version8.0.0/version typejar/type /dependency dependency groupIdorg.apache.arrow/groupId artifactIdarrow-vector/artifactId version8.0.0/version typepom/type /dependency dependency groupIdorg.apache.arrow/groupId artifactIdarrow-c-data/artifactId version8.0.0/version typejar/type /dependency /dependencies /project用 Maven 编译并收集依赖副作用target/目录生成 jar 包dependencies/目录收集全部依赖 jarPython 后续从这两个目录加载类$ mvn package $ mvn org.apache.maven.plugins:maven-dependency-plugin:2.7:copy-dependencies -DoutputDirectorydependencies第二条命令把所有依赖 jar 收集到dependencies目录方便 Python 侧通过 classpath 通配符一次性加载。文档还提到可选替代用maven-assembly-plugin打成一个包含全部依赖的 fat jar但那是可选项不影响主路径。Python 侧导出数组并调用 Java 方法创建fillten.py。脚本的流程是启动 JVM 并加载FillTen类 → 创建 10 个 0 的 PyArrow 数组 → 通过 C 数据接口导出数组和它的 Schema → 把两个指针传给 Java → 打印结果看内容是否被 Java 修改import jpype import jpype.imports from jpype.types import * # Init the JVM and make FillTen class available to Python. jpype.startJVM(classpath[./dependencies/*, ./target/*]) FillTen JClass(FillTen) # Create a Python array of 10 elements import pyarrow as pa array pa.array([0]*10) from pyarrow.cffi import ffi as arrow_c # Export the Python array through C Data c_array arrow_c.new(struct ArrowArray*) c_array_ptr int(arrow_c.cast(uintptr_t, c_array)) array._export_to_c(c_array_ptr) # Export the Schema of the Array through C Data c_schema arrow_c.new(struct ArrowSchema*) c_schema_ptr int(arrow_c.cast(uintptr_t, c_schema)) array.type._export_to_c(c_schema_ptr) # Send Array and its Schema to the Java function # that will populate the array with numbers from 1 to 10 FillTen.fillCArray(c_array_ptr, c_schema_ptr) # See how the content of our Python array was changed from Java # while it remained of the Python type. print(ARRAY, type(array), array)脚本里classpath[./dependencies/*, ./target/*]对应上一步 Maven 生成的两个目录需要在包含这两个目录的工作目录下运行。array._export_to_c(...)把数组按 C 数据接口填入消费者这里是 Python 侧用 cffi 分配的struct ArrowArray*array.type._export_to_c(...)同理填入 Schema这是 PyArrow 暴露 C 数据接口的入口。结果验证$ mvn package $ mvn org.apache.maven.plugins:maven-dependency-plugin:2.7:copy-dependencies -DoutputDirectorydependencies $ python fillten.py文档展示的运行结果示例输出ARRAY class pyarrow.lib.Int64Array [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]判断成功的方法打印的对象类型仍是pyarrow.lib.Int64Array数据在 Java 侧被修改后它依然是 Python 侧的 PyArrow 数组且内容从 10 个 0 变成了 1 到 10——说明 Java 通过 C 数据接口直接改写了 Python 数组的内容而不是拷贝了一份。可选分支用 C Stream Interface 交换 RecordBatchReader如果需要交换的是一串 RecordBatch 而不是单个数组文档给出 C Stream Interface 的演示Java 类PythonInteropDemo提供exportStream读本地 Arrow IPC 文件并导出流和importStream导入流并写成 JSON 文件两个方法Java 侧用ArrowArrayStream.wrap(cStreamPointer)和Data.exportArrayStream/Data.importArrayStream完成导入导出完整 Java 代码见文档。Python 侧对应地把RecordBatchReader导出/导入from pyarrow.cffi import ffi as arrow_c # Export the Python reader through C Data c_stream arrow_c.new(struct ArrowArrayStream*) c_stream_ptr int(arrow_c.cast(uintptr_t, c_stream)) reader._export_to_c(c_stream_ptr)以及从 Java 回读的导入方向with pa.RecordBatchReader._import_from_c(c_stream_ptr) as source: print(source.read_all())文档示例输出示例结果显示 Java 写出的 JSON 文件和 Java 读取的 IPC 文件内容都正确反映了 Python 侧构造的两个 batchints列[[0,2,4,8],[null,32,64,null]]、strs列[[a,b,c,null],[e,null,null,h]]。限制与注意事项仅限同进程C 数据接口的设计目标是零拷贝共享同进程内不同运行时和组件之间的 Arrow 数据文档的 Non-goals 明确不包含跨进程共享和存储持久化跨进程/跨机器应使用 Arrow IPC 格式。原地修改数组不安全文档特别注明Java 侧直接改写传入的数组内容不是安全操作示例之所以能工作mostly是因为数组的大小、类型和 null 都没变。不要把这条示例路径当作常规用法。release 回调语义按 C 数据接口规范消费者用完后必须调用基结构的release回调但不得调用其 children 的 release由生产者负责调用后不得再访问该结构。Java 侧Data.importVector与 PyArrow 的_export_to_c已按此协议实现手写 C 实现时参照 规范中的 release 回调示例。pyarrow.jvm不是 C 数据接口文档说明pyarrow.jvm模块目前是为 JPype 专门写的能力有限——嵌套类型如 struct不支持且只支持同一进程内运行的 JVM。它适合做 JavaBigIntVector到 PyArrow array 的简单转换但走 C 数据接口才是通用、无适配层的路径且文档提到pyarrow.jvm未来会改为基于 C Data interface 实现。完成上述步骤后如果你的场景是Java 方法处理 PyArrow 数组/批数据并原路返回本文的fillCArray路径就是主路径若涉及多 batch 流式交换改用 C Stream Interface 分支即可两者都依赖同一套-Parrow-c-data编译产物和 JPype 同进程环境。【免费下载链接】arrowApache Arrow is the universal columnar format and multi-language toolbox for fast data interchange and in-memory analytics项目地址: https://gitcode.com/GitHub_Trending/arrow3/arrow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表