RedisGeo实现增删改查 java计算指定坐标最近的距离并排序

利用Redis的Geo功能实现查找附近的位 - 云+社区 - 腾讯云

package com.easy.hotel.pms.util;import com.easy.hotel.common.data.tenant.TenantContextHolder;
import com.easy.hotel.pms.mapper.CommunityMapper;
import com.easy.hotel.pms.service.impl.CommunityServiceImpl;
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.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import java.util.ArrayList;
import java.util.List;/***/
@Component
public class RedisGeoUntil {@Autowiredprivate  RedisTemplate redisTemplate;//communicode+租户号public static String redisKeyCommunityCode = "REDIS_GEO_COMMUNITY_CODE:";//communicode+用户IDpublic static String redisGeoUserCommunity = "REDIS_GEO_USER_COMMUNITY:";public static  String getRedisKey(){//区分租户的Long tenantId = TenantContextHolder.getTenantId();String redisKey =  RedisGeoUntil.redisKeyCommunityCode + tenantId;return 	redisKey;}/*新增   修改和新增是一样的*/public void insertRedisGeo(String redisKey , Double longitudeX,Double latitudeY,String code){//增加(添加经纬度信息)//Point的属性值,x轴是经度longitude,y轴是纬度latitude。Point point  = new Point(longitudeX,latitudeY);Long addedNum = redisTemplate.opsForGeo().add(redisKey,point,code);System.out.println(addedNum);}/*删除*/public void deleteRedisGeo(String redisKey , String code){//删除//redisTemplate.opsForZSet().remove(redisKey,"hangzhou ");Long remove = redisTemplate.boundZSetOps(redisKey).remove(code);System.out.println(remove);}/*修改  不用删除    修改和新增是一样的*/public void updateRedisGeo(String redisKey, Double longitudeX,Double latitudeY , String code){//修改(先删除再新增)//deleteRedisGeo(  redisKey ,   code);insertRedisGeo(  redisKey ,   longitudeX,  latitudeY,  code);System.out.println();}/*查询多个*/public List<Point> getRedisGeoList(String redisKey , List<String> codeList) {List<Point> pointList = new ArrayList<>();for(int i = 0 ; i < codeList.size();i++){Point redisGeo = getRedisGeo(redisKey, codeList.get(i));if(redisGeo != null){pointList.add(redisGeo);}}System.out.println(pointList);return pointList;}/*查询单个*/public Point getRedisGeo(String redisKey , String code) {//查询可以查询多个 经纬度List<Point> pointsAll = redisTemplate.opsForGeo().position(redisKey,code);System.out.println(pointsAll);if(!CollectionUtils.isEmpty(pointsAll)){return pointsAll.get(0);}return null;}/*** 计算指定点 5km内的(MaxInteger KM)*/public GeoResults<RedisGeoCommands.GeoLocation<String>> getRedisGeoMaxIntegerKm(String redisKey   , String  code) {Distance disFiveKmFive = new Distance(Integer.MAX_VALUE, Metrics.KILOMETERS);RedisGeoCommands.GeoRadiusCommandArgs argsFiveKmFive = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(Integer.MAX_VALUE);GeoResults<RedisGeoCommands.GeoLocation<String>> resultsFiveKmFive = redisTemplate.opsForGeo().radius(redisKey,code,disFiveKmFive,argsFiveKmFive);System.out.println(resultsFiveKmFive);return  resultsFiveKmFive;}/*** //中心点设置  某个经纬度算距离*/public GeoResults<RedisGeoCommands.GeoLocation<String>> getRedisGeoMaxIntegerKm(String redisKey , Double longitudeX,Double latitudeY ) {//longitude,latitude//中心点设置  某个经纬度算距离Point pointCenter = new Point(longitudeX,latitudeY);Distance distanceCenter = new Distance(Integer.MAX_VALUE, RedisGeoCommands.DistanceUnit.KILOMETERS);Circle circleCenter = new Circle(pointCenter, distanceCenter);RedisGeoCommands.GeoRadiusCommandArgs argsCircle = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(Integer.MAX_VALUE);GeoResults<RedisGeoCommands.GeoLocation<String>> resultsDis = redisTemplate.opsForGeo().radius(redisKey,circleCenter ,argsCircle);System.out.println(resultsDis);return resultsDis;}/*查询单个Hash*/public List<String> getRedisGeoListHash(String redisKey ,  String code) {List<String> resultsHash = redisTemplate.opsForGeo().hash(redisKey,code);System.out.println(resultsHash);return resultsHash;}/*//计算2地之间距离(返回两个地方的距离,可以指定单位,比如米m,千米km,英里mi,英尺ft)*/public Distance getRedisGeoListTwoSpace(String redisKey , String  codeOne,String codeTwo) {Distance disTwoPlace = redisTemplate.opsForGeo().distance(redisKey,codeOne,codeTwo, RedisGeoCommands.DistanceUnit.KILOMETERS);System.out.println(disTwoPlace);return disTwoPlace;}}

package com.easy.hotel.pms.controller;import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easy.hotel.common.core.constant.enums.REnum;
import com.easy.hotel.common.core.util.EmptyUtils;
import com.easy.hotel.common.core.util.R;
import com.easy.hotel.common.data.mybatis.QPage;
import com.easy.hotel.common.data.mybatis.RPage;
import com.easy.hotel.common.data.tenant.TenantContextHolder;
import com.easy.hotel.common.log.annotation.SysLog;
import com.easy.hotel.common.security.annotation.Inner;import com.easy.hotel.pms.api.dto.house.*;
import com.easy.hotel.pms.api.entity.*;
import com.easy.hotel.pms.api.enums.SiteLevelEnum;
import com.easy.hotel.pms.api.enums.UserTypeEnum;import com.easy.hotel.pms.api.vo.UserHouseVo;
import com.easy.hotel.pms.api.vo.house.*;
import com.easy.hotel.pms.service.*;
import com.easy.hotel.pms.service.impl.CommunityServiceImpl;
import com.easy.hotel.pms.util.RedisGeoUntil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
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.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;/*** <p class="detail">* 功能:* </p>** @author cm* @ClassName HouseVo controller.* @Version V1.0.* @date 2019.05.09 14:29:00*/
@RequestMapping("/redisTest")
@RestController
@AllArgsConstructor
@Api(value = "RedisController", tags = "redis房屋Api")
public class RedisGEOController {@Autowiredprivate RedisGeoUntil redisGeoUntil;// 大屏那个先做!!!26号做完  其他的往后延迟一周/*** 获取房屋统计** @param* @return success/false*/@GetMapping("/v2/redisTest")@ApiOperation(value = "redistest获取房屋统计测试-yangjiabin20220412", notes = "获取房屋统计测试-yangjiabin20220412")public R getHouseStatistics() {//Point的属性值,x轴是经度longitude,y轴是纬度latitude。String redisKey =  CommunityServiceImpl.getRedisKey();List<String> codeList = new ArrayList<>();codeList.add("hangzhou1");codeList.add("hangzhou2");codeList.add("hangzhou3");codeList.add("hangzhou4");  // 大屏那个先做!!!26号做完  其他的往后延迟一周codeList.add("hangzhou5");codeList.add("hangzhou6");codeList.add("hangzhou7");codeList.add("hangzhou8");/**/codeList.add("huanlecheng");codeList.add("nanyuan");codeList.add("sd001");codeList.add("tlshehz");codeList.add("bzhhgwjhihe");codeList.add("32414314321");codeList.add("cssq");codeList.add("ertertert");codeList.add("qiaosi");codeList.add("yangjiabinshequ");codeList.add("10011223");codeList.add("xqsq");codeList.add("xqsq001");codeList.add("xqsq002");codeList.add("xqsq003");codeList.add("xqsq004");codeList.add("xqsq005");codeList.add("xqsq11001");codeList.add("xqsq11002");codeList.add("xqsq11003");//查询可以查询多个 经纬度List<Point> redisGeoList0 = redisGeoUntil.getRedisGeoList(redisKey, codeList);//[]//中心点设置  某个经纬度算距离GeoResults<RedisGeoCommands.GeoLocation<String>> redisGeoMaxIntegerKm2 = redisGeoUntil.getRedisGeoMaxIntegerKm(redisKey, 120.206590, 30.233336);GeoResults<RedisGeoCommands.GeoLocation<String>> redisGeoMaxIntegerKm1222 = redisGeoUntil.getRedisGeoMaxIntegerKm(redisKey, "cssq");//增加(添加经纬度信息)redisGeoUntil.insertRedisGeo(redisKey,116.10,19.10,"hangzhou1");redisGeoUntil.insertRedisGeo(redisKey,116.20,19.20,"hangzhou2");
//		redisGeoUntil.insertRedisGeo(redisKey,116.30,19.30,"hangzhou3");
//		redisGeoUntil.insertRedisGeo(redisKey,116.40,19.40,"hangzhou4");
//		redisGeoUntil.insertRedisGeo(redisKey,116.50,19.50,"hangzhou5");
//		redisGeoUntil.insertRedisGeo(redisKey,116.60,19.60,"hangzhou6");//查询可以查询多个 经纬度List<Point> redisGeoList2 = redisGeoUntil.getRedisGeoList(redisKey, codeList);//[Point [x=116.099999, y=19.100000], Point [x=116.199997, y=19.200000], Point [x=116.300001, y=19.299999], Point [x=116.399999, y=19.399999], Point [x=116.500002, y=19.499999], Point [x=116.600001, y=19.599999]]//计算指定点codeGeoResults<RedisGeoCommands.GeoLocation<String>> hangzhou11 = redisGeoUntil.getRedisGeoMaxIntegerKm(redisKey, "hangzhou1");//GeoResults: [averageDistance: 30.5927 KILOMETERS, results: GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou1, point=Point [x=116.099999, y=19.100000]), distance: 0.0 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou2, point=Point [x=116.199997, y=19.200000]), distance: 15.3006 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou3, point=Point [x=116.300001, y=19.299999]), distance: 30.5972 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou4, point=Point [x=116.399999, y=19.399999]), distance: 45.889 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou5, point=Point [x=116.500002, y=19.499999]), distance: 61.1767 KILOMETERS, ]]//删除redisGeoUntil.deleteRedisGeo(redisKey,"hangzhou5");//没事。。。redisGeoUntil.deleteRedisGeo(redisKey,"删除不存在的");//查询可以查询多个 经纬度List<Point> redisGeoList3 = redisGeoUntil.getRedisGeoList(redisKey, codeList);//[Point [x=116.099999, y=19.100000], Point [x=116.199997, y=19.200000], Point [x=116.300001, y=19.299999], Point [x=116.399999, y=19.399999], Point [x=116.600001, y=19.599999]]//修改(和新增一样)redisGeoUntil.updateRedisGeo( redisKey, 116.99,19.99,"hangzhou4");//查询可以查询多个 经纬度List<Point> redisGeoList4 = redisGeoUntil.getRedisGeoList(redisKey, codeList);//[Point [x=116.099999, y=19.100000], Point [x=116.199997, y=19.200000], Point [x=116.300001, y=19.299999], Point [x=116.989999, y=19.990001], Point [x=116.600001, y=19.599999]]//查询单个Point hangzhou1 = redisGeoUntil.getRedisGeo(redisKey, "hangzhou1");//[Point [x=116.099999, y=19.100000]]//查询单个Point hangzhou2 = redisGeoUntil.getRedisGeo(redisKey, "没有这个地址");//[null]//查找一个位置的时间复杂度为 ?? hash值List<String> hangzhou122 = redisGeoUntil.getRedisGeoListHash(redisKey, "hangzhou1");//[we6s9vj3w40]//计算2地之间距离(返回两个地方的距离,可以指定单位,比如米m,千米km,英里mi,英尺ft)Distance redisGeoListTwoSpace = redisGeoUntil.getRedisGeoListTwoSpace(redisKey, "hangzhou1", "hangzhou2");//15.3006 KILOMETERS//longitude,latitude//中心点设置  某个经纬度算距离GeoResults<RedisGeoCommands.GeoLocation<String>> redisGeoMaxIntegerKm = redisGeoUntil.getRedisGeoMaxIntegerKm(redisKey, 126.40, 29.90);//GeoResults: [averageDistance: 1537.1931 KILOMETERS, results: GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou4, point=Point [x=116.989999, y=19.990001]), distance: 1453.0984 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou6, point=Point [x=116.600001, y=19.599999]), distance: 1512.4838 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou3, point=Point [x=116.300001, y=19.299999]), distance: 1558.2093 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou2, point=Point [x=116.199997, y=19.200000]), distance: 1573.4598 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou1, point=Point [x=116.099999, y=19.100000]), distance: 1588.7142 KILOMETERS, ]]//selectRidesPoint(146.40f,49.90f,Integer.MAX_VALUE);//计算指定点 5km内的GeoResults<RedisGeoCommands.GeoLocation<String>> redisGeoMaxIntegerKm12 = redisGeoUntil.getRedisGeoMaxIntegerKm(redisKey, "hangzhou1");//GeoResults: [averageDistance: 51.675599999999996 KILOMETERS, results: GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou1, point=Point [x=116.099999, y=19.100000]), distance: 0.0 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou2, point=Point [x=116.199997, y=19.200000]), distance: 15.3006 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou3, point=Point [x=116.300001, y=19.299999]), distance: 30.5972 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou6, point=Point [x=116.600001, y=19.599999]), distance: 76.4596 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou4, point=Point [x=116.989999, y=19.990001]), distance: 136.0206 KILOMETERS, ]]return  null;}//	private Map<String, Map<String, Double>> selectRidesPoint(float lng, float lat, Integer radius) {
//		String redisLnglatName = redisKey;
//		//中心点设置
//		Point point = new Point(lng, lat);
//		Metric metric = RedisGeoCommands.DistanceUnit.KILOMETERS;
//		Distance distance = new Distance(radius, metric);
//		Circle circle = new Circle(point, distance);
//
//		//redis查询参数配置:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
//		RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
//				.newGeoRadiusArgs()
//				.includeDistance()
//				.includeCoordinates()
//				.sortAscending()
//				.limit(5);
//		GeoResults<RedisGeoCommands.GeoLocation<String>> data = redisTemplate.opsForGeo().geoRadius(redisLnglatName, circle, args);
//		System.out.println("计算circleDis 和 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5 的距离 ");
//		System.out.println(data);
//
//
//
//
//
//
//
//
//
//		//数据封装
//		Map<String, Map<String, Double>> cameraMap = new HashMap<>();
//		if (data != null) {
//			data.forEach(geoLocationGeoResult -> {
//				RedisGeoCommands.GeoLocation<String> content = geoLocationGeoResult.getContent();
//				Map<String, Double> pointMap = new HashMap<>();
//				//member 名称  如  tianjin
//				String name = content.getName();
//				// 对应的经纬度坐标
//				Point pos = content.getPoint();
//				// 距离中心点的距离
//				Distance dis = geoLocationGeoResult.getDistance();
//				pointMap.put("lng", pos.getX());
//				pointMap.put("lat", pos.getY());
//				cameraMap.put(name, pointMap);
//			});
//		}
//		return cameraMap;
//	}}

package com.easy.hotel.pms.util;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.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import java.util.ArrayList;
import java.util.List;/***/
@Component
public class RedisGeoUntil {@Autowiredprivate  RedisTemplate redisTemplate;/*新增*/public void insertRedisGeo(String redisKey , Double longitudeX,Double latitudeY,String code){//增加(添加经纬度信息)//Point的属性值,x轴是经度longitude,y轴是纬度latitude。Point point  = new Point(longitudeX,latitudeY);Long addedNum = redisTemplate.opsForGeo().add(redisKey,point,code);System.out.println(addedNum);}/*删除*/public void deleteRedisGeo(String redisKey , String code){//删除//redisTemplate.opsForZSet().remove(redisKey,"hangzhou5");Long remove = redisTemplate.boundZSetOps(redisKey).remove(code);System.out.println(remove);}/*修改*/public void updateRedisGeo(String redisKey, Double longitudeX,Double latitudeY , String code){//修改(先删除再新增)deleteRedisGeo(  redisKey ,   code);insertRedisGeo(  redisKey ,   longitudeX,  latitudeY,  code);System.out.println();}/*查询多个*/public List<Point> getRedisGeoList(String redisKey , List<String> codeList) {List<Point> pointList = new ArrayList<>();for(int i = 0 ; i < codeList.size();i++){Point redisGeo = getRedisGeo(redisKey, codeList.get(i));if(redisGeo != null){pointList.add(redisGeo);}}System.out.println(pointList);return pointList;}/*查询单个*/public Point getRedisGeo(String redisKey , String code) {//查询可以查询多个 经纬度List<Point> pointsAll = redisTemplate.opsForGeo().position(redisKey,code);System.out.println(pointsAll);if(!CollectionUtils.isEmpty(pointsAll)){return pointsAll.get(0);}return null;}/*** 计算指定点 5km内的(MaxInteger KM)*/public GeoResults<RedisGeoCommands.GeoLocation<String>> getRedisGeoMaxIntegerKm(String redisKey   , String  code) {Distance disFiveKmFive = new Distance(Integer.MAX_VALUE, Metrics.KILOMETERS);RedisGeoCommands.GeoRadiusCommandArgs argsFiveKmFive = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(5);GeoResults<RedisGeoCommands.GeoLocation<String>> resultsFiveKmFive = redisTemplate.opsForGeo().radius(redisKey,code,disFiveKmFive,argsFiveKmFive);System.out.println(resultsFiveKmFive);return  resultsFiveKmFive;}/*** //中心点设置  某个经纬度算距离*/public GeoResults<RedisGeoCommands.GeoLocation<String>> getRedisGeoMaxIntegerKm(String redisKey , Double longitudeX,Double latitudeY ) {//longitude,latitude//中心点设置  某个经纬度算距离Point pointCenter = new Point(longitudeX,latitudeY);Distance distanceCenter = new Distance(Integer.MAX_VALUE, RedisGeoCommands.DistanceUnit.KILOMETERS);Circle circleCenter = new Circle(pointCenter, distanceCenter);RedisGeoCommands.GeoRadiusCommandArgs argsCircle = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(5);GeoResults<RedisGeoCommands.GeoLocation<String>> resultsDis = redisTemplate.opsForGeo().radius(redisKey,circleCenter ,argsCircle);System.out.println(resultsDis);return resultsDis;}/*查询单个Hash*/public List<String> getRedisGeoListHash(String redisKey ,  String code) {List<String> resultsHash = redisTemplate.opsForGeo().hash(redisKey,code);System.out.println(resultsHash);return resultsHash;}/*//计算2地之间距离(返回两个地方的距离,可以指定单位,比如米m,千米km,英里mi,英尺ft)*/public Distance getRedisGeoListTwoSpace(String redisKey , String  codeOne,String codeTwo) {Distance disTwoPlace = redisTemplate.opsForGeo().distance(redisKey,codeOne,codeTwo, RedisGeoCommands.DistanceUnit.KILOMETERS);System.out.println(disTwoPlace);return disTwoPlace;}}

package com.easy.hotel.pms.controller;import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easy.hotel.common.core.constant.enums.REnum;
import com.easy.hotel.common.core.util.EmptyUtils;
import com.easy.hotel.common.core.util.R;
import com.easy.hotel.common.data.mybatis.QPage;
import com.easy.hotel.common.data.mybatis.RPage;
import com.easy.hotel.common.data.tenant.TenantContextHolder;
import com.easy.hotel.common.log.annotation.SysLog;
import com.easy.hotel.common.security.annotation.Inner;import com.easy.hotel.pms.api.dto.house.*;
import com.easy.hotel.pms.api.entity.*;
import com.easy.hotel.pms.api.enums.SiteLevelEnum;
import com.easy.hotel.pms.api.enums.UserTypeEnum;import com.easy.hotel.pms.api.vo.UserHouseVo;
import com.easy.hotel.pms.api.vo.house.*;
import com.easy.hotel.pms.service.*;
import com.easy.hotel.pms.util.RedisGeoUntil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
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.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;/*** <p class="detail">* 功能:* </p>** @author cm* @ClassName House controller.* @Version V1.0.* @date 2019.05.09 14:29:00*/
@RequestMapping("/redisTest")
@RestController
@AllArgsConstructor
@Api(value = "RedisController", tags = "redis房屋Api")
public class RedisController {private final RedisTemplate redisTemplate;//租户号+communicodeprivate static String redisKeyCommunityCode = "REDIS_GEO_COMMUNITY_CODE:";@Autowiredprivate RedisGeoUntil redisGeoUntil;public  String getRedisKey(){Long tenantId = TenantContextHolder.getTenantId();String redisKey = redisKeyCommunityCode+tenantId;return 	redisKey;}/*** 获取房屋统计** @param* @return success/false*/@GetMapping("/v2/redisTest")@ApiOperation(value = "redistest获取房屋统计测试-yangjiabin20220412", notes = "获取房屋统计测试-yangjiabin20220412")public R getHouseStatistics() {//Point的属性值,x轴是经度longitude,y轴是纬度latitude。String redisKey =  getRedisKey();List<String> codeList = new ArrayList<>();codeList.add("hangzhou1");codeList.add("hangzhou2");codeList.add("hangzhou3");codeList.add("hangzhou4");codeList.add("hangzhou5");codeList.add("hangzhou6");codeList.add("hangzhou7");codeList.add("hangzhou8");//查询可以查询多个 经纬度List<Point> redisGeoList0 = redisGeoUntil.getRedisGeoList(redisKey, codeList);//[]//增加(添加经纬度信息)redisGeoUntil.insertRedisGeo(redisKey,116.10,19.10,"hangzhou1");redisGeoUntil.insertRedisGeo(redisKey,116.20,19.20,"hangzhou2");redisGeoUntil.insertRedisGeo(redisKey,116.30,19.30,"hangzhou3");redisGeoUntil.insertRedisGeo(redisKey,116.40,19.40,"hangzhou4");redisGeoUntil.insertRedisGeo(redisKey,116.50,19.50,"hangzhou5");redisGeoUntil.insertRedisGeo(redisKey,116.60,19.60,"hangzhou6");//查询可以查询多个 经纬度List<Point> redisGeoList2 = redisGeoUntil.getRedisGeoList(redisKey, codeList);//[Point [x=116.099999, y=19.100000], Point [x=116.199997, y=19.200000], Point [x=116.300001, y=19.299999], Point [x=116.399999, y=19.399999], Point [x=116.500002, y=19.499999], Point [x=116.600001, y=19.599999]]//计算指定点codeGeoResults<RedisGeoCommands.GeoLocation<String>> hangzhou11 = redisGeoUntil.getRedisGeoMaxIntegerKm(redisKey, "hangzhou1");//GeoResults: [averageDistance: 30.5927 KILOMETERS, results: GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou1, point=Point [x=116.099999, y=19.100000]), distance: 0.0 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou2, point=Point [x=116.199997, y=19.200000]), distance: 15.3006 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou3, point=Point [x=116.300001, y=19.299999]), distance: 30.5972 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou4, point=Point [x=116.399999, y=19.399999]), distance: 45.889 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou5, point=Point [x=116.500002, y=19.499999]), distance: 61.1767 KILOMETERS, ]]//删除redisGeoUntil.deleteRedisGeo(redisKey,"hangzhou5");//查询可以查询多个 经纬度List<Point> redisGeoList3 = redisGeoUntil.getRedisGeoList(redisKey, codeList);//[Point [x=116.099999, y=19.100000], Point [x=116.199997, y=19.200000], Point [x=116.300001, y=19.299999], Point [x=116.399999, y=19.399999], Point [x=116.600001, y=19.599999]]//修改(先删除再新增)redisGeoUntil.updateRedisGeo( redisKey, 116.99,19.99,"hangzhou4");//查询可以查询多个 经纬度List<Point> redisGeoList4 = redisGeoUntil.getRedisGeoList(redisKey, codeList);//[Point [x=116.099999, y=19.100000], Point [x=116.199997, y=19.200000], Point [x=116.300001, y=19.299999], Point [x=116.989999, y=19.990001], Point [x=116.600001, y=19.599999]]//查询单个Point hangzhou1 = redisGeoUntil.getRedisGeo(redisKey, "hangzhou1");//[Point [x=116.099999, y=19.100000]]//查询单个Point hangzhou2 = redisGeoUntil.getRedisGeo(redisKey, "没有这个地址");//[null]//查找一个位置的时间复杂度为 ?? hash值redisGeoUntil.getRedisGeoListHash(redisKey, "hangzhou1");//[we6s9vj3w40]//计算2地之间距离(返回两个地方的距离,可以指定单位,比如米m,千米km,英里mi,英尺ft)Distance redisGeoListTwoSpace = redisGeoUntil.getRedisGeoListTwoSpace(redisKey, "hangzhou1", "hangzhou2");//15.3006 KILOMETERS//longitude,latitude//中心点设置  某个经纬度算距离GeoResults<RedisGeoCommands.GeoLocation<String>> redisGeoMaxIntegerKm = redisGeoUntil.getRedisGeoMaxIntegerKm(redisKey, 126.40, 29.90);//GeoResults: [averageDistance: 1537.1931 KILOMETERS, results: GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou4, point=Point [x=116.989999, y=19.990001]), distance: 1453.0984 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou6, point=Point [x=116.600001, y=19.599999]), distance: 1512.4838 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou3, point=Point [x=116.300001, y=19.299999]), distance: 1558.2093 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou2, point=Point [x=116.199997, y=19.200000]), distance: 1573.4598 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou1, point=Point [x=116.099999, y=19.100000]), distance: 1588.7142 KILOMETERS, ]]//selectRidesPoint(146.40f,49.90f,Integer.MAX_VALUE);//计算指定点 5km内的GeoResults<RedisGeoCommands.GeoLocation<String>> redisGeoMaxIntegerKm2 = redisGeoUntil.getRedisGeoMaxIntegerKm(redisKey, "hangzhou1");//GeoResults: [averageDistance: 51.675599999999996 KILOMETERS, results: GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou1, point=Point [x=116.099999, y=19.100000]), distance: 0.0 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou2, point=Point [x=116.199997, y=19.200000]), distance: 15.3006 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou3, point=Point [x=116.300001, y=19.299999]), distance: 30.5972 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou6, point=Point [x=116.600001, y=19.599999]), distance: 76.4596 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou4, point=Point [x=116.989999, y=19.990001]), distance: 136.0206 KILOMETERS, ]]return  null;}//	private Map<String, Map<String, Double>> selectRidesPoint(float lng, float lat, Integer radius) {
//		String redisLnglatName = redisKey;
//		//中心点设置
//		Point point = new Point(lng, lat);
//		Metric metric = RedisGeoCommands.DistanceUnit.KILOMETERS;
//		Distance distance = new Distance(radius, metric);
//		Circle circle = new Circle(point, distance);
//
//		//redis查询参数配置:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
//		RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
//				.newGeoRadiusArgs()
//				.includeDistance()
//				.includeCoordinates()
//				.sortAscending()
//				.limit(5);
//		GeoResults<RedisGeoCommands.GeoLocation<String>> data = redisTemplate.opsForGeo().geoRadius(redisLnglatName, circle, args);
//		System.out.println("计算circleDis 和 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5 的距离 ");
//		System.out.println(data);
//
//
//
//
//
//
//
//
//
//		//数据封装
//		Map<String, Map<String, Double>> cameraMap = new HashMap<>();
//		if (data != null) {
//			data.forEach(geoLocationGeoResult -> {
//				RedisGeoCommands.GeoLocation<String> content = geoLocationGeoResult.getContent();
//				Map<String, Double> pointMap = new HashMap<>();
//				//member 名称  如  tianjin
//				String name = content.getName();
//				// 对应的经纬度坐标
//				Point pos = content.getPoint();
//				// 距离中心点的距离
//				Distance dis = geoLocationGeoResult.getDistance();
//				pointMap.put("lng", pos.getX());
//				pointMap.put("lat", pos.getY());
//				cameraMap.put(name, pointMap);
//			});
//		}
//		return cameraMap;
//	}}

@RequestMapping("/redisTest")
@RestController
@AllArgsConstructor
@Api(value = "RedisController", tags = "redis房屋Api")
public class RedisController {private final RedisTemplate redisTemplate;private static String redisKey = "GET_DISTANCE";/*** 获取房屋统计** @param* @return success/false*/@GetMapping("/v2/redisTest")@ApiOperation(value = "redistest获取房屋统计测试-yangjiabin20220412", notes = "获取房屋统计测试-yangjiabin20220412")public R getHouseStatistics() {//Point的属性值,x轴是经度longitude,y轴是纬度latitude。Point point1  = new Point(116.40,19.90);Point point2  = new Point(126.40,29.90);Point point3  = new Point(136.40,39.90);Point point4  = new Point(146.40,49.90);Point point5  = new Point(156.40,59.90);Point point6  = new Point(166.40,69.90);//增加(添加经纬度信息)Long addedNum1 = redisTemplate.opsForGeo().add(redisKey,point1,"hangzhou1");Long addedNum2 = redisTemplate.opsForGeo().add(redisKey,point2,"hangzhou2");Long addedNum3 = redisTemplate.opsForGeo().add(redisKey,point3,"hangzhou3");Long addedNum4 = redisTemplate.opsForGeo().add(redisKey,point4,"hangzhou4");Long addedNum5 = redisTemplate.opsForGeo().add(redisKey,point5,"hangzhou5");//查询可以查询多个 经纬度List<Point> pointsAll = redisTemplate.opsForGeo().position(redisKey,"hangzhou1","hangzhou2","hangzhou3","hangzhou4","hangzhou5");System.out.println("首次新增 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5 ");System.out.println(pointsAll);//计算指定点 5km内的Distance disFiveKmFive = new Distance(Integer.MAX_VALUE,Metrics.KILOMETERS);RedisGeoCommands.GeoRadiusCommandArgs argsFiveKmFive = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(5);GeoResults<RedisGeoCommands.GeoLocation<String>>  resultsFiveKmFive = redisTemplate.opsForGeo().radius(redisKey,"hangzhou1",disFiveKmFive,argsFiveKmFive);System.out.println("首次计算hangzhou1 和 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5 的距离 ");System.out.println(resultsFiveKmFive);//删除//redisTemplate.opsForZSet().remove(redisKey,"hangzhou5");redisTemplate.boundZSetOps(redisKey).remove("hangzhou5");//查询可以查询多个 经纬度List<Point> pointsAllDelete = redisTemplate.opsForGeo().position(redisKey,"hangzhou1","hangzhou2","hangzhou3","hangzhou4","hangzhou5");System.out.println("删除hangzhou5 后查询 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5   ");System.out.println(pointsAllDelete);//修改(先删除再新增)redisTemplate.opsForZSet().remove(redisKey,"hangzhou4");Long addedNumDel5 = redisTemplate.opsForGeo().add(redisKey,point6,"hangzhou4");//查询可以查询多个 经纬度List<Point> pointsAll2 = redisTemplate.opsForGeo().position(redisKey,"hangzhou1","hangzhou2","hangzhou3","hangzhou4","hangzhou5");System.out.println("修改hangzhou4 后查询 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5   ");System.out.println(pointsAll2);List<Point> points2 = redisTemplate.opsForGeo().position(redisKey,"hangzhou1");System.out.println("查询hangzhou1    ");System.out.println(points2);//查找一个位置的时间复杂度为 ?? hash值List<String> resultsHash = redisTemplate.opsForGeo().hash(redisKey,"hangzhou1","hangzhou2","hangzhou3");System.out.println(" 查询 hangzhou1 , hangzhou2 , hangzhou3 hash值   ");System.out.println(resultsHash);//计算2地之间距离(返回两个地方的距离,可以指定单位,比如米m,千米km,英里mi,英尺ft)Distance disTwoPlace = redisTemplate.opsForGeo().distance(redisKey,"hangzhou1","hangzhou2", RedisGeoCommands.DistanceUnit.KILOMETERS);System.out.println(" 查询 hangzhou1 , hangzhou2 之间距离   ");System.out.println(disTwoPlace);//计算2地之间距离(返回两个地方的距离,可以指定单位,比如米m,千米km,英里mi,英尺ft)        会报错!!!这个怎么办??
//		Distance disTwoPlace222 = redisTemplate.opsForGeo().distance(redisKey,"hangzhou1","没有这个地址", RedisGeoCommands.DistanceUnit.KILOMETERS);
//		System.out.println(disTwoPlace222);List<Point> pointsNull = redisTemplate.opsForGeo().position(redisKey,"没有这个地址");System.out.println(" 查询 没有的code   ");System.out.println(pointsNull);//longitude,latitude//中心点设置  某个经纬度算距离Point pointCenter = new Point(126.40,29.90);Distance distanceCenter = new Distance(Integer.MAX_VALUE, RedisGeoCommands.DistanceUnit.KILOMETERS);Circle circleCenter = new Circle(pointCenter, distanceCenter);RedisGeoCommands.GeoRadiusCommandArgs argsCircle = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(5);GeoResults<RedisGeoCommands.GeoLocation<String>> resultsDis = redisTemplate.opsForGeo().radius(redisKey,circleCenter ,argsCircle);//GeoResults<RedisGeoCommands.GeoLocation<String>> resultsDis = redisTemplate.opsForGeo().radius(redisKey,circleDis,argsCircle);System.out.println("计算circleDis 和 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5 的距离 ");System.out.println(resultsDis);selectRidesPoint(146.40f,49.90f,Integer.MAX_VALUE);//计算指定点 5km内的Distance disFiveKm = new Distance(Integer.MAX_VALUE,Metrics.KILOMETERS);RedisGeoCommands.GeoRadiusCommandArgs argsFiveKm = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(5);GeoResults<RedisGeoCommands.GeoLocation<String>>  resultsFiveKm = redisTemplate.opsForGeo().radius(redisKey,"hangzhou1",disFiveKm,argsFiveKm);System.out.println("计算hangzhou1 和 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5 的距离 ");System.out.println(resultsFiveKm);/*
[Point [x=116.399999, y=19.900001], Point [x=126.399998, y=29.900000], Point [x=136.399998, y=39.900000], Point [x=146.400003, y=49.900000], Point [x=156.400002, y=59.899999]]
GeoResults: [averageDistance: 2828.28654 KILOMETERS, results: GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou1, point=Point [x=116.399999, y=19.900001]), distance: 0.0 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou2, point=Point [x=126.399998, y=29.900000]), distance: 1500.0764 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou3, point=Point [x=136.399998, y=39.900000]), distance: 2929.5193 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou4, point=Point [x=146.400003, y=49.900000]), distance: 4258.88 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou5, point=Point [x=156.400002, y=59.899999]), distance: 5452.957 KILOMETERS, ]]
[Point [x=116.399999, y=19.900001], Point [x=126.399998, y=29.900000], Point [x=136.399998, y=39.900000], Point [x=146.400003, y=49.900000], null]
[Point [x=116.399999, y=19.900001], Point [x=126.399998, y=29.900000], Point [x=136.399998, y=39.900000], Point [x=166.400001, y=69.899999], null]
[Point [x=116.399999, y=19.900001]]
[wedc0wxvut0, wv3fh71sjk0, xp0fzze6q70]
1500.0764 KILOMETERS
[null]
GeoResults: [averageDistance: 0.0 METERS, results: ]
GeoResults: [averageDistance: 2724.986925 KILOMETERS, results: GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou1, point=Point [x=116.399999, y=19.900001]), distance: 0.0 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou2, point=Point [x=126.399998, y=29.900000]), distance: 1500.0764 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou3, point=Point [x=136.399998, y=39.900000]), distance: 2929.5193 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou4, point=Point [x=166.400001, y=69.899999]), distance: 6470.352 KILOMETERS, ]]*/
/*
首次新增 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5
[Point [x=116.399999, y=19.900001], Point [x=126.399998, y=29.900000], Point [x=136.399998, y=39.900000], Point [x=146.400003, y=49.900000], Point [x=156.400002, y=59.899999]]
首次计算hangzhou1 和 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5 的距离
GeoResults: [averageDistance: 2828.28654 KILOMETERS, results: GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou1, point=Point [x=116.399999, y=19.900001]), distance: 0.0 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou2, point=Point [x=126.399998, y=29.900000]), distance: 1500.0764 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou3, point=Point [x=136.399998, y=39.900000]), distance: 2929.5193 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou4, point=Point [x=146.400003, y=49.900000]), distance: 4258.88 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou5, point=Point [x=156.400002, y=59.899999]), distance: 5452.957 KILOMETERS, ]]
删除hangzhou5 后查询 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5
[Point [x=116.399999, y=19.900001], Point [x=126.399998, y=29.900000], Point [x=136.399998, y=39.900000], Point [x=146.400003, y=49.900000], null]
修改hangzhou4 后查询 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5
[Point [x=116.399999, y=19.900001], Point [x=126.399998, y=29.900000], Point [x=136.399998, y=39.900000], Point [x=166.400001, y=69.899999], null]
查询hangzhou1
[Point [x=116.399999, y=19.900001]]查询 hangzhou1 , hangzhou2 , hangzhou3 hash值
[wedc0wxvut0, wv3fh71sjk0, xp0fzze6q70]查询 hangzhou1 , hangzhou2 之间距离
1500.0764 KILOMETERS查询 没有的code
[null]查询 hangzhou1
GeoResults: [averageDistance: 0.0 METERS, results: ]
首次计算hangzhou1 和 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5 的距离
GeoResults: [averageDistance: 2724.986925 KILOMETERS, results: GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou1, point=Point [x=116.399999, y=19.900001]), distance: 0.0 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou2, point=Point [x=126.399998, y=29.900000]), distance: 1500.0764 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou3, point=Point [x=136.399998, y=39.900000]), distance: 2929.5193 KILOMETERS, ],GeoResult [content: RedisGeoCommands.GeoLocation(name=hangzhou4, point=Point [x=166.400001, y=69.899999]), distance: 6470.352 KILOMETERS, ]]*/return  null;}private Map<String, Map<String, Double>> selectRidesPoint(float lng, float lat, Integer radius) {String redisLnglatName = redisKey;//中心点设置Point point = new Point(lng, lat);Metric metric = RedisGeoCommands.DistanceUnit.KILOMETERS;Distance distance = new Distance(radius, metric);Circle circle = new Circle(point, distance);//redis查询参数配置:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(5);GeoResults<RedisGeoCommands.GeoLocation<String>> data = redisTemplate.opsForGeo().geoRadius(redisLnglatName, circle, args);System.out.println("计算circleDis 和 hangzhou1 , hangzhou2 , hangzhou3 , hangzhou4 , hangzhou5 的距离 ");System.out.println(data);//数据封装Map<String, Map<String, Double>> cameraMap = new HashMap<>();if (data != null) {data.forEach(geoLocationGeoResult -> {RedisGeoCommands.GeoLocation<String> content = geoLocationGeoResult.getContent();Map<String, Double> pointMap = new HashMap<>();//member 名称  如  tianjinString name = content.getName();// 对应的经纬度坐标Point pos = content.getPoint();// 距离中心点的距离Distance dis = geoLocationGeoResult.getDistance();pointMap.put("lng", pos.getX());pointMap.put("lat", pos.getY());cameraMap.put(name, pointMap);});}return cameraMap;}}

redis geo 删除函数

做附近的人功能时候,需要用到geo功能,redis正好提供了这个功能,但是发现没有删除geo位置的函数

  • GEOADD 添加一个经纬度到一个集合的位置
  • GEODIST 计算一个集合中2个位置的距离
  • GEOHASH 把经纬度计算成一个标准的Geohash
  • GEOPOS 返回一个集合中指定位置的经纬度
  • GEORADIUS 以一个经纬度为中心 计算指定距离范围内所有的位置元素
  • GEORADIUSBYMEMBER 以一个位置为中心 计算指定距离范围内所有的位置元素

我们发现,上面列出的所有geo相关的函数中没有关于删除geo的函数,怎么才能删除geo位置呢?答案是使用集合函数中的 zrem 即可删除,因为geo本质是储存在了一个集合中的。

对于如何删除redis中geo存入的坐标

    redis中geo 就是将坐标存在reids 中可以进行判断坐标之间的距离,判断坐标及公里内的坐标。
但是由于geo大部分博客都是添加geo 进行判断,但是没有教大家怎么删除,对于坐标点比较多的话会
再redis中进行冗余数据。
    geo其实就是redis中的有序集合,大家可以自行百度查看用法。
    我用的是 Map<String, Point> memberCoordinateMap = new HashMap<String, Point>(); 
来存储坐标的RedisTemplate.opsForGeo().geoAdd(b, memberCoordinateMap);怎么运用就看大家
的需求了。b 是用的uuid 当作key值的,
    结束之后我们进行删除geo 。RedisTemplate.opsForZset.remove(b,String.valueof(ccc)),
其中c 就是memberCoordinateMap的key。 需要遍历删除。即可把获赠个有序集合删除
 

利用Redis的GEO功能,实现位置查询_juejiang坚持的博客-CSDN博客_geo redis 实现

利用Redis的GEO功能,实现位置查询

利用Redis的GEO功能,实现位置查询

juejiang坚持

于 2021-02-24 11:19:56 发布

522
 收藏 1
分类专栏: Java 数据库 文章标签: redis java
版权

Java
同时被 2 个专栏收录
12 篇文章0 订阅
订阅专栏

数据库
3 篇文章0 订阅
订阅专栏
业务需求:项目中有需求要根据图上绘制的路径搜索某半径范围内所有的设备。
1
解决思路:利用高德地图绘制的路线,可以取得路线上所有点位的经纬度。根据Redis的GEO功能,将所有设备的经纬度写入Redis,然后根据点位经纬度和搜索半径,通过Redis提供的方法即可查询出在此范围内的所有设备。

1、Redis Geo提供了6个命令:
GEOADD、GEODIST、GEOPOS、GEOHASH、GEORADIUS、GEORADIUSBYMEMBER
(1)GEOADD key longitude latitude member [longitude latitude member …]
将一个包含经度、纬度、名称的位置存放在key里
(2)GEODIST key member1 member2 [unit]
计算key里指定的两个位置之间的距离,unit单位:m/Km/mi/ft
(3)GEOPOS key member [member …]
返回key里指定位置的经纬度。返回值是一个数组, 数组中的每个项都由两个元素组成: 第一个元素为给定位置元素的经度, 第二个元素则为给定位置元素的纬度。
(4)GEOHASH key member [member …]
返回key里指定位置的 Geohash 表示。返回一个数组, 数组的每个项都是一个geohash表达式 。返回的geohash的位置与指定位置的位置一一对应。
(5)GEORADIUS key longitude latitude radius m/km/ft/mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC/DESC]
以给定的经纬度为中心点,查找指定半径内,包含的所有位置元素。
WITHCOORD: 将位置元素的经度和维度一并返回。
WITHDIST: 位置元素与中心点之间的距离
WITHHASH: 返回位置的 Geohash 表达式
COUNT: 返回指定条数,相当于MySQL查询的limit
ASC/DESC: 根据中心的位置, 按照从近到远或从远到近的方式返回位置元素。
(6)GEORADIUSBYMEMBER key member radius m/km/ft/mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC/DESC]
和GEORADIUS命令操作相同,只是GEORADIUSBYMEMBER的中心点是key里的位置元素。

