在Java中利用GeoHash实现高效的‘附近xxx‘功能

news2024/12/25 12:33:07

GeoHash的介绍

GeoHash是一种高效的地理编码系统,它通过将地球表面划分为网格并用字母数字组合的字符串来表示每个区域。
这种编码方法将二维的经纬度坐标转换为一维的字符串,使得地理位置的存储和检索变得更加简单。GeoHash的核心原理是将经纬度坐标转换为二进制,然后交替取位组合,最后转换为base32编码。这种方法的一个重要特性是,相邻区域通常会有相同的GeoHash前缀,这使得它非常适合用于快速查找附近位置。GeoHash字符串的长度决定了编码的精度,越长越精确,例如6位GeoHash可以精确到约1.2公里,而10位可以精确到2.4米。
简单来说,GeoHash就是将某个地点的地理位置转换成可以比较可以排序的唯一字符串

功能分析

在这里插入图片描述

通常我们在实现发现附近xxx功能的时候,需要统计我们当前所在地点附近终端的数量或者具体的地理位置。以共享单车举例子,当我们在A地点的时候通过APP可以看到附近200米的所存在的共享单车的数量以及每辆单车的具体位置,然后就可以根据地图的定位过去寻找车辆了。这个时候我们只需要通过A地点的GeoHash字符串进行模糊匹配,找到相关区域的所有车辆然后再根据200米距离的限制就可以实现发现附近共享单车的功能了。

Java代码实现

写个小DEMO来实现这个功能

首先引入GeoHash的相关依赖

<dependency>
    <groupId>ch.hsr</groupId>
    <artifactId>geohash</artifactId>
    <version>1.4.0</version>
</dependency>

写一个方法获取给定位置的GeoHash及其相邻区域的方位

    public List<String> neighbour(float longitude, float latitude, int length) {

        List<String> geoHashes = Lists.newArrayList();
        if (length == 0 || (longitude == 0 && latitude == 0)) {
            return geoHashes;
        }
        GeoHash geoHash = GeoHash.withCharacterPrecision(latitude, longitude, length);
        geoHashes.add(geoHash.toBase32());
        GeoHash[] neighbourArray = geoHash.getAdjacent();
        for (GeoHash child : neighbourArray) {
            geoHashes.add(child.toBase32());
        }
        return geoHashes;
    }

传入参数:经度、纬度和GeoHash的精度

这里解释一下GeoHash的精度:
GeoHash使用base32编码(32个字符),每增加一个字符,精度就会提高。

  • 1个字符:约 5,000km × 5,000km
  • 2个字符:约 1,250km × 625km
  • 3个字符:约 156km × 156km
  • 4个字符:约 39.1km × 19.5km
  • 5个字符:约 4.89km × 4.89km
  • 6个字符:约 1.22km × 0.61km
  • 7个字符:约 153m × 153m
  • 8个字符:约 38.2m × 19.1m
  • 9个字符:约 4.77m × 4.77m

再解释一下方位:
在GeoHash系统中,方位指的是相对于中心GeoHash的周围8个相邻区域的位置。这8个方位形成了一个3x3的网格,中心是我们关注的GeoHash

NW | N | NE
---+---+---
W | C | E
---+---+---
SW | S | SE

通过知道相邻区域的方位,我们可以快速扩展搜索范围,而不需要重新计算整个区域的GeoHash。同时GeoHash有一个特性,就是相邻的地理位置可能会有完全不同的GeoHash编码。

举个例子:
假设有两家咖啡店

  • 一家在城市的东边(编码为 E999)
  • 另一家在城市的西边(编码为 W001)

这两家店实际上可能只隔着一条街,非常近,但是这条街就是中轴线将城市的东西边划分开来。如果有人站在东边的咖啡店门口,想找附近的咖啡店。
他们使用一个只基于编码前缀的搜索系统(类似于简单的GeoHash搜索)。
系统可能会搜索所有以 “E99” 开头的地点。这个搜索会找到东边(E区)的许多咖啡店。但它可能会完全忽略那家就在街对面、编码完全不同(W001)的咖啡店。所以使用方位寻找各个方向的门店,以防止出现边界问题。

通过数据库中根据每条数据的geohash进行过滤

List<String> geoHashList = GeoHashUtil.neighbour(Point.getLongitude(), 
                                Point.getLatitude(), DistanceEunm.TWOHUNDRED.getLength());

 String geoHashSql = "(";
            for (int i = 0; i < geoHashList.size(); i++) {
                if (i > 0) {
                    geoHashSql += " or ";
                }
                geoHashSql += " geohash LIKE '" + geoHashList.get(i) + "%' ";
            }
            geoHashSql += ")";

