Skip to content

一、为什么需要空间索引

假设地图有 100 万个点

如果用户点击地图,需要找:

text
离鼠标最近的点

最简单方式:

text
遍历所有点
O(n)

如果:

text
n = 1000000

每次点击都遍历:

text
1000000 次计算

地图就会卡顿。

所以需要:

text
空间索引(Spatial Index)

目标:

text
O(n) → O(log n)

二、空间索引核心思想

普通数据库索引:

text
B-Tree

一维数据

但 GIS 数据是:

text
二维 / 三维

例如:

text
(x, y)

所以需要:

text
多维索引

常见结构:

索引用途
R-TreeGIS 最常见
QuadTree地图瓦片
KD-Tree最近邻搜索

三、R-Tree(GIS最常见)

R-Tree 是 矩形树

核心思想:

text
用矩形包裹对象

例如:

        Root
       /    \
    NodeA  NodeB

每个节点是:

text
MBR
Minimum Bounding Rectangle

例如:

+--------+
| 点集合 |
+--------+

插入流程

假设插入一个点:

text
P(10,20)

步骤:

1 找最合适节点

选择 扩展面积最小 的矩形。

例如:

text
Area increase 最小

2 插入叶子节点

Leaf
 ├ Point1
 ├ Point2
 └ Point3

3 节点溢出

如果:

text
node > maxEntries

就:

text
split

拆分节点。

四、查询流程(核心)

例如查询:

text
鼠标附近的点

步骤:

1 从 root 开始

检查:

text
query bbox

是否和节点矩形相交。

2 如果不相交

直接:

text
skip

3 如果相交

进入子节点。

4 到达 leaf

返回数据。

查询复杂度:

text
O(log n)

而不是:

text
O(n)

五、QuadTree(地图常用)

地图系统很常见:

text
QuadTree

原理:

text
空间递归四分

示意:

+--------+
|        |
|   +----+----+
|   |    |    |
|---+----+----|
|   |    |    |
|   +----+----+

每个节点分成:

text
4 个象限

优点:

text
实现简单

很多地图:

text
tile

本质就是:

text
QuadTree

六、KD-Tree(最近邻搜索)

如果问题是:

text
找最近的点

通常使用:

text
KD-Tree

原理:

text
交替按 x / y 分割

示例:

x < 50
      \
       y < 30

适合:

text
Nearest Neighbor

七、前端如何实现空间索引

前端一般不会自己写 R-Tree。

常见库:

rbush

非常流行。

javascript
import RBush from "rbush"

const tree = new RBush()

tree.insert({
  minX: 10,
  minY: 20,
  maxX: 10,
  maxY: 20,
  id: "point1"
})

查询:

javascript
tree.search({
  minX: 0,
  minY: 0,
  maxX: 50,
  maxY: 50
})

复杂度:

text
O(log n)

八、GIS 系统真实架构

大型地图系统通常:

text
前端

VectorTile

TileServer

PostGIS

数据库层:

text
GIST Index

例如:

sql
CREATE INDEX idx_geom
ON points
USING GIST(geom)

查询:

sql
ST_Intersects

九、前端真实应用场景

空间索引常见用途:

1 点击地图选点

text
click → nearest point

2 框选查询

text
bbox search

3 聚合算法

text
cluster

4 碰撞检测

例如:

text
label collision

十、空间索引怎么实现?

空间索引主要用于优化 GIS 数据查询,因为空间数据是二维或三维的,普通 B-Tree 只能处理一维数据,所以 GIS 通常使用多维索引结构,比如 R-Tree、QuadTree 或 KD-Tree。

其中 R-Tree 是最常见的,它通过 Minimum Bounding Rectangle 对空间对象进行分组,形成层级树结构。查询时只需要遍历与查询范围相交的节点,从而将复杂度从 O(n) 降低到 O(log n)。

在地图系统中,QuadTree 常用于瓦片地图划分,而 KD-Tree 更适合最近邻搜索。

在前端实现中,一般会使用 rbush 这样的库构建 R-Tree 索引,用于快速实现点击选点、框选查询或点位聚合等功能。