在 Java 中使用 redis 实现 LBS 服务

By admin in 亚洲必赢app在哪下载 on 2018年11月17日

前言

LBS(基于位置的劳务)
服务是今天动互联网中比较常用的效果。例如外卖服务遭遇常用之自附近的柜的效应,通常是坐用户眼前之职务坐标为底蕴,查询一定距离限制类的小卖部,按照距离远近进行倒序排序。

从今 redis 4 版本发布后, lbs 相关命令正式放在 redis
的发行本备受。要实现上述的功能,主要用到 redis geo 相关的星星只指令
GEOADD 和 GEORADIOUS

令描述

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

    夫令将指定的地理空间位置(纬度、经度、名称)添加到指定的 key
    中。
    得力之经度从-180渡过至180度过。
    实用之纬度从-85.05112878度届85.05112878度。
    当坐标位置超出上述指定范围时,该令将见面回到一个谬误。
    该令可以同糟糕补充加多个地理位置点

  2. 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);
}
}

测试结果

LBS 服务测试结果

后记

这么,我们经过 redis 就能大概实现一个自家附近的有点招待所之法力的 LBS服务。

本文程序是在前面的章《在 Java 中使用
redis》的底蕴亚洲必赢app在哪下载及添加新的落实类似的主意形成的。代码同步发表以
GitHub
仓库中

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 亚洲必赢app官方下载 版权所有