cuSpatial 库设计#
概述#
从较高层面来看,cuspatial
包含三个部分
一种由 GPU 支持的
GeoDataFrame
数据结构一组计算 API
一个 Cython API 层
核心数据结构#
注意
注意:cuSpatial 的核心数据结构与 geopandas
的核心数据结构名称相同,因此我们将 geopandas 的 dataframe 对象称为 geopandas.GeoDataFrame
,而将 cuspatial 的 dataframe 对象称为 GeoDataFrame
。
GeoArrow 格式介绍#
在底层,cuspatial 利用其数组结构 (SoA) 格式,可以对几何数据进行并行计算。具体来说,cuspatial 采用 GeoArrow 格式,它是 Apache Arrow 格式的扩展,使用 Arrow 的 变长列表布局
来支持几何数组。
根据定义,几何复杂性(维度或多几何)的每次增加都需要额外的间接层。在 cuSpatial 中,我们从最高层到最低层使用以下名称表示间接层:geometries
、parts
、rings
和 coordinates
。前三个是整数偏移数组,最后一个是浮点交叉 xy 坐标数组。
Geoarrow 还通过采用密集联合数组布局,允许同一列中存在混合的几何类型。
阅读geoarrow 格式规范以了解更多详情。
GeoColumn#
cuSpatial 通过 GeoColumn
和 GeoMeta
实现了 Arrow 密集联合的特化。一个 GeoColumn
由子列和一个 GeoMeta
对象组成。GeoMeta
拥有两个数组,它们类似于 Arrow 密集联合的类型缓冲区和偏移量缓冲区。
注意
目前,GeoColumn
实现了四种具体的数组类型:points
、multipoints
、multilinestrings 和 multipolygons。Linestrings 和 multilinestrings 统一存储在 multilinestrings
数组中,作为 multilinestrings。Polygons 和 multipolygons 统一存储在 multipolygons
数组中,作为 multipolygons。
点和多点分别存储在不同的数组中,因为将点存储在多点数组中会增加 50% 的存储开销。虽然对于线串和多边形来说也可能如此,但 cuSpatial 的许多用例涉及更复杂的线串和多边形,其中多几何间接的存储开销相对点较低。
GeoSeries
和 GeoDataFrame
分别继承自 cudf.Series
和 cudf.DataFrame
。Series
和 DataFrame
都是泛型的 Frame
对象,表示通用列的集合。cuSpatial 通过允许 GeoColumn
存在于 frame 中来扩展这些 cuDF 对象。
GeoSeries
和 GeoDataFrame
可以与 geopandas
相互转换。cuspatial、geopandas
和其他数据格式之间的互操作性在 cuspatial.io
包中维护。
UnionArray 兼容性#
如前所述,cuspatial 的 GeoColumn
是 Arrow 密集 UnionArray
的特化。对 cuDF 数据类型的基本补充应在 cuDF 中实现,以便 GeoColumn
可以简单地继承其功能。然而,密集 UnionArray
与 libcudf 中现有数据类型截然不同,需要大量努力来实现。在此期间,cuSpatial 提供了一个符合密集 UnionArray
规范的 GeoColumn
。随着其成熟,这可能会被上游到 libcudf。
地理空间计算 API#
除了数据结构之外,cuSpatial 还提供了一组计算 API。这些计算 API 被组织成多个模块。所有空间计算模块进一步分组到 spatial
子包中。模块名称应对应特定的计算类别,例如 distance
或 join
。Cuspatial 避免使用通用类别名称,例如 generic
。
遗留 API 和现代 API#
出于历史原因,旧的 cuSpatial API 公开原始数组输入,供用户提供原始几何坐标数组和偏移量。较新的 Python API 应接受 GeoSeries
或 GeoDataFrame
作为输入。开发者可以通过 cuSpatial 的几何访问器(例如 GeoSeries.points
、GeoSeries.multipoints
、GeoSeries.lines
、GeoSeries.polygons
)提取几何偏移量和坐标。然后,开发者可以将几何偏移量和坐标数组传递给 Cython API。
Cython 层#
cuspatial 的最底层是通过 Cython 与 libcuspatial
的交互。Cython 层由两个组件组成:C++ 绑定和 Cython 包装器。第一个组件包括 .pxd
文件,它们是 Cython 声明文件,将 C++ 头文件的内容暴露给其他 Cython 文件。第二个组件是此功能的 Cython 包装器。这些包装器对于将此功能暴露给纯 Python 代码是必需的。
为了与 libcuspatial
中的基于列的 API 交互,开发者应基本熟悉 libcudf
对象。libcudf
围绕两个主要对象构建,它们的名称大部分是自解释的:column
和 table
。libcudf
还定义了相应的非拥有“视图”类型 column_view
和 table_view
。libcudf
和 libcuspatial
API 通常都接受视图并返回拥有类型。当一个 cuspatial
对象拥有一个或多个 c++ 拥有对象时,这些对象的生命周期由 python 的引用计数机制自动管理。
与 cuDF 类似,Cython 包装器必须将 Column
对象转换为 column_view
对象,调用 libcuspatial
API,并从 c++ 结果重构一个 cuDF 对象。当代码到达这个阶段时,对象被认为是 libcuspatial
API 的完全合法输入。因此,包装器除了上述内容外不应包含额外组件。