2、项目中的实现
(1)添加点位到Redis

private void insertRedis(double lng, double lat, String id){
    Map<String, Point> points = new HashMap<>();
    points.put(id, new Point(lng, lat));
    // 添加 Geo
    stringRedisTemplate.boundGeoOps(Constans.REDIS_CAMERA_LNGLAT).geoAdd(points);
}
1
2
3
4
5
6
(2)将一个点位信息删除

private void deleteRedis(String id) {
    stringRedisTemplate.boundZSetOps(Constans.REDIS_CAMERA_LNGLAT).remove(id);
}
1
2
3
(3)根据页面上绘制的路径得到的点位经纬度查询半径范围内的所有数据

private List<String> selectRidesPoint(float lng, float lat, Integer radius) {
    String redisLnglatName = Constans.REDIS_CAMERA_LNGLAT;
    //中心点设置
    Point point = new Point(lng, lat);
    Metric metric = RedisGeoCommands.DistanceUnit.METERS;
    Distance distance = new Distance(radius, metric);
    Circle circle = new Circle(point, distance);

    //redis查询参数配置:GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
    RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
        .newGeoRadiusArgs()
        .includeDistance()
        .includeCoordinates()
        .sortAscending()
        .limit(limit);
    GeoResults<RedisGeoCommands.GeoLocation<String>> data = stringRedisTemplate.opsForGeo().geoRadius(redisLnglatName, circle, args);
    
    //数据封装
    Map<String, Map<String, Double>> cameraMap = new HashMap<>();
    if (data != null) {
        data.forEach(geoLocationGeoResult -> {
            RedisGeoCommands.GeoLocation<String> content = geoLocationGeoResult.getContent();
            Map<String, Double> pointMap = new HashMap<>();
            //member 名称  如  tianjin 
            String name = content.getName();
             // 对应的经纬度坐标
            Point pos = content.getPoint();
            // 距离中心点的距离
            Distance dis = geoLocationGeoResult.getDistance();
            pointMap.put("lng", pos.getX());
            pointMap.put("lat", pos.getY());
            cameraMap.put(name, pointMap);
        });
    }
    return cameraMap;
}
 

