Optimizing sorted GEORADIUS COUNT with partial sorting. (#8326)

This commit provides an optimization, in terms of time, for all GEORADIUS*
and GEOSEARCH* searches which utilize the default, sorted, COUNT clause.
This is commonly used for nearest-neighbor (top-K points closest to a given lat/lon)
searches. While the previous implementation appends all matching points to the
geoPoint array and performs pruning after-the-fact via a full sort and [0, count)-based
for-loop, this PR sorts only the required number of elements.

This optimization provides a 5-20% improvement in runtime depending on the
density of points of interest (POI) as well as the radius searched.
No performance degradation has been observed.
This commit is contained in:
Jonah H. Harris 2021-02-02 03:57:12 -05:00 committed by GitHub
parent 9760475a39
commit a3718cde06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -31,6 +31,7 @@
#include "geo.h"
#include "geohash_helper.h"
#include "debugmacro.h"
#include "pqsort.h"
/* Things exported from t_zset.c only for geo.c, since it is the only other
* part of Redis that requires close zset introspection. */
@ -699,10 +700,20 @@ void georadiusGeneric(client *c, int srcKeyIndex, int flags) {
long option_length = 0;
/* Process [optional] requested sorting */
if (sort == SORT_ASC) {
qsort(ga->array, result_length, sizeof(geoPoint), sort_gp_asc);
} else if (sort == SORT_DESC) {
qsort(ga->array, result_length, sizeof(geoPoint), sort_gp_desc);
if (sort != SORT_NONE) {
int (*sort_gp_callback)(const void *a, const void *b) = NULL;
if (sort == SORT_ASC) {
sort_gp_callback = sort_gp_asc;
} else if (sort == SORT_DESC) {
sort_gp_callback = sort_gp_desc;
}
if (returned_items == result_length) {
qsort(ga->array, result_length, sizeof(geoPoint), sort_gp_callback);
} else {
pqsort(ga->array, result_length, sizeof(geoPoint), sort_gp_callback,
0, (returned_items - 1));
}
}
if (storekey == NULL) {