当前位置: 首页 > news >正文

Java 实现 Redis中的GEO数据结构

Java 实现 Redis中的GEO数据结构

LBS (基于位置信息服务(Location-Based Service,LBS))应用访问的数据是和人

或物关联的一组经纬度信息,而且要能查询相邻的经纬度范围,GEO 就非常适合应用在

LBS 服务的场景中


import java.util.ArrayList;
import java.util.List;

// 定义一个表示地理位置的类,用于存储地理位置的相关信息
public class GeoLocation {
    // 成员名称,用于标识这个地理位置,比如某个地点的名称
    private String member;
    // 地理位置的经度
    private double longitude;
    // 地理位置的纬度
    private double latitude;

    // 构造函数,用于初始化 GeoLocation 对象
    // 参数 member 为成员名称,longitude 为经度,latitude 为纬度
    public GeoLocation(String member, double longitude, double latitude) {
        this.member = member;
        this.longitude = longitude;
        this.latitude = latitude;
    }

    // 获取成员名称的方法
    public String getMember() {
        return member;
    }

    // 获取经度的方法
    public double getLongitude() {
        return longitude;
    }

    // 获取纬度的方法
    public double getLatitude() {
        return latitude;
    }
}

// 定义一个用于计算两个地理位置之间距离的工具类
 class GeoDistanceCalculator {
    // 地球的平均半径,单位为千米,在计算距离时会用到
    private static final int EARTH_RADIUS = 6371;

    // 静态方法,使用 Haversine 公式计算两个经纬度之间的距离
    // 参数 lat1 和 lon1 是第一个地点的纬度和经度
    // 参数 lat2 和 lon2 是第二个地点的纬度和经度
    public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        // 计算两个纬度之间差值的弧度
        double dLat = Math.toRadians(lat2 - lat1);
        // 计算两个经度之间差值的弧度
        double dLon = Math.toRadians(lon2 - lon1);

        // 将第一个地点的纬度转换为弧度
        lat1 = Math.toRadians(lat1);
        // 将第二个地点的纬度转换为弧度
        lat2 = Math.toRadians(lat2);

        // Haversine 公式的一部分,用于计算球面距离
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
        // 计算反三角函数,得到球面距离的弧度值
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        // 最终距离等于地球半径乘以弧度值
        return EARTH_RADIUS * c;
    }
}

// 定义一个模拟 Redis Geo 数据结构的类,用于管理地理位置信息


 class GeoDataStructure {
    // 用于存储所有地理位置信息的列表
    private List<GeoLocation> locations;

    // 构造函数,初始化存储地理位置信息的列表
    public GeoDataStructure() {
        this.locations = new ArrayList<>();
    }

    // 向数据结构中添加一个新的地理位置信息
    // 参数 member 为成员名称,longitude 为经度,latitude 为纬度
    public void addLocation(String member, double longitude, double latitude) {
        // 创建一个新的 GeoLocation 对象
        GeoLocation location = new GeoLocation(member, longitude, latitude);
        // 将新的地理位置信息添加到列表中
        locations.add(location);
    }

    // 根据给定的经纬度和距离范围,查找附近的成员
    // 参数 longitude 和 latitude 是查询的中心点的经度和纬度
    // 参数 distance 是查询的距离范围,单位为千米
    public List<String> findNearbyMembers(double longitude, double latitude, double distance) {
        // 用于存储附近成员名称的列表
        List<String> nearbyMembers = new ArrayList<>();
        // 遍历所有存储的地理位置信息
        for (GeoLocation location : locations) {
            // 计算当前地理位置与查询中心点之间的距离
            double dist = GeoDistanceCalculator.calculateDistance(latitude, longitude,
                    location.getLatitude(), location.getLongitude());
            // 如果计算出的距离小于等于查询的距离范围
            if (dist <= distance) {
                // 将该地理位置的成员名称添加到附近成员列表中
                nearbyMembers.add(location.getMember());
            }
        }
        // 返回附近成员列表
        return nearbyMembers;
    }
}

// 测试 GeoDataStructure 类功能的测试类
 class GeoDataStructureTest {
    public static void main(String[] args) {
        // 创建一个 GeoDataStructure 对象,用于管理地理位置信息
        GeoDataStructure geoData = new GeoDataStructure();

        // 向 GeoDataStructure 对象中添加一些地理位置信息
        // 这里添加了三个地点,分别是 place1、place2 和 place3
        geoData.addLocation("place1", 116.4074, 39.9042);
        geoData.addLocation("place2", 121.4737, 31.2304);
        geoData.addLocation("place3", 113.2644, 23.1291);

        // 定义查询的中心点的经度
        double targetLongitude = 116.4074;
        // 定义查询的中心点的纬度
        double targetLatitude = 39.9042;
        // 定义查询的距离范围,单位为千米
        double searchDistance = 10000;

        // 调用 findNearbyMembers 方法,查找附近的成员
        List<String> nearbyMembers = geoData.findNearbyMembers(targetLongitude, targetLatitude, searchDistance);
        // 输出附近的成员名称列表
        System.out.println("附近的地点: " + nearbyMembers);
    }
}

相关文章:

  • 基于 Python 和 OpenCV 的酒店客房入侵检测系统设计与实现
  • 服务网格(Istio)核心概念与关键知识点
  • Redis未授权访问漏洞导致getshell
  • 解锁机器学习核心算法 | 决策树:机器学习中高效分类的利器
  • 八、SPI读写XT25数据
  • 【Java进阶篇】——第9篇:Lambda表达式与Stream API
  • 【深度学习】计算机视觉(CV)-目标检测-Faster R-CNN —— 高精度目标检测算法
  • SpringBoot速成(12)文章分类P15-P20
  • QT 读写锁
  • linux常用命令大全(包括抓包、网络检测、路由等,做项目一点点总结而来!)
  • 请解释设备像素、CSS 像素、设备独立像素、DPR、PPI 之间的区别?
  • 【Agent的革命之路——LangGraph】工作流中的 map-reduce 模式
  • 【力扣】98.验证搜索二叉树
  • 线性表之顺序表
  • 《LeetCode 763. 划分字母区间 | 高效分割字符串》
  • linux-5.10.110内核源码分析 - bcm2711 pcie BAR地址分配
  • 牛客寒假训练营3
  • 芯片引脚描述或电路原理图中的Ipd、Ipu是什么意思?
  • fps武器系统6:随机弹道
  • vLLM专题(四)-故障排除
  • 电影路演,虚幻狂欢?
  • 政策一视同仁引导绿色转型,企业战略回应整齐划一?
  • 著名军旅作家、文艺评论家周政保逝世,享年77岁
  • 习近平结束对俄罗斯国事访问并出席纪念苏联伟大卫国战争胜利80周年庆典回到北京
  • 交涉之政、交涉之学与交涉文献——《近代中外交涉史料丛书》第二辑“总序”
  • 第四轮伊美核谈判将于11日在阿曼举行