String filtersql = "ST_Distance_Sphere(POINT(bike_table.longitude, bike_table.latitude), " +
                   "POINT(?, ?)) < 200 AND " + geoHashSql;

// 使用参数化查询来执行 SQL
bikeservice.getBikeList(filtersql, Point.getLongitude(), Point.getLatitude());

执行的SQL

SELECT 
    ID,
	ST_Distance_Sphere ( POINT ( bike_table.longitude, bike_table.latitude ), POINT ( longitude, latitude ) ) AS distance 
FROM
	bike_table 
WHERE
	ST_Distance_Sphere ( POINT ( bike_table.longitude, bike_table.latitude ), POINT ( longitude, latitude ) ) < 200 
	AND (
		geohash LIKE'ws0e%' 
		OR geohash LIKE'ws0s%' 
		OR geohash LIKE'ws0u%' 
		OR geohash LIKE'ws0g%' 
		OR geohash LIKE'ws0f%' 
		OR geohash LIKE'ws0d%' 
		OR geohash LIKE'ws06%' 
		OR geohash LIKE'ws07%' 
		OR geohash LIKE'ws0k%' 
	)

最后就能得到相关车辆的ID以及与当前位置的距离了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1960622.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

后端开发工程师vue2初识的学习

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;JavaWeb关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 什么是Vue&#xff1f; Vue &#xff08;通常指 Vue.js&#xff09;是一个用…

权限管理的概述以及vue开发前端的路由、菜单、按钮权限控制实现方案

1. 权限管理概念 1.1 权限定义 权限管理是确保用户只能访问被授权资源的机制。在计算机系统中&#xff0c;权限通常指对特定数据或功能的访问权。权限的设置和控制对于保护数据安全和系统安全至关重要。 1.2 前端权限控制重要性 前端权限控制是用户与应用交互的第一道防线。…

超级好用的免费在线流程图软件

超级好用的免费在线流程图软件 Draw io 是一款免费开源的流程图绘制工具&#xff0c;可在浏览器中使用或下载安装。它提供了简单易用的界面和丰富的图形元素&#xff0c;支持创建各种类型的流程图、组织结构图、网络图等。Draw io 支持导入和导出多种格式&#xff0c;包括 PDF…

从零开始,快速打造API:揭秘 Python 库toapi的神奇力量

在开发过程中&#xff0c;我们常常需要从不同的网站获取数据&#xff0c;有时候还需要将这些数据转化成API接口提供给前端使用。传统的方法可能需要大量的时间和精力去编写代码。但今天我要介绍一个神奇的Python库——toapi&#xff0c;它可以让你在几分钟内创建API接口&#x…

数据库练习——处理表