附:关于地球经纬度之间间距计算

/**
 * 根据经纬度和半径计算经纬度范围
 *
 * @param raidus 单位米
 * @return minLat, minLng, maxLat, maxLng
 */
private Map<String, Double> getAround(double lat, double lon, int raidus) {

    Double latitude = lat;
    Double longitude = lon;

    Double degree = (24901 * 1609) / 360.0;
    double raidusMile = raidus;

    Double dpmLat = 1 / degree;
    Double radiusLat = dpmLat * raidusMile;
    Double minLat = latitude - radiusLat;
    Double maxLat = latitude + radiusLat;

    Double mpdLng = degree * Math.cos(latitude * (Math.PI / 180));
    Double dpmLng = 1 / mpdLng;
    Double radiusLng = dpmLng * raidusMile;
    Double minLng = longitude - radiusLng;
    Double maxLng = longitude + radiusLng;
//        return new double[]{minLat, minLng, maxLat, maxLng};
    
    Map<String, Double> aroundMap = new HashMap<>();
    aroundMap.put("minLng", minLng);
    aroundMap.put("minLat", minLat);
    aroundMap.put("maxLng", maxLng);
    aroundMap.put("maxLat", maxLat);
    return aroundMap;
}
/**
 * 计算地球上任意两点(经纬度)距离
 *
 * @param long1 第一点经度
 * @param lat1  第一点纬度
 * @param long2 第二点经度
 * @param lat2  第二点纬度
 * @return 返回距离 单位:米
 */
