предисловие
Служба LBS (Location-Based Service) — более часто используемая функция в мобильном Интернете. Например, функция магазинов рядом со мной, обычно используемая в службах доставки еды на вынос, обычно основана на координатах текущего местоположения пользователя для запроса магазинов в пределах определенного диапазона расстояний и сортировки их в обратном порядке в соответствии с расстоянием.
С момента выпуска Redis 4 команды, связанные с lbs, официально встроены в дистрибутив Redis. Для достижения вышеуказанных функций в основном используются две команды, относящиеся к redis geo. ГЕОАДД и ГЕОРАДИОУС
описание команды
-
GEOADD GEOADD key longitude latitude member [longitude latitude member ...]Эта команда добавляет указанное геопространственное местоположение (широта, долгота, имя) к указанному ключу. Допустимые долготы от -180 градусов до 180 градусов. Допустимые значения широты: от -85,05112878 градусов до 85,05112878 градусов. Команда вернет ошибку, когда положение координат превысит указанный выше диапазон. Эта команда может добавить сразу несколько точек геолокации
-
GEORADIOUS
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
Эта команда принимает заданную широту и долготу в качестве центра и возвращает все элементы позиции, содержащиеся в ключе, расстояние от центра которых не превышает заданного максимального расстояния. Диапазоны могут использовать одну из следующих единиц измерения:
- m означает, что единицей измерения являются метры.
- км указывает, что единицей измерения являются километры.
- mi указывает, что единицей измерения являются мили.
- ft означает, что единицей измерения являются футы.
Команда возвращает дополнительную информацию, если заданы следующие параметры:
- WITHDIST: при возврате элемента позиции также возвращается расстояние между элементом позиции и центром. Единица измерения расстояния соответствует единице дальности, заданной пользователем.
- WITHCOORD: также возвращает долготу и широту элемента position.
- WITHHASH: возвращает необработанную отсортированную оценку множества элемента position, закодированную геохэшем, в виде 52-битного целого числа со знаком. Этот параметр в основном используется для низкоуровневых приложений или отладки и на практике малоэффективен.
- 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<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);
}
}
Результаты теста
постскриптум
Таким образом, мы можем просто реализовать службу LBS, которая работает как небольшой магазин рядом со мной через Redis.
Эта статья программы находится в предыдущей статье«Использование Redis в Java»Это делается на основе добавления новых классов реализации. Код выпускается синхронно вРепозиторий GitHubсередина
Оригинальный текст был опубликован в брифе,оригинальная ссылка