使用redisTemplate-geo计算经纬度距离

简介

业务中常有需求是计算经纬度之间的距离,redis是使用较多的缓存中间件,正好有关于geo位置计算的api,可以直接拿来用.

redis依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-redisartifactId>
dependency>
redis:
  host: xxx.xxx.xxx.xxx
  port: 36379
  password: xxx
  database: 0
  jedis:
    pool:
      max-idle: 10
      max-wait: 3000
      max-active: 50
      min-idle: 5
  timeout: 30000

demo展示

直接上demo代码

package com.felix.spring_cloud_one.service;

import com.felix.spring_cloud_one.params.SaveGeoPointVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class RedisGeoService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public Object saveGeoPoint(List<SaveGeoPointVO> vos) {
        String city = vos.get(0).getCity();
        Map<String, Point> map;
        map = vos.stream().collect(Collectors.toMap(SaveGeoPointVO::getName, it -> new Point(it.getLgt(), it.getLat())));
        Long add = stringRedisTemplate.opsForGeo().add(city, map);
        return add;
    }

    public Object getGeoPoint(SaveGeoPointVO vo) {
        List<Point> position = getGeoPoint(vo.getCity(), vo.getName());
        return position;
    }

    /**
     * [
     *     {
     *         "x": 120.11999756097794,
     *         "y": 41.079998971862615
     *     }
     * ]
     * @param city
     * @param members
     * @return
     */
    //查找指定key的经纬度信息,可以指定多个member,批量返回
    private List<Point> getGeoPoint(String city, String ... members) {
        List<Point> position = stringRedisTemplate.opsForGeo()
                .position(
                        city,
                        members
                );
        return position;
    }

    /**
     * {
     *     "value": 925.2986,
     *     "metric": "KILOMETERS"
     * }
     */
    //获取一个key下的2个位置点的距离
    public Distance getDistance(String city, String members1, String members2, Metric metric){
        if(Objects.isNull(metric)){
            metric = Metrics.KILOMETERS;
        }
        Distance distance = stringRedisTemplate.opsForGeo().distance(city, members1, members2, metric);
        return distance;
    }

    //redis命令:georadius key 116.405285 39.904989 100 km WITHDIST WITHCOORD ASC
    //根据给定的经纬度返回半径范围内不超过指定距离的元素
    public Object nearByXY(String city, Circle circle, long count){
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                //包含距离
                .includeDistance()
                //包含经纬度
                .includeCoordinates()
                //升序
                .sortAscending()
                .limit(count);

        GeoResults<RedisGeoCommands.GeoLocation<String>> radius = stringRedisTemplate.opsForGeo().radius(city, circle, args);
        return radius;
    }

    /**
     * {
     *     "averageDistance": {
     *         "value": 193.9615,
     *         "metric": "KILOMETERS"
     *     },
     *     "content": [
     *         {
     *             "content": {
     *                 "name": "2",
     *                 "point": {
     *                     "x": 120.11999756097794,
     *                     "y": 41.079998971862615
     *                 }
     *             },
     *             "distance": {
     *                 "value": 120.5517,
     *                 "metric": "KILOMETERS"
     *             }
     *         },
     *         {
     *             "content": {
     *                 "name": "3",
     *                 "point": {
     *                     "x": 117.12000042200089,
     *                     "y": 39.080000053576654
     *                 }
     *             },
     *             "distance": {
     *                 "value": 267.3713,
     *                 "metric": "KILOMETERS"
     *             }
     *         }
     *     ]
     * }
     */
    public Object nearByXY(String city, Double lng, Double lat, double distanceNum, long count){
        Point point = new Point(lng, lat);
        Distance distance = new Distance(distanceNum, Metrics.KILOMETERS);
        Circle circle = new Circle(point, distance);
        Object result = nearByXY(city, circle, count);
        return result;
    }


    //删除
    //GEO数据本质上是放到一个zset集合里了 
	//删除可以用 ZREM key member
    public Boolean deleteByMembers(String city, String... members){
        Long remove = stringRedisTemplate.opsForGeo().remove(city, members);
        return remove.intValue() == members.length;
    }

}

你可能感兴趣的:(springboot,redis,redis,缓存,java)