private double distanceByLongNLat(double long1, double lat1, double long2, double lat2) {
    double a, b, R;
    R = 6378137;//地球半径
    lat1 = lat1 * Math.PI / 180.0;
    lat2 = lat2 * Math.PI / 180.0;
    a = lat1 - lat2;
    b = (long1 - long2) * Math.PI / 180.0;
    double d;
    double sa2, sb2;
    sa2 = Math.sin(a / 2.0);
    sb2 = Math.sin(b / 2.0);
    d = 2 * R * Math.asin(Math.sqrt(sa2 * sa2 + Math.cos(lat1) * Math.cos(lat2) * sb2 * sb2));
    return d;
}
————————————————
版权声明:本文为CSDN博主「juejiang坚持」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/juejiangjianchi/article/details/109205198

利用Redis的Geo功能实现查找附近的位 - 云+社区 - 腾讯云

利用Redis的Geo功能实现查找附近的位

2020-06-28阅读 3880

1. 前言

老板突然要上线一个需求,获取当前位置方圆一公里的业务代理点。明天上线!当接到这个需求的时候我差点吐血,这时间也太紧张了。赶紧去查相关的技术选型。经过一番折腾,终于在晚上十点完成了这个需求。现在把大致实现的思路总结一下。

图1

2. MySQL 不合适

