跳转至
Apache Sedona 1.9.0 已正式发布,新增 Spark 4.1 支持、proj4sedona 坐标系转换、Bing Tile 函数等众多特性!

在 Spark 上使用 Apache Sedona 处理 GeoPackage

本文介绍如何使用 Apache Sedona 与 Spark 读取 GeoPackage 文件。

您将了解 GeoPackage 文件格式的优缺点,以及如何在生产环境中使用它。

下面先创建一个 GeoPackage 文件,再演示读取。

使用 Sedona 与 Spark 读取 GeoPackage 文件

先创建一个包含若干行数据的 GeoPackage 文件。

首先构造一个 GeoPandas DataFrame:

point1 = Point(0, 0)
point2 = Point(1, 1)
polygon1 = Polygon([(5, 5), (6, 6), (7, 5), (6, 4)])

data = {
    "name": ["Point A", "Point B", "Polygon A"],
    "value": [10, 20, 30],
    "geometry": [point1, point2, polygon1],
}
gdf = gpd.GeoDataFrame(data, geometry="geometry")

将 GeoPandas DataFrame 写入 GeoPackage 文件:

gdf.to_file("/tmp/my_file.gpkg", layer="my_layer", driver="GPKG")

代码中将 driver 设为 GPKG,因此 GeoPandas 会以 GeoPackage 格式写出。

可以把 layer 视作表名。

接下来用 Apache Sedona 与 Spark 读取这个 GeoPackage 文件:

df = (
    sedona.read.format("geopackage")
    .option("tableName", "my_layer")
    .load("/tmp/my_file.gpkg")
)
df.show()

DataFrame 内容如下:

+---+--------------------+---------+-----+
|fid|                geom|     name|value|
+---+--------------------+---------+-----+
|  1|         POINT (0 0)|  Point A|   10|
|  2|         POINT (1 1)|  Point B|   20|
|  3|POLYGON ((5 5, 6 ...|Polygon A|   30|
+---+--------------------+---------+-----+

几何列可以包含点、多边形等多种几何对象。

也可以查看 GeoPackage 文件的元数据:

df = (
    sedona.read.format("geopackage")
    .option("showMetadata", "true")
    .load("/tmp/my_file.gpkg")
)
df.show()

输出如下:

+----------+---------+----------+-----------+--------------------+-----+-----+-----+-----+------+
|table_name|data_type|identifier|description|         last_change|min_x|min_y|max_x|max_y|srs_id|
+----------+---------+----------+-----------+--------------------+-----+-----+-----+-----+------+
|  my_layer| features|  my_layer|           |2025-02-25 06:28:...|  0.0|  0.0|  7.0|  6.0| 99999|
+----------+---------+----------+-----------+--------------------+-----+-----+-----+-----+------+

使用 Sedona 与 Spark 读取多个 GeoPackage 文件

Sedona 也支持读取多个 GeoPackage 文件。假设有以下文件结构:

gpkgs/
  my_file1.gpkg
  my_file2.gpkg

可以这样读取所有文件:

df = sedona.read.format("geopackage").option("tableName", "my_layer").load("/tmp/gpkgs")
df.show()

结果如下:

+---+--------------------+---------+-----+
|fid|                geom|     name|value|
+---+--------------------+---------+-----+
|  1|         POINT (5 5)|  Point C|   30|
|  2|POLYGON ((5 5, 6 ...|Polygon A|   40|
|  1|         POINT (0 0)|  Point A|   10|
|  2|         POINT (1 1)|  Point B|   20|
+---+--------------------+---------+-----+

只需指定包含 GeoPackage 文件的目录,Sedona 即可将它们全部加载到一个 DataFrame 中。

由于 Sedona 可以并行读取与处理这些文件,因此非常适合分析大量 GeoPackage 文件。

加载 GeoPackage 中的栅格数据

也可以从 GeoPackage 中的栅格表加载数据。代码如下:

df = (
    sedona.read.format("geopackage")
    .option("tableName", "raster_table")
    .load("/path/to/geopackage")
)

DataFrame 内容如下:

+---+----------+-----------+--------+--------------------+
| id|zoom_level|tile_column|tile_row|           tile_data|
+---+----------+-----------+--------+--------------------+
|  1|        11|        428|     778|GridCoverage2D["c...|
|  2|        11|        429|     778|GridCoverage2D["c...|
|  3|        11|        428|     779|GridCoverage2D["c...|
|  4|        11|        429|     779|GridCoverage2D["c...|
|  5|        11|        427|     777|GridCoverage2D["c...|
+---+----------+-----------+--------+--------------------+

已知限制(v1.7.0):

  • 不支持 webp 栅格
  • 不支持 ewkb 几何
  • 不支持基于几何包络的过滤

以上限制都将在后续版本中陆续解决,敬请关注!

GeoPackage 文件格式的优势

GeoPackage 格式有许多优点:

  • 因为是开放格式,任何引擎都可以支持。
  • 与许多其他格式不同,它是可变的。
  • 不像某些格式,它会保存 CRS 信息。
  • 既可以存储矢量数据,也可以存储栅格数据。
  • GeoPandas、Sedona、SQLite 等众多引擎都能读取。

但 GeoPackage 也存在不少不足。

GeoPackage 的劣势

GeoPackage 文件格式有以下劣势:

  • 行式存储,无法享受列式格式的列裁剪优势。
  • 不支持多引擎并发事务。
  • 虽然支持 SQLite 事务,但跨引擎可靠事务很难实现。
  • 并非所有引擎都完整支持。

结论

如果您本身在使用 SQLite,GeoPackage 是非常稳健的格式选择。

Sedona 能读取由 SQLite 分析生成的 GeoPackage 文件这一点非常有价值——可以并行读取这些文件,并对海量数据进行分析;同时也可以在集群上运行 Sedona。

如果您还没有使用过 GeoPackage,那么使用 GeoParquet、Iceberg 这类格式通常会是更好的选择。