mirror of
https://github.com/fluencelabs/redis
synced 2025-03-18 08:30:51 +00:00
GEORADIUS: Don't report duplicates when radius is huge.
Georadius works by computing the center + neighbors squares covering all the area of the specified position and radius. Then a distance filter is used to remove elements which are actually outside the range. When a huge radius is used, like 5000 km or more, adjacent neighbors may collide and be the same, leading to the reporting of the same element multiple times. This only happens in the edge case of huge radius but is not ideal. A robust but slow solution would involve qsorting the range to remove all the duplicates. However since the collisions are only in adjacent boxes, for the way they are ordered in the code, it is much faster to just check if the current box is the same as the previous one processed. This commit adds a regression test for the bug. Fixes #2767.
This commit is contained in:
parent
0a91fc459f
commit
3c23b5ffd0
12
src/geo.c
12
src/geo.c
@ -319,7 +319,7 @@ int membersOfGeoHashBox(robj *zobj, GeoHashBits hash, geoArray *ga, double lon,
|
||||
/* Search all eight neighbors + self geohash box */
|
||||
int membersOfAllNeighbors(robj *zobj, GeoHashRadius n, double lon, double lat, double radius, geoArray *ga) {
|
||||
GeoHashBits neighbors[9];
|
||||
unsigned int i, count = 0;
|
||||
unsigned int i, count = 0, last_processed = 0;
|
||||
|
||||
neighbors[0] = n.hash;
|
||||
neighbors[1] = n.neighbors.north;
|
||||
@ -336,7 +336,17 @@ int membersOfAllNeighbors(robj *zobj, GeoHashRadius n, double lon, double lat, d
|
||||
for (i = 0; i < sizeof(neighbors) / sizeof(*neighbors); i++) {
|
||||
if (HASHISZERO(neighbors[i]))
|
||||
continue;
|
||||
|
||||
/* When a huge Radius (in the 5000 km range or more) is used,
|
||||
* adjacent neighbors can be the same, leading to duplicated
|
||||
* elements. Skip every range which is the same as the one
|
||||
* processed previously. */
|
||||
if (last_processed &&
|
||||
neighbors[i].bits == neighbors[last_processed].bits &&
|
||||
neighbors[i].step == neighbors[last_processed].step)
|
||||
continue;
|
||||
count += membersOfGeoHashBox(zobj, neighbors[i], ga, lon, lat, radius);
|
||||
last_processed = i;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -64,6 +64,11 @@ start_server {tags {"geo"}} {
|
||||
r georadius nyc -73.9798091 40.7598464 10 km COUNT 2 DESC
|
||||
} {{wtc one} q4}
|
||||
|
||||
test {GEORADIUS HUGE, issue #2767} {
|
||||
r geoadd users -47.271613776683807 -54.534504198047678 user_000000
|
||||
llength [r GEORADIUS users 0 0 50000 km WITHCOORD]
|
||||
} {1}
|
||||
|
||||
test {GEORADIUSBYMEMBER simple (sorted)} {
|
||||
r georadiusbymember nyc "wtc one" 7 km
|
||||
} {{wtc one} {union square} {central park n/q/r} 4545 {lic market}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user