遇到需求,首先要想到现有的东西能不能满足,成本如何。

MySQL是我首先能够想到的,毕竟大部分数据要持久化到MySQL。但是使用MySQL需要自行计算Geohash。需要使用大量数学几何计算,并且需要学习地理相关知识,门槛较高,短时间内不可能完成需求,而且长期来看这也不是MySQL擅长的领域,所以没有考虑它。

Geohash 参考 https://www.cnblogs.com/LBSer/p/3310455.html

2. Redis 中的 GEO

Redis是我们最为熟悉的K-V数据库,它常被拿来作为高性能的缓存数据库来使用,大部分项目都会用到它。从3.2版本开始它开始提供了GEO能力,用来实现诸如附近位置、计算距离等这类依赖于地理位置信息的功能。GEO相关的命令如下:

Redis 命令

描述

GEOHASH

返回一个或多个位置元素的 Geohash 表示

GEOPOS

从 key 里返回所有给定位置元素的位置(经度和纬度)

GEODIST

返回两个给定位置之间的距离

GEORADIUS

以给定的经纬度为中心, 找出某一半径内的元素

GEOADD

将指定的地理空间位置(纬度、经度、名称)添加到指定的 key 中

GEORADIUSBYMEMBER

找出位于指定范围内的元素,中心点是由给定的位置元素决定

