Hilbert 曲线

问题

一POI(Point of Interest)数据库每天都有增量的数据更新进来,对每个新增的poi必须进行dedup(去重)。即在已有库中查找是否有匹配的poi。

解决

找是否匹配的POI,当然不可能把所有的数据(几千万的点)全部取出来一一匹配。所以通用的做法是按距离进行过滤,只取当前点一定范围内的点。这是一个典型的空间索引的问题(Spatial index)。 空间索引有R-Tree, Grid Index, Quad-Tree 等。

其中最容易实现的是Grid Index。把给定区域划分固定大小的格子,每个格子一个编号。根据距离过滤如下实现:
  • 对给定目标点,计算目标格子编号
  • 根据距离计算周边格子的编号
  • 取出相应格子内的POI点


批处理的优化

我们每天需要处理的是一批数据。可以做的一个优化是对待处理的数据进行排序,让地理位置相近的点处在队列的相邻位置。这样做的好处是:
  • 数据库端的缓存可能会有好的命中率。前一个(几个)点的查询结果可能被后一个(后几个)用到
  • 查询端可以做一个本地的LRU cache,同样的增加命中率。

地理位置相邻是一个二维坐标,而处理队列的编号是一维。Hilbert Curve 就是一个很好的二维映射一维的曲线,维持了数据的局部性特征。

Hilbert 编号生成 java代码

public class Hilbert {

	static Logger logger = Logger.getLogger(Hilbert.class);

	public static boolean debug = logger.isDebugEnabled();

	static ImmutableMap<String, Pair[][]> hilbert_map = null;
	static {
		hilbert_map = ImmutableMap.of("a", new Pair[][] {
				{ new Pair(0, "d"), new Pair(1, "a") },
				{ new Pair(3, "b"), new Pair(2, "a") } }, "b", new Pair[][] {
				{ new Pair(2, "b"), new Pair(1, "b") },
				{ new Pair(3, "a"), new Pair(0, "c") } }, "c", new Pair[][] {
				{ new Pair(2, "c"), new Pair(3, "d") },
				{ new Pair(1, "c"), new Pair(0, "b") } }, "d", new Pair[][] {
				{ new Pair(0, "a"), new Pair(3, "c") },
				{ new Pair(1, "d"), new Pair(2, "d") } });
	}

	/**
	 * Our x and y coordinates, then, should be normalized to a range of 0 to
	 * 2order-1
	 * 
	 * @param x
	 * @param y
	 * @param order
	 *            An order 1 curve fills a 2x2 grid, an order 2 curve fills a
	 *            4x4 grid, and so forth.
	 * @return
	 */
	public static long xy2d(int x, int y, int order) {
		String current_square = "a";
		long position = 0;
		int quad_x = 0;
		int quad_y = 0;
		int quad_position = 0;
		for (int i = order - 1; i >= 0; i--) {
			position <<= 2;
			quad_x = (x & (1 << i)) > 0 ? 1 : 0;
			quad_y = (y & (1 << i)) > 0 ? 1 : 0;

			Pair p = hilbert_map.get(current_square)[quad_x][quad_y];
			quad_position = p.no;
			current_square = p.square;
			position |= quad_position;
		}

		return position;
	}

	static int SCALE_FACTOR = (int) 1e5;
	static int hibert_order = 1;

	static double max_length = 1.5;

	static {
		int Max = (int) (max_length * SCALE_FACTOR);

		int size = 1;
		while (size < Max) {
			size <<= 1;
			hibert_order++;
		}
	}
	
	static class Pair {
		int no = 0;
		String square;

		Pair(int no, String square) {
			this.no = no;
			this.square = square;
		}
	}
}

http://blog.notdot.net/2009/11/Damn-Cool-Algorithms-Spatial-indexing-with-Quadtrees-and-Hilbert-Curves

Hilbert 分布效果

简单的case
   

实际的case





2012-01-11更新
server 的数据排序比client更有效果,server端已经保证了地理位置相邻的点物理位置也相邻。
insert into us_ta_2 (select * from us_ta_1 order by node_index)






### 关于Hilbert曲线 #### 定义与特点 Hilbert曲线是一种分形曲线,属于空间填充曲线的一种。这种类型的曲线能够遍历给定区域内的每一个位置至少一次,并且保持良好的局部性——即物理上靠近的位置在曲线上也彼此邻近[^1]。 #### 算法实现 创建Hilbert曲线的过程相对较为复杂,涉及到递归操作以及方向变换。下面给出Python版本的简化版Hilbert曲线生成器: ```python def hilbert_curve(n, angle=90): """Generates coordinates of points on a Hilbert Curve.""" def hilbert(side_length, direction, turtle): if side_length == 0: return turtle.right(direction * angle) hilbert(side_length - 1, -direction, turtle) turtle.forward(1) turtle.left(direction * angle) hilbert(side_length - 1, direction, turtle) turtle.forward(1) hilbert(side_length - 1, direction, turtle) turtle.left(direction * angle) turtle.forward(1) hilbert(side_length - 1, -direction, turtle) turtle.right(direction * angle) import turtle as t t.setup(width=800, height=800) pen = t.Turtle() pen.speed('fastest') hilbert(4, 1, pen) t.done() ``` 此代码片段展示了如何利用海龟绘图库绘制简单的希尔伯特曲线图形。实际应用中可能会采用更加高效的迭代方式或其他优化技术来提高性能并减少资源消耗。 #### 应用场景 - **计算几何**: 如前所述,在处理球面点集时,`CGAL::hilbert_sort()` 函数通过运用Hilbert曲线实现了有效的排序机制,从而提高了基于此类数据的操作效率[^3]。 - **数据库索引**: 利用Hilbert曲线优秀的聚集特性可以帮助设计高效的空间索引结构,比如R树及其变体,这有助于加速地理信息系统(GIS)中的查询响应速度。 - **图像压缩**: 借助该曲线的良好覆盖性质,可以在不损失过多质量的前提下减小图片文件大小;同时也有利于视频编码领域内帧间预测环节的工作开展。 - **网络布局规划**: 对于某些特定场合下的通信基站部署或是传感器节点安排等问题而言,合理选用Hilbert曲线作为指导原则之一可获得不错的效果。 #### 数据结构影响 当涉及大量多维数据项之间的关系管理时,借助像Hilbert这样的空间填充曲线来进行预处理往往可以使后续的任务变得更加容易执行。例如,在增量式的几何运算里,预先按照某种形式排列好待处理实体之后再逐一加入目标容器之中,不仅有利于维持较好的访问模式,而且还能促进缓存命中率提升进而间接加快整体流程进展[^4]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FireCoder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值