preface

Recently, there is a demand to obtain the road where the vehicle is located. The range of the vehicle is within the urban area of a city, and the data volume of the road longitude and latitude nodes of a city will be relatively large (for Jinan, the current data volume is about 200,000). The accuracy and retrieval efficiency of the data are the primary concerns.

Recommended reading

  • Springboot2.x tutorial summary

Redis Geo

After a series of investigations, Redis Geo was used to solve this problem because the data was of an acceptable magnitude.

Redis has enhanced Geo support from **3.2+** version, providing the ability to retrieve the nearest latitude and longitude points within a specified range based on the location of a given latitude and longitude point as a center point.

Redis Geo can also be used to locate businesses within the range of 1km based on the location of mobile phones on meituan Waimai and Ele. me.

yuqiyu@hengyu ~> redis-cli
127.0.0.1:6379> keys *
(empty list or set) 127.0.0.1:6379> GeoAdd Road: Nodes :370100 117.1087416 36.7148919 point1integer) 1 127.0.0.1:6379> geoAdd Road: Nodes :370100 117.1087006 36.7152294 Point2 (integer) 1
127.0.0.1:6379> keys *
1) "road:nodes:370100"

# query a latitude and longitude127.0.0.1:6379> Georadius Road: Nodes :370100 117.1089668 36.7151653 100 m withdist withcoord count 11) 1)"point2"
   2) "24.5815"
   3) 1) "117.10870295763015747"
      2) "36.7152294132502206"

Select * from latitude and longitude127.0.0.1:6379> Georadius Road: Nodes :370100 117.1089668 36.7151653 100 m withdist withcoord count 2 1) 1)"point2"
   2) "24.5815"
   3) 1) "117.10870295763015747"
      2) "36.7152294132502206"
2) 1) "point1"
   2) "36.4573"
   3) 1) "117.10874050855636597"
      2) "36.71489229533602838"
Copy the code

Geoadd command

geoadd key longitude latitude member [longitude latitude member ...]
Copy the code
  • key: the unique key of the geo collection
  • longitude: Added longitude of GPS position
  • latitude: Added latitude of GPS position
  • member: Unique identifier of the GPS location

Georadius command

georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
Copy the code
  • key: the unique key of the geo collection
  • longitude: GPS longitude to be retrieved
  • latutude: GPS latitude to be retrieved
  • radius: Search range in meters (m), kilometers (km), miles (mi), or feet (ft)
  • withcoord: Outputs the matched latitude and longitude
  • withdist: will match the latitude and longitude distance output
  • count: Displays the number of matches
  • asc|descAsc: from near to far, DESC: from far to near

Georadius instruction will take the given latitude and longitude as the central point of retrieval, and retrieve the positions of matched latitude and longitude points within the specified range.

Retrieve the implementation

In the process of practice, two methods were used to test, and slight differences were found in the efficiency of retrieval. The following is a comparison through code practice.

Spring Data

Spring-boot-starter-data-redis is a SpringBoot dependency that can be used to operate redis, and the internal interface is lettuce. The following is a code implementation to retrieve points in range by way of RedisTemplate.

/** * Spring Data to test Redis Geo **@authorHeng Yu Teenager */
@SpringBootTest
@Slf4j
public class SpringDataRedisGeoTest {
    /** * Redis Geo Key */
    private static final String GEO_KEY = "road:nodes:370100";
    @Autowired
    private RedisTemplate redisTemplate;

    /** * retrieves the most recent location in the geo collection */
    @Test
    public void searchPoint(a) {
        double longitude = 117.1089668;
        double latitude = 36.7151653;
        Point centerPoint = new Point(longitude, latitude);
        Distance distance = new Distance(100, RedisGeoCommands.DistanceUnit.METERS);
        Circle circle = new Circle(centerPoint, distance);
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands
                .GeoRadiusCommandArgs
                .newGeoRadiusArgs()
                .includeDistance()
                .includeCoordinates()
                .sortAscending()
                .limit(1);
        GeoResults<RedisGeoCommands.GeoLocation<String>> radius = redisTemplate.boundGeoOps(GEO_KEY).radius(circle, args);
        for (GeoResult<RedisGeoCommands.GeoLocation<String>> result : radius) {
            RedisGeoCommands.GeoLocation<String> content = result.getContent();
            log.info("Result of retrieval, unique identifier: {}, location: {}, distance: {}.", content.getName(), content.getPoint(), result.getDistance()); }}}Copy the code

Search in Redission mode

The internal customization of Redisson encapsulates the logic of operating Redis and supports Redis Geo. After testing, it is found that the retrieval efficiency of Redisson method is higher than that of Spring Data method.

Taking 100,000 pieces of Data as an example, Spring Data retrieval takes about 300ms, while Redisson retrieval only takes about 90ms.

/** * Redisson mode test Redis Geo **@authorHeng Yu Teenager */
@SpringBootTest
@Slf4j
public class RedissonRedisGeoTest {
    private static final String GEO_KEY = "road:nodes:370100";
    @Autowired
    private RedissonClient redissonClient;

    @Test
    public void searchPoint(a) {
        double longitude = 117.1089668;
        double latitude = 36.7151653;
        RGeo<String> geo = redissonClient.getGeo(GEO_KEY, new StringCodec());
        GeoSearchArgs args = GeoSearchArgs.from(longitude, latitude)
                .radius(100, GeoUnit.METERS)
                .order(GeoOrder.ASC)
                .count(1);
        Map<String, Double> resultMap = geo.searchWithDistance(args);
        resultMap.keySet().stream().forEach(member ->
                log.info("Search result, matching position identifier: {}, distance: {}.", member, resultMap.get(member))); }}Copy the code

conclusion

It is possible to operate Redis Geo either way, but it is important to note that the Spring Data method cannot obtain the Distance of points in the range if the Redisson dependency is integrated.