Redis 会假设地球为完美的球形, 所以可能有一些位置计算偏差,据说<=0.5%,对于有严格地理位置要求的需求来说要经过一些场景测试来检验是否能够满足需求。

2.1 写入地理信息

那么如何实现目标单位半径内的所有元素呢?我们可以将所有的位置的经纬度通过上表中的GEOADD将这些地理信息转换为 52 位的Geohash写入Redis

该命令格式:

geoadd key longitude latitude member [longitude latitude member ...]

复制

对应例子:

redis> geoadd cities:locs 117.12 39.08 tianjin 114.29 38.02  shijiazhuang
(integer) 2

复制

意思是将经度为117.12纬度为39.08的地点tianjin和经度为114.29纬度为38.02的地点shijiazhuang加入keycities:locssorted set集合中。可以添加一到多个位置。然后我们就可以借助于其他命令来进行地理位置的计算了。

有效的经度从-180 度到 180 度。有效的纬度从-85.05112878 度到 85.05112878 度。当坐标位置超出上述指定范围时,该命令将会返回一个错误。

2.2 统计单位半径内的地区

我们可以借助于GEORADIUS来找出以给定经纬度,某一半径内的所有元素。

该命令格式:

georadius key longtitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC]

复制

这个命令比GEOADD要复杂一些:

  • radius 半径长度,必选项。后面的mkmftmi、是长度单位选项,四选一。
  • WITHCOORD 将位置元素的经度和维度也一并返回,非必选。
  • WITHDIST 在返回位置元素的同时, 将位置元素与中心点的距离也一并返回。距离的单位和查询单位一致,非必选。
  • WITHHASH 返回位置的 52 位精度的Geohash值,非必选。这个我反正很少用,可能其它一些偏向底层的LBS应用服务需要这个。
  • COUNT 返回符合条件的位置元素的数量,非必选。比如返回前 10 个,以避免出现符合的结果太多而出现性能问题。
  • ASC|DESC 排序方式,非必选。默认情况下返回未排序,但是大多数我们需要进行排序。参照中心位置,从近到远使用ASC ,从远到近使用DESC

