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 中,我们从最高层到最低层使用以下名称表示间接层:geometriespartsringscoordinates。前三个是整数偏移数组,最后一个是浮点交叉 xy 坐标数组。

Geoarrow 还通过采用密集联合数组布局,允许同一列中存在混合的几何类型。

阅读geoarrow 格式规范以了解更多详情。

GeoColumn#

cuSpatial 通过 GeoColumnGeoMeta 实现了 Arrow 密集联合的特化。一个 GeoColumn 由子列和一个 GeoMeta 对象组成。GeoMeta 拥有两个数组,它们类似于 Arrow 密集联合的类型缓冲区和偏移量缓冲区。

注意

目前,GeoColumn 实现了四种具体的数组类型:pointsmultipoints、multilinestrings 和 multipolygons。Linestrings 和 multilinestrings 统一存储在 multilinestrings 数组中,作为 multilinestrings。Polygons 和 multipolygons 统一存储在 multipolygons 数组中,作为 multipolygons。

点和多点分别存储在不同的数组中,因为将点存储在多点数组中会增加 50% 的存储开销。虽然对于线串和多边形来说也可能如此,但 cuSpatial 的许多用例涉及更复杂的线串和多边形,其中多几何间接的存储开销相对点较低。

GeoSeriesGeoDataFrame 分别继承自 cudf.Seriescudf.DataFrameSeriesDataFrame 都是泛型的 Frame 对象,表示通用列的集合。cuSpatial 通过允许 GeoColumn 存在于 frame 中来扩展这些 cuDF 对象。

GeoSeriesGeoDataFrame 可以与 geopandas 相互转换。cuspatial、geopandas 和其他数据格式之间的互操作性在 cuspatial.io 包中维护。

UnionArray 兼容性#

如前所述,cuspatial 的 GeoColumn 是 Arrow 密集 UnionArray 的特化。对 cuDF 数据类型的基本补充应在 cuDF 中实现,以便 GeoColumn 可以简单地继承其功能。然而,密集 UnionArray 与 libcudf 中现有数据类型截然不同,需要大量努力来实现。在此期间,cuSpatial 提供了一个符合密集 UnionArray 规范的 GeoColumn。随着其成熟,这可能会被上游到 libcudf。

地理空间计算 API#

除了数据结构之外,cuSpatial 还提供了一组计算 API。这些计算 API 被组织成多个模块。所有空间计算模块进一步分组到 spatial 子包中。模块名称应对应特定的计算类别,例如 distancejoin。Cuspatial 避免使用通用类别名称,例如 generic

遗留 API 和现代 API#

出于历史原因,旧的 cuSpatial API 公开原始数组输入,供用户提供原始几何坐标数组和偏移量。较新的 Python API 应接受 GeoSeriesGeoDataFrame 作为输入。开发者可以通过 cuSpatial 的几何访问器(例如 GeoSeries.pointsGeoSeries.multipointsGeoSeries.linesGeoSeries.polygons)提取几何偏移量和坐标。然后,开发者可以将几何偏移量和坐标数组传递给 Cython API。

Cython 层#

cuspatial 的最底层是通过 Cython 与 libcuspatial 的交互。Cython 层由两个组件组成:C++ 绑定和 Cython 包装器。第一个组件包括 .pxd 文件,它们是 Cython 声明文件,将 C++ 头文件的内容暴露给其他 Cython 文件。第二个组件是此功能的 Cython 包装器。这些包装器对于将此功能暴露给纯 Python 代码是必需的。

为了与 libcuspatial 中的基于列的 API 交互,开发者应基本熟悉 libcudf 对象。libcudf 围绕两个主要对象构建,它们的名称大部分是自解释的:columntablelibcudf 还定义了相应的非拥有“视图”类型 column_viewtable_viewlibcudflibcuspatial API 通常都接受视图并返回拥有类型。当一个 cuspatial 对象拥有一个或多个 c++ 拥有对象时,这些对象的生命周期由 python 的引用计数机制自动管理。

与 cuDF 类似,Cython 包装器必须将 Column 对象转换为 column_view 对象,调用 libcuspatial API,并从 c++ 结果重构一个 cuDF 对象。当代码到达这个阶段时,对象被认为是 libcuspatial API 的完全合法输入。因此,包装器除了上述内容外不应包含额外组件。