GeoHash处理经纬度,降维,空间填充曲线

server/2024/11/14 4:40:19/

个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview


参考

https://segmentfault.com/a/1190000042971576

GeoHash原理以及代码实现_geohash编码-CSDN博客

GeoHash代码实现–java_geohash java代码示例-CSDN博客

在线经纬度距离计算

http://geohash.co/

https://geohash.jorren.nl/

简介

Geohash是一种用于标识地理位置的编码方法。它将经纬度坐标转换为一个简短的字符串,这个字符串可以用来表示地球上的任意位置。Geohash的特点是,编码的长度越长,表示的位置就越精确;反之,编码越短,则表示的位置范围就越大。

接下来我们来一起探究一下这是个什么东西,有什么用?

参考的文章讲的也是非常不错,这里就啰嗦整理一下,并引申一下了。

经纬度

首先必须要从经纬度开始,我们都知道为了标记我们在地球上的位置,出现了经纬度,南北方向叫做纬度[-90,90],东西方向是经度[-180,180]。在使用具有定位功能的设备时,通过人造地球卫星就能确定我们在地球上的位置,其使用的都是经纬度

GeoHash

GeoHash是一种地理编码,就是用于处理经纬度的。其原理是使用空间填充曲线—— Z 阶曲线(Z-order curve),在地球表面的经纬度球面坐标系下,划分出许许多多不规则矩形,并将每个矩形进行编码,表示某个经纬度范围的面,本质上就是一种降维打击方案。

image

如果你对hash比较敏感的话,就会联想到计算机科学中还有很多hashJava顶级父类Objecthashcode数据结构hashcode,散列hash算法如:md5hash负载均衡策略,等等。提到这些是为了重复强调一下相比于无序的hash算法GeoHash是有序的,毕竟它存在的意义就是为了降维,降维是将(x,y)表示的二维坐标系的点转换为一条直线上的点,虽然信息丢失是不可避免的,但是保留信息就是降维的重要目的之一。如下图,将平面划分成矩形,并将其串联起来,最终拉成一条直线,其是有序的,信息从(x,y)变为[起点,终点],实现了降维。

image

结论出发一般会有一个很大的问题:放弃思考,不再问为什么?

提出问题往往是进步的开始!

为什么这样的曲线是可行?空间填充曲线都有什么特点?

我并不能回答所有相关问题,但至少可以知道这样的曲线一定是可微分的,也就是能通过数学表达式表示的。而且其还能一定程度上的转换二维信息,比如:二维坐标系下很重要的距离问题,在降维后通过大小就能判断。

实现原理

经纬度GeoHash

1、经纬度,按照[-90,90][-180,180]逐渐二分,在左区间为0,在右区间为1,得到二进制编码,具体要得到多少位的二进制,看选取的精度,5位二进制对应1位GeoHash

2、合并经纬度,偶数位放经度,奇数位放纬度,注意第一位是0,放偶数,简单理解,经度纬度经度纬度…叠加

3、每5位对应以为base32编码,转译一下就得到了GeoHash编码

GeoHash经纬度

反之即可,只是GeoHash代码的是一块区域,转换后的经纬度是区域的中心点的经纬度

image

参考网站:

http://geohash.co/

https://geohash.jorren.nl/

局限性

GeoHash是有序的,但本质上都是从二维平面到曲线,无论如何都是会丢失信息的。

边界问题

很容易理解,所有的区域划分问题都会存在这样的问题,如下图,相比如参考点,明显红点更近一些,但是通过GeoHash编码,结论就是绿色的点更近。

通常的解决方案是除了本身区域还要使用周围的相邻区域辅助判断计算。

image

非线性问题

要知道我们讨论的是地球这个三维球体的表面,抛开地球本身就是不规则球体不讲,就算是规则,肯定不能完全套用在球面上吧,这本身就不是矩形啊。球面距离公式也不是简单平方差开根号的吧。0纬度的赤道移动一个经度和30纬度移动一个经度差别也是可想而知的。