例如,我们在 cities:locs 中查找以(115.03,38.44)为中心,方圆200km的城市,结果包含城市名称、对应的坐标和距离中心点的距离(km),并按照从近到远排列。命令如下:

redis> georadius cities:locs 115.03 38.44 200 km WITHCOORD WITHDIST ASC
1) 1) "shijiazhuang"2) "79.7653"3) 1) "114.29000169038772583"2) "38.01999994251037407"
2) 1) "tianjin"2) "186.6937"3) 1) "117.02000230550765991"2) "39.0800000535766543"

复制

你可以加上 COUNT 1来查找最近的一个位置。

3. 基于 Redis GEO 实战

大致的原理思路说完了,接下来就是实操了。结合Spring Boot应用我们应该如何做?

3.1 开发环境

需要具有GEO特性的Redis版本,这里我使用的是Redis 4 。另外我们客户端使用 spring-boot-starter-data-redis 。这里我们会使用到 RedisTemplate对象。

3.2 批量添加位置信息

第一步,我们需要将位置数据初始化到Redis中。在Spring Data Redis中一个位置坐标(lng,lat) 可以封装到org.springframework.data.geo.Point对象中。然后指定一个名称,就组成了一个位置Geo信息。RedisTemplate提供了批量添加位置信息的方法。我们可以将章节 2.1中的添加命令转换为下面的代码:

   Map<String, Point> points = new HashMap<>();points.put("tianjin", new Point(117.12, 39.08));points.put("shijiazhuang", new Point(114.29, 38.02));// RedisTemplate 批量添加 GeoredisTemplate.boundGeoOps("cities:locs").add(points);

复制

可以结合Spring Boot 提供的 ApplicationRunner 接口来实现初始化。

