欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-02-18 15:45:28
前言 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 <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<postion> 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<postion> radious(string type, geocoordinate center, long distinct, boolean asc) {
list<postion> postions = new arraylist<postion>();
jedis jedis = redisconnection.getjedis();
try {
georadiusparam georadiusparam = georadiusparam.georadiusparam().withcoord().withdist();
if (asc) {
georadiusparam.sortascending();
} else {
georadiusparam.sortdescending();
}
list<georadiusresponse> 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.redis.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("2017122802", 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<postion> postions = lbsserviceredis.radious(type, center, 1000 * 10l, true);
assert.asserttrue(postions.size() == 2 && exist(postions, "2017122802") && exist(postions, "2017122803"));
}
@test
public void test50kmradious() {
list<postion> 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<postion> 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);
}
}

测试结果

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

lbs 服务测试结果

后记

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

代码同步发布在 github 仓库

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。