新建数据库 mysql> create database mydb15_indexstu; Query OK, 1 row affected (0.00 sec)mysql> use mydb15_indexstu; Database changed 新建表 建立student表 mysql> create table student(Sno int primary key auto_increment,-> Sname varchar(30) not …

社区团购系统搭建开发,前端uniapp。社区团购搭建开发定制

目录 前言&#xff1a; 一、社区团购系统有哪些功能&#xff1f; 二、社区团购管理端 三、社区团购的基本流程如下&#xff1a; 总结 &#xff1a; 前言&#xff1a; 社区团购是一种以社区为单位进行的集体购物模式。这种模式利用了互联网平台来组织同一社区内的居民一起购…

Linux I/O 体系结构与访问设备

I/O 体系结构 与外设的通信通常称之为输入输出&#xff0c;一般都缩写为I/O。 在实现外设的I/O时&#xff0c;内核必须处理3个可能出现的问题&#xff1a; &#xff08;1&#xff09;必须根据具体的设备类型和模型&#xff0c;使用各种方法对硬件寻址&#xff1b; &#xff08…

26.x86游戏实战-寻找公共call

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 工具下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1rEEJnt85npn7N38Ai0_F2Q?pwd6tw3 提…

KeePass密码管理工具部署

KeePass密码管理工具部署 安装包下载入口 双击执行&#xff0c;根据提示完成安装&#xff1a; 安装完成后如图&#xff1a;

RCE和php文件上传

一、远程命令执行&#xff08;RCE&#xff09; RCE漏洞概述 RCE漏洞允许攻击者通过某种方式在目标服务器上执行任意命令。这种漏洞通常出现在服务器端语言中&#xff0c;如PHP。 RCE漏洞原理 PHP中的一些函数可以执行命令或代码&#xff0c;但如果对这些函数的输入未加限制&a…

Java并发(十五)Java并发工具类

CountDownLatch 字面意思为 递减计数锁。用于控制一个线程等待多个线程。 **CountDownLatch**** 维护一个计数器 count&#xff0c;表示需要等待的事件数量。**countDown 方法递减计数器&#xff0c;表示有一个事件已经发生。调用 await 方法的线程会一直阻塞直到计数器为零&a…

程序员如何准备既符合“八股文“又展现实力的面试?

在当今竞争激烈的IT行业中,面试已成为程序员求职路上的一道重要关卡。而在这个过程中,"八股文"这个词频频出现,引发了业内人士的热议。本文将深入探讨"八股文"在程序员面试中的角色,以及它对实际工作的影响。 目录 1. 程序员面试八股文的利弊分析什么是&q…

Unity 预制动态绑定光照贴图遇到变白问题

预制绑定光照贴图&#xff0c;网上解决方案很多&#xff0c;已下是要点&#xff1a; //烘培完场景之后&#xff0c;保存光照贴图信息 void StoreLightmapData() {lightMap.Clear();LightmapData[] lds LightmapSettings.lightmaps;foreach (LightmapData data in lds){Custom…

无人机之科学防汛篇

随着全球气候变化的加剧&#xff0c;极端天气时间频发&#xff0c;汛期防汛工作面临着前所未有的挑战。传统的防汛手段&#xff0c;如人工巡堤、地面监测等&#xff0c;在复杂多变的自然环境下显得力不从心。而无人机技术的快速发展&#xff0c;为科学防汛提供了新的解决方案。…

Java面试八股之Spring AOP 和 AspectJ AOP 的区别

Spring AOP 和 AspectJ AOP 的区别 Spring AOP 和 AspectJ AOP 是两种不同的面向切面编程&#xff08;Aspect-Oriented Programming, AOP&#xff09;实现。它们各有特点&#xff0c;适用于不同的场景。下面是一些主要的区别&#xff1a; 1. 实现机制 Spring AOP: 基于代理…

Python NLTK 情感分析不正确

1、问题背景 一位 Reddit 用户使用 Python 的 NLTK 库来训练一个朴素贝叶斯分类器以研究其他句子的情感&#xff0c;但是无论输入什么句子&#xff0c;分类器总是预测为正面。 2、解决方案 经过仔细检查&#xff0c;发现原始代码中的问题在于 wordList 为空。因此&#xff0…

【LLM】-12-部署Langchain-Chatchat-0.3.x版本

目录 1、0.3与0.2的功能对比 2、0.3.x支持多种部署方式 2.3、源码安装 2.3.1、项目源码下载 2.3.2、创建conda环境 2.3.3、安装poetry 2.3.4、安装依赖库 2.3.5、项目初始化 2.3.6、初始化知识库 2.3.7、启动服务 2.3.8、配置说明 2.3.8.1、basic_settings.yaml 2…

一副穿戴甲背后,5万苏北宝妈如何硬控全球美甲潮流?

2019年的一天&#xff0c;张达在拼多多后台看到一个有趣的订单。“看姓名、联系方式&#xff0c;像表妹下的订单&#xff0c;但我的穿戴甲店才开第二天&#xff0c;她应该不可能知道。”张达回忆。 1993年出生的张达&#xff0c;是江苏东海县人&#xff0c;当地以水晶闻名。高…

达梦数据库的系统视图v$bufferpool

达梦数据库的系统视图v$bufferpool 达梦数据库系统视图V$BUFFERPOOL的主要作用是监控和管理数据库缓冲池的性能。通过查询V$BUFFERPOOL视图&#xff0c;用户可以获取以下关键信息&#xff1a; 缓存命中率&#xff1a;显示缓冲池的命中率&#xff0c;即从缓冲池中成功获取数据的…

嵌入式☞第二组(壹)

C语言基础: 循环的构成&#xff1a; 循环体 循环条件 循环的分类&#xff1a; 无限循环&#xff1a;程序设计中尽量避免无限循环。(程序中的无限循环必须可控) 有限循环&#xff1a;循环限定循环次数或者循环的条件。 当型循环的实现&#xff1a; while 语法 while(循…