@Bean
public ApplicationRunner cacheActiveAppRunner(RedisTemplate<String, String> redisTemplate) {return args -> {final String GEO_KEY = "cities:locs";// 清理缓存redisTemplate.delete(GEO_KEY);Map<String, Point> points = new HashMap<>();points.put("tianjin", new Point(117.12, 39.08));points.put("shijiazhuang", new Point(114.29, 38.02));// RedisTemplate 批量添加 GeoLocationBoundGeoOperations<String, String> geoOps = redisTemplate.boundGeoOps(GEO_KEY);geoOps.add(points);};
}

复制

3.3 查询附近的特定位置

RedisTemplate 针对GEORADIUS命令也有封装:

GeoResults<GeoLocation<M>> radius(K key, Circle within, GeoRadiusCommandArgs args)

复制

Circle对象是封装覆盖的面积(图 1),需要的要素为中心点坐标Point对象、半径(radius)、计量单位(metric), 例如:

Point point = new Point(115.03, 38.44);Metric metric = RedisGeoCommands.DistanceUnit.KILOMETERS;
Distance distance = new Distance(200, metric);Circle circle = new Circle(point, distance);

复制

GeoRadiusCommandArgs用来封装GEORADIUS的一些可选命令参数,参见章节 2.2中的WITHCOORDCOUNTASC等,例如我们需要在返回结果中包含坐标、中心距离、由近到远排序的前 5 条数据:

RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().includeCoordinates().sortAscending().limit(limit);

复制

然后执行 radius方法就会拿到GeoResults<RedisGeoCommands.GeoLocation<String>>封装的结果,我们对这个可迭代对象进行解析就可以拿到我们想要的数据:

GeoResults<RedisGeoCommands.GeoLocation<String>> radius = redisTemplate.opsForGeo().radius(GEO_STAGE, circle, args);if (radius != null) {List<StageDTO> stageDTOS = new ArrayList<>();radius.forEach(geoLocationGeoResult -> {RedisGeoCommands.GeoLocation<String> content = geoLocationGeoResult.getContent();//member 名称  如  tianjinString name = content.getName();// 对应的经纬度坐标Point pos = content.getPoint();// 距离中心点的距离Distance dis = geoLocationGeoResult.getDistance();});
}

复制

3.4 删除元素

有时候我们可能需要删除某个位置元素,但是RedisGeo并没有删除成员的命令。不过由于它的底层是zset,我们可以借助zrem命令进行删除,对应的Java代码为:

redisTemplate.boundZSetOps(GEO_STAGE).remove("tianjin");

复制

4. 总结

今天我们使用RedisGeo特性实现了常见的附近的地理信息查询需求,简单易上手。其实使用另一个Nosql数据库MongoDB也可以实现。在数据量比较小的情况下Redis已经能很好的满足需要。如果数据量大可使用MongoDB来实现。

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

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

相关文章

openglshader实现虚拟场景_opengl+shader

1、环境介绍&#xff1a;】软件 &#xff1a;visual studio编程语言&#xff1a;opengl库 &#xff1a;glad glfw【2、内容介绍】-- 绘制场景&#xff1a;场景1&#xff1a; 一片沙漠中&#xff0c;一本书&#xff0c;四周出现 5 个自球&#xff0c;逐渐被黑雾笼罩场景2&#x…

没有注册类 (异常来自 HRESULT:0x80040154 (REGDB_E_CLASSNOTREG))

今天在开发指纹识别的项目时候&#xff0c;出现了个问题&#xff0c;这个问题之前也没有见过&#xff0c;所以无从下手&#xff0c;只能从网上找解决方法&#xff0c;找了半天说要注册com组件啥的&#xff0c;我老是注册不成功&#xff0c;后来瞎捣鼓终于解决了&#xff0c;原因…

JS获取自定义属性data-*值与dataset

转载自 JS获取自定义属性data值 <body> <div id"tree" data-leaves"47" data-plant-height"2.4m"></div> <script> var tree document.getElementById("tree"); //getAttribute()取值属性 console.log(tr…

插值查找+代码实现+注意事项

图解 代码实现 package com.atguigu.search;import java.util.Arrays;/*** 创建人 wdl* 创建时间 2021/3/23* 描述*/ public class InsertValueSearch {public static void main(String[] args) {int[] arrnew int[100];for (int i 0; i < 100; i) {arr[i]i1;}// S…

SQL Server on Linux的文件和目录结构

问题引入 “鸟儿啊&#xff0c;我记得你写过一篇《SQLServer On Linux Package List on CentOS》的文章&#xff0c;从这篇文章&#xff0c;我们很清楚的知道了SQL Server on Linux包含有哪些必要的包。那么&#xff0c;我们怎么知道SQL Server on Linux到底包含哪些重要的文件…

3级调度 fpga_FPGA的软核、硬核、固核

“核”现在的FPGA设计&#xff0c;规模巨大而且功能复杂&#xff0c;因此设计的每一个部分都从头开始是不切实际的。一种解决的办法是&#xff1a;对于较为通用的部分可以重用现有的功能模块&#xff0c;而把主要的时间和资源用在设计中的那些全新的、独特的部分。这就像是你在…

ssm中spring mvc找不到控制器,报错404

今晚在整合ssm的时候&#xff0c;出现了个错误&#xff0c;自己的都感觉醉了。之前没学过spring mvc&#xff0c;所以做起来感觉有点很陌生&#xff0c;在网上看了看代码之后就呼呼呼的写代码了。写了2小时&#xff0c;终于把环境搭建好了。然后做了个小案例查询全部的数据&…

JS 获取浏览器、显示器 窗体等宽度和高度

转载自 JS 获取浏览器、显示器 窗体等宽度和高度 网页可见区域宽&#xff1a;document.body.clientWidth 网页可见区域高&#xff1a;document.body.clientHeight 网页可见区域宽&#xff1a;document.body.offsetWidth (包括边线的宽) 网页可见区域高&#xff1a;documen…

斐波那契查找+思路分析

图解 代码实现 package com.atguigu.search;import java.util.Arrays;/*** 创建人 wdl* 创建时间 2021/3/23* 描述*/ public class FibonacciSearch {public static int maxSize 20;public static void main(String[] args) {int[] arr {1, 8, 10, 89, 1000, 1234};System.o…

OSS.Social微信项目标准库介绍

经过本周的努力&#xff0c;昨晚终于完成OSS.Social微信项目的标准库支持&#xff0c;当前项目你已经可以同时在.net framework和.net core 中进行调用&#xff0c;调用方法也发生了部分变化&#xff0c;这里我简单分享下&#xff0c;主要包含下边几个部分&#xff1a; 移植后…

使用stream进行分页

public class UserService {public List<User> findUserByParamToPage(Integer index,Integer pageSize){UserDao userDao new UserDao();List<User> users userDao.findAll().stream()/*** 过滤address为""的数据*/.filter(user -> !user.getAddres…

ssh(Spring+Spring mvc+hibernate)简单增删改查案例

最近和spring mvc干上了&#xff0c;各种奇葩问题&#xff0c;各种解决。。。现在想想这历程还挺艰辛的&#xff0c;好了&#xff0c;不在这墨迹了&#xff0c;我们进入正题。 据说&#xff0c;现在Springmvc很流行&#xff0c;既然很流行就搞搞它&#xff0c;看看是个什么鬼&…

python把字符串按照指定长度分割_python如何将字符串等长分割

python将字符串等长分割的方法:1、两个一组分割,代码为【b=re.findall(r.{2},aa) 】;2、按照固定长度分割字符串三个字符一组,代码为【re.findall(r.{3}, string)】。 【相关学习推荐:python教程】 python将字符串等长分割的方法: 方法一: 代码示例#!/bin/python #site:W…

js Date 函数方法

转载自 js Date 函数方法 var myDate new Date();myDate.getYear(); //获取当前年份(2位) myDate.getFullYear(); //获取完整的年份(4位,1970-????) myDate.getMonth(); //获取当前月份(0-11,0代表1月) myDate.getDate(); //获取当前日(1-31) myDate.getDay(); //获取当…

按小区楼栋单元楼层房间号进行排序-多列字符串提取数字进行排序

多列字符串提取数字进行排序 order by e.community_code, e.estate_id, cast(cour.court_name as UNSIGNED) , cast(b.build_name as UNSIGNED) , cast(u.unit_name as UNSIGNED) ,cast(f.floor_name as UNSIGNED) , cast(a.house_no as UNSIGNED) <select id"ge…

Visual Studio 2017 离线安装方式

Visual Studio&#xff0c; 特别是Visual Studio 2017 通常是一个在线安装程序&#xff0c;如果你在安装过程中失去连接&#xff0c;你可以遇到问题。但是&#xff0c;由于法律原因&#xff0c;微软没有提供完整的可下载的ISO镜像。他们不能将Android安装程序从Google打包到ISO…

小米开发版安装magisk_小米9手机不用解锁安装Magisk工具的教程

也是来把咱们的这个小米9手机的安装Magisk的方法整理一下了&#xff0c;这个Magisk工具也是用到的比较多&#xff0c;今天来说的安装方法是不用刷recovery就可来进行安装了&#xff0c;也是在9.0以上的系统可以用的&#xff0c;不过手机是需要开发版的才行的&#xff0c;如果你…

如何用xshell上宝塔

如何下载xshell7免费版 网盘链接 提取码tmtn 如何连接服务器 第一步 第二步 第三步 第四步 第五步 安装宝塔 直接输入命令 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh得到 打开浏览…

ssh(Spring+Spring mvc+hibernate)——Emp.hbm.xml

<?xml version"1.0" encoding"utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Mapping file au…

Essential MSBuild: .NET 工具生成引擎概述

过去几年大家一直都在使用 .NET Core&#xff08;有这么久吗&#xff1f;&#xff09;并且都知道“生成系统”经历了重大改变&#xff0c;不论是终止对 Gulp 的内置支持&#xff0c;还是放弃 Project.json。对于我这个专栏作家来说&#xff0c;这些变化一直很棘手&#xff0c;因…