Unverified Commit e48ac075 authored by filipe oliveira's avatar filipe oliveira Committed by GitHub
Browse files

GEOSEARCH BYBOX: Simplified haversine distance formula when longitude diff is 0 (#11579)

This is take 2 of `GEOSEARCH BYBOX` optimizations based on haversine
distance formula when longitude diff is 0.
The first one was in #11535 . 

- Given longitude diff is 0 the asin(sqrt(a)) on the haversine is asin(sin(abs(u))).
- arcsin(sin(x)) equal to x when x ∈[−𝜋/2,𝜋/2]. 
- Given latitude is between [−𝜋/2,𝜋/2] we can simplifiy arcsin(sin(x)) to x.

On the sample dataset with 60M datapoints, we've measured 55% increase
in the achievable ops/sec.
parent 2d80cd78
...@@ -216,20 +216,28 @@ GeoHashFix52Bits geohashAlign52Bits(const GeoHashBits hash) { ...@@ -216,20 +216,28 @@ GeoHashFix52Bits geohashAlign52Bits(const GeoHashBits hash) {
return bits; return bits;
} }
/* Calculate distance using simplified haversine great circle distance formula.
* Given longitude diff is 0 the asin(sqrt(a)) on the haversine is asin(sin(abs(u))).
* arcsin(sin(x)) equal to x when x ∈[−𝜋/2,𝜋/2]. Given latitude is between [−𝜋/2,𝜋/2]
* we can simplify arcsin(sin(x)) to x.
*/
double geohashGetLatDistance(double lat1d, double lat2d) {
return EARTH_RADIUS_IN_METERS * fabs(deg_rad(lat2d) - deg_rad(lat1d));
}
/* Calculate distance using haversine great circle distance formula. */ /* Calculate distance using haversine great circle distance formula. */
double geohashGetDistance(double lon1d, double lat1d, double lon2d, double lat2d) { double geohashGetDistance(double lon1d, double lat1d, double lon2d, double lat2d) {
double lat1r, lon1r, lat2r, lon2r, u, v; double lat1r, lon1r, lat2r, lon2r, u, v, a;
lat1r = deg_rad(lat1d);
lon1r = deg_rad(lon1d); lon1r = deg_rad(lon1d);
lat2r = deg_rad(lat2d);
lon2r = deg_rad(lon2d); lon2r = deg_rad(lon2d);
u = sin((lat2r - lat1r) / 2);
v = sin((lon2r - lon1r) / 2); v = sin((lon2r - lon1r) / 2);
double a = u * u; /* if v == 0 we can avoid doing expensive math when lons are practically the same */
/* if v == 0 we can avoid doing expensive math */ if (v == 0.0)
if (v != 0.0){ return geohashGetLatDistance(lat1d, lat2d);
a += cos(lat1r) * cos(lat2r) * v * v; lat1r = deg_rad(lat1d);
} lat2r = deg_rad(lat2d);
u = sin((lat2r - lat1r) / 2);
a = u * u + cos(lat1r) * cos(lat2r) * v * v;
return 2.0 * EARTH_RADIUS_IN_METERS * asin(sqrt(a)); return 2.0 * EARTH_RADIUS_IN_METERS * asin(sqrt(a));
} }
...@@ -259,7 +267,7 @@ int geohashGetDistanceIfInRectangle(double width_m, double height_m, double x1, ...@@ -259,7 +267,7 @@ int geohashGetDistanceIfInRectangle(double width_m, double height_m, double x1,
double x2, double y2, double *distance) { double x2, double y2, double *distance) {
/* latitude distance is less expensive to compute than longitude distance /* latitude distance is less expensive to compute than longitude distance
* so we check first for the latitude condition */ * so we check first for the latitude condition */
double lat_distance = geohashGetDistance(x2, y2, x2, y1); double lat_distance = geohashGetLatDistance(y2, y1);
if (lat_distance > height_m/2) { if (lat_distance > height_m/2) {
return 0; return 0;
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment