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 collectionlongitude
: Added longitude of GPS positionlatitude
: Added latitude of GPS positionmember
: 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 collectionlongitude
: GPS longitude to be retrievedlatutude
: GPS latitude to be retrievedradius
: Search range in meters (m), kilometers (km), miles (mi), or feet (ft)withcoord
: Outputs the matched latitude and longitudewithdist
: will match the latitude and longitude distance outputcount
: Displays the number of matchesasc|desc
Asc: 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.