球面的必然问题

这是不可避免的问题,还是和前面一样的原因,我们目标是球面,其是无边的!

因为我们经纬度的划分规则,体现在了经度上,-180180是一样的一条线。

GeoHash是无法理解-179179是相近的。

image

意义

尽管GeoHash具有一些局限性,但是在现实中还是有很多用处的。

顺带一讲,Redis中的Geo也有使用GeoHash哦!

1、附近,在使用某些带有地图功能的软件时,查找附近距离最近的xxx,有可能就用到了GeoHash哦,原因也很简单,GeoHash极大的加快了检索速度,相比如球面距离计算可想而知对比一串字符串要简单的多。

2、聚集,想要统计某片区域有多少用户,就可以利用GeoHash经纬度编码,然后取不同位数,做不同精度的统计。

代码实现

下面是优化了性能的代码实现,其中使用了一些位运算,不过效果是一致的。

public class GeoHash {/*** geoHash 32位*/private static final char[] BASE32 = {'0', '1', '2', '3', '4', '5', '6', '7','8', '9', 'b', 'c', 'd', 'e', 'f', 'g','h', 'j', 'k', 'm', 'n', 'p', 'q', 'r','s', 't', 'u', 'v', 'w', 'x', 'y', 'z'};/*** 纬度范围*/private static final double MIN_LAT = -90.0, MAX_LAT = 90.0;/*** 经度范围*/private static final double MIN_LON = -180.0, MAX_LON = 180.0;/*** 将给定的纬度和经度编码为GeoHash字符串,指定精度。** @param latitude  纬度[-90,90]* @param longitude 经度[-180,180]* @param precision 精度[1,12]* @return GeoHash字符串*/public static String encode(double latitude, double longitude, int precision) {if (latitude < MIN_LAT || latitude > MAX_LAT || longitude < MIN_LON || longitude > MAX_LON) {throw new IllegalArgumentException("Latitude and longitude must be within valid ranges.");}if (precision <= 0 || precision > 12) {throw new IllegalArgumentException("precision must between 1 and 12");}long geoHashBits = 0;boolean isEven = true;double minLat = MIN_LAT, maxLat = MAX_LAT;double minLon = MIN_LON, maxLon = MAX_LON;int bitIndex = 0;// 每个字符代表5位二进制数int requiredBits = precision * 5;while (bitIndex < requiredBits) {double midValue;if (isEven) {midValue = (minLon + maxLon) / 2;if (longitude > midValue) {geoHashBits |= (1L << (requiredBits - bitIndex - 1));minLon = midValue;} else {maxLon = midValue;}} else {midValue = (minLat + maxLat) / 2;if (latitude > midValue) {geoHashBits |= (1L << (requiredBits - bitIndex - 1));minLat = midValue;} else {maxLat = midValue;}}isEven = !isEven;bitIndex++;}return bitsToBase32(geoHashBits, precision);}/*** 将给定的二进制位转换为GeoHash字符串。** @param bits      二进制位* @param precision 精度* @return GeoHash字符串*/private static String bitsToBase32(long bits, int precision) {char[] base32Chars = new char[precision];for (int i = 0; i < precision; i++) {// Extract 5 bitsint index = (int) ((bits >>> (i * 5)) & 0x1F);base32Chars[precision - i - 1] = BASE32[index];}return new String(base32Chars);}/*** 将给定的经度和纬度转换为7位GeoHash字符串。** @param latitude  纬度[-90,90]* @param longitude 经度[-180,180]* @return GeoHash字符串*/public static String geoHash7(double latitude, double longitude) {return encode(latitude, longitude, 7);}public static void main(String[] args) {long start = System.currentTimeMillis();// GeoHash 字符串长度int precision = 9;//30.2549529076, 120.1646161079System.out.println(encode(30.2549958229, 120.1647019386, precision));System.out.println(geoHash7(30.2549958229, 120.1647019386));System.out.println("耗时:" + (System.currentTimeMillis() - start));}
}

总结

说到降维,立刻就想到了前几年看的一个视频《一种降维打击的可视化方案》。

https://player.bilibili.com/player.html?bvid=BV1Sf4y147J9&autoplay=0

数学就是基础学科之王,人类进步的重要动力。

不得不说近现代文明是欧美人主导的,而至今欧美人的创造力还是领先的。很早之前我也发过一篇文章,大概有一个结论,基础学科教育无比重要,创新是发展的重要动力。

当未来越来越多的杨辉三角、王氏悖论、华氏定理、杨x材料、张x曲线、宋x射线出来就好了!

写在最后

拙作艰辛,字句心血,望诸君垂青,多予支持,不胜感激。


个人博客:无奈何杨(wnhyang)

个人语雀:wnhyang

共享语雀:在线知识共享

Github:wnhyang - Overview


http://www.ppmy.cn/server/141009.html

相关文章

NLP之ASR之moonshine:moonshine的简介、安装和使用方法、案例应用之详细攻略

NLP之ASR之moonshine&#xff1a;moonshine的简介、安装和使用方法、案例应用之详细攻略 目录 moonshine的简介 moonshine的安装和使用方法 1、安装 推荐使用uv管理Python环境 安装Moonshine包 Torch后端 TensorFlow后端 JAX后端 ONNX运行时 2、使用方法 0、测试 1…

Android下的系统调用 (syscall),内联汇编syscall

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 什么是系统调用 (syscall) 系统调用是操作系统提供给应用程序的一组接口&#xff0c;允许用户空间程序与内核进行交互。 在 Android&#xff08;基于 Linux …

华硕推出Intel Xeon 6/ Gaudi 3服务器 加速企业AI布局!

(10月23日&#xff0c;台北讯) 华硕服务器新品接力强势助攻&#xff0c;今再推出多款搭载Intel Xeon 6处理器的服务器&#xff0c;包括&#xff1a;多节点的ASUS RS920Q-E12&#xff0c;其兼容适用HPC运算的Intel Xeon 6900系列处理器&#xff1b;以及ASUS RS720Q-E12、RS720-E…

一篇文章解释AI中的“算力”与“数据”两个概念!

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、什么是算力?为什么算力重要?算力的发展历程什么是数据?数据的作用数据的应用场景算力与数据的关系总结前言 为什么我要特别讲这两个词呢?因为人工智能的核心其实就是三件事儿:算力、…

「QT」几何数据类 之 QPolygon 多边形类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…

计算机的错误计算(一百五十)

摘要 探讨 MATLAB 中 的计算精度问题。当 为含有小数的大数或 &#xff08;&#xff09;附近数时&#xff0c;输出会有错误数字。 例1. 已知 计算 直接贴图吧&#xff1a; 另外&#xff0c;16位的正确值分别为 -0.7882256119904400e0、0.1702266977524110e0、-0.…

Redis的缓存问题与应对策略

Redis 作为一种高效的缓存系统&#xff0c;在高并发环境下应用广泛&#xff0c;但也面临一些缓存问题&#xff0c;以下是常见问题及其应对策略。 1. 缓存穿透 问题描述 缓存穿透是指请求的数据在缓存和数据库中都不存在&#xff0c;但大量请求直接到达数据库&#xff0c;从而给…

JavaSecLab靶场搭建

下载地址 whgojp/JavaSecLab: ​ JavaSecLab是一款综合型Java漏洞平台&#xff0c;提供相关漏洞缺陷代码、修复代码、漏洞场景、审计SINK点、安全编码规范&#xff0c;覆盖多种漏洞场景&#xff0c;友好用户交互UI…… (github.com) 安装流程 git clone https://github.com/…