如何在 Java 中利用 redis 实现 LBS 服务

网友投稿 309 2023-01-05


如何在 Java 中利用 redis 实现 LBS 服务

前言

LBS(基于位置的服务) 服务是现在移动互联网中比较常用的功能。例如外卖服务中常用的我附近的店铺的功能,通常是以用户当前的位置坐标为基础,查询一定距离范围类的店铺,按照距离远近进行倒序排序。

自从 redis 4 版本发布后, lbs 相关命令正式内置在 redis 的发行版中。要实现上述的功能,主要用到 redis geo 相关的两个命令

GEOADD 和 GEORADIOUS

命令描述

GEOADD

GEOADD key longitude latitude member [longitude latitude member ...]

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

有效的经度从-180度到180度。

有效的纬度从-85.05112878度到85.05112878度。

当坐标位置超出上述指定范围时,该命令将会返回一个错误。

该命令可以一次添加多个地理位置点

GEORADIOUS

GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]

这个命令以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

范围可以使用以下其中一个单位:

m 表示单位为米。

km 表示单位为千米。

mi 表示单位为英里。

ft 表示单位为英尺。

在给定以下可选项时, 命令会返回额外的信息:

WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。

WITHCOORD: 将位置元素的经度和维度也一并返回。

WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。

ASC: 根据中心的位置, 按照从近到远的方式返回位置元素。

DESC: 根据中心的位置, 按照从远到近的方式返回位置元素。

在默认情况下, GEORADIUS 命令会返回所有匹配的位置元素。 虽然用户可以使用 COUNT 选项去获取前 N 个匹配元素

接口定义

package com.x9710.common.redis;

import com.x9710.common.redis.domain.GeoCoordinate;

import com.x9710.common.redis.domain.Postion;

import java.util.List;

public interface LBSService {

/**

* 存储一个位置

*

* @param postion 增加的位置对象

* @throws Exception

*/

boolean addPostion(Postion postion);

/**

* 查询以指定的坐标为中心,指定的距离为半径的范围类的所有位置点

*

* @param center 中心点位置

* @param distinct 最远距离,单位米

* @param asc 是否倒序排序

* @return 有效的位置

*/

List radious(String type, GeoCoordinate center, Long distinct, Boolean asc);

}

实现的接口

package com.x9710.common.redis.impl;

import com.x9710.common.redis.LBSService;

import com.x9710.common.redis.RedisConnection;

import com.x9710.common.redis.domain.GeoCoordinate;

import com.x9710.common.redis.domain.Postion;

import redis.clients.jedis.GeoRadiusResponse;

import redis.clients.jedis.GeoUnit;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.params.geo.GeoRadiusParam;

import java.util.ArrayList;

import java.util.List;

public class LBSServiceRedisImpl implements LBSService {

private RedisConnection redisConnection;

private Integer dbIndex;

public void setRedisConnection(RedisConnection redisConnection) {

this.redisConnection = redisConnection;

}

public void setDbIndex(Integer dbIndex) {

this.dbIndex = dbIndex;

}

public boolean addPostion(Postion postion) {

Jedis jedis = redisConnection.getJedis();

try {

return (1L == jedis.geoadd(postion.getType(),

postion.getCoordinate().getLongitude(),

postion.getCoordinate().getLatitude(),

postion.getId()));

} finally {

if (jedis != null) {

jedis.close();

}

}

}

public List radious(String type, GeoCoordinate center, Long distinct, Boolean asc) {

List postions = new ArrayList();

Jedis jedis = redisConnection.getJedis();

try {

GeoRadiusParam geoRadiusParam = GeoRadiusParam.geoRadiusParam().withCoord().withDist();

if (asc) {

geoRadiusParam.sortAscending();

} else {

geoRadiusParam.sortDescending();

}

List responses = jedis.georadius(type,

center.getLongitude(),

center.getLatitude(),

distinct.doubleValue(),

GeoUnit.M,

geoRadiusParam);

if (responses != null) {

for (GeoRadiusResponse response : responses) {

Postion postion = new Postion(response.getMemberByString(),

type,

response.getCoordinate().getLongitude(),

response.getCoordinate().getLatitude());

postion.setDistinct(response.getDistance());

postions.add(postion);

}

}

} finally {

if (jedis != null) {

jedis.close();

}

}

return postions;

}

}

测试用例

package com.x9710.common.redis.test;

import com.x9710.common.redis.RedisConnection;

import com.x9710.common.redis.domain.GeoCoordinate;

import com.x9710.common.redis.domain.Postion;

import com.x9710.common.redis.impl.CacheServiceRedisImpl;

import com.x9710.common.redislLbUDIANgk.impl.LBSServiceRedisImpl;

import org.junit.Assert;

import org.junit.Before;

import org.junit.Test;

import java.util.List;

/**

* LBS服务测试类

*

* @author 杨高超

* @since 2017-12-28

*/

public class RedisLBSTest {

private CacheServiceRedisImpl cacheService;

private LBSServiceRedisImpl lbsServiceRedis;

private String type = "SHOP";

private GeoCoordinate center;

@Before

public void before() {

RedisConnection redisConnection = RedisConnectionUtil.create();

lbsServiceRedis = new LBSServiceRedisImpl();

lbsServiceRedis.setDbIndex(15);

lbsServiceRedis.setRedisConnection(redisConnection);

Postion postion = new Postion("2017122801", type, 91.118970, 29.654210);

lbsServiceRedis.addPostion(postion);

postion = new Postion("2017122802http://", type, 116.373472, 39.972528);

lbsServiceRedis.addPostion(postion);

postion = new Postion("2017122803", type, 116.344820, 39.948420);

lbsServiceRedis.addPostion(postion);

postion = new Postion("2017122804", type, 116.637920, 39.905460);

lbsServiceRedis.addPostion(postion);

postion = new Postion("2017122805", type, 118.514590, 37.448150);

lbsServiceRedis.addPostion(postion);

postion = new Postion("2017122806", type, 116.374766, 40.109508);

lbsServiceRedis.addPostion(postion);

center = new GeoCoordinate();

center.setLongitude(116.373472);

center.setLatitude(39.972528);

}

@Test

public void test10KMRadious() {

List postions = lbsServiceRedis.radious(type, center, 1000 * 10L, true);

Assert.assertTrue(postions.size() == 2 && exist(postions, "2017122802") && exist(postions, "2017122803"));

}

@Test

public void test50KMRadious() {

List postions = lbsServiceRedis.radious(type, center, 1000 * 50L, true);

Assert.assertTrue(postions.size() == 4

&& exist(postions, "2017122802")

&& exist(postions, "2017122803")

&& exist(postions, "2017122806")

&& exist(postions, "2017122804"));

}

private boolean exist(List postions, String key) {

if (postions != null) {

for (Postion postion : postions) {

if (postion.getId().equals(key)) {

return true;

}

}

}

return false;

}

@Before

public void after() {

RedisConnection redisConnection = RedisConnectionUtil.create();

cacheService = new CacheServiceRedisImpl();

cacheService.setDbIndex(15);

cacheService.setRedisConnection(redisConnection);

cacheService.delObject(type);

}

}

测试结果

LBS 服务测试结果

后记

这样,我们通过 redis 就能简单实现一个我附近的小店的功能的 LBS服务。

代码同步发布在 github 仓库中


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:做接口测试要考虑什么(做接口测试要考虑什么问题)
下一篇:开源接口自动化框架(开源接口自动化框架结构)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~