aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--db/schema.sql28
-rw-r--r--db/schema_0033-speed-up-nearby.sql47
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Nearby.pm12
3 files changed, 58 insertions, 29 deletions
diff --git a/db/schema.sql b/db/schema.sql
index 5bac02bce..ef996fe8c 100644
--- a/db/schema.sql
+++ b/db/schema.sql
@@ -226,6 +226,7 @@ create table problem (
create index problem_state_latitude_longitude_idx on problem(state, latitude, longitude);
create index problem_user_id_idx on problem ( user_id );
create index problem_external_body_idx on problem(lower(external_body));
+create index problem_radians_latitude_longitude_idx on problem(radians(latitude), radians(longitude));
create table questionnaire (
id serial not null primary key,
@@ -242,17 +243,6 @@ create table questionnaire (
create index questionnaire_problem_id_idx on questionnaire using btree (problem_id);
--- angle_between A1 A2
--- Given two angles A1 and A2 on a circle expressed in radians, return the
--- smallest angle between them.
-create function angle_between(double precision, double precision)
- returns double precision as '
-select case
- when abs($1 - $2) > pi() then 2 * pi() - abs($1 - $2)
- else abs($1 - $2)
- end;
-' language sql immutable;
-
-- R_e
-- Radius of the earth, in km. This is something like 6372.8 km:
-- http://en.wikipedia.org/wiki/Earth_radius
@@ -274,11 +264,11 @@ create function problem_find_nearby(double precision, double precision, double p
-- table or results set in memory. That means we can't check the values of
-- the parameters, sadly.
-- Through sheer laziness, just use great-circle distance; that'll be off
- -- by ~0.1%:
- -- http://www.ga.gov.au/nmd/geodesy/datums/distance.jsp
+ -- by ~0.1%.
-- We index locations on lat/lon so that we can select the locations which lie
-- within a wedge of side about 2 * DISTANCE. That cuts down substantially
-- on the amount of work we have to do.
+ -- http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates
'
-- trunc due to inaccuracies in floating point arithmetic
select problem.id,
@@ -292,9 +282,13 @@ create function problem_find_nearby(double precision, double precision, double p
longitude is not null and latitude is not null
and radians(latitude) > radians($1) - ($3 / R_e())
and radians(latitude) < radians($1) + ($3 / R_e())
- and (abs(radians($1)) + ($3 / R_e()) > pi() / 2 -- case where search pt is near pole
- or angle_between(radians(longitude), radians($2))
- < $3 / (R_e() * cos(radians($1 + $3 / R_e()))))
+ and (
+ abs(radians($1)) + ($3 / R_e()) > pi() / 2 -- case where search pt is near pole
+ or (
+ radians(longitude) > radians($2) - asin(sin($3 / R_e())/cos(radians($1)))
+ and radians(longitude) < radians($2) + asin(sin($3 / R_e())/cos(radians($1)))
+ )
+ )
-- ugly -- unable to use attribute name "distance" here, sadly
and R_e() * acos(trunc(
(sin(radians($1)) * sin(radians(latitude))
@@ -302,7 +296,7 @@ create function problem_find_nearby(double precision, double precision, double p
* cos(radians($2 - longitude)))::numeric, 14)
) < $3
order by distance desc
-' language sql; -- should be "stable" rather than volatile per default?
+' language sql stable;
-- Comments/q&a on problems.
diff --git a/db/schema_0033-speed-up-nearby.sql b/db/schema_0033-speed-up-nearby.sql
new file mode 100644
index 000000000..845f3c22e
--- /dev/null
+++ b/db/schema_0033-speed-up-nearby.sql
@@ -0,0 +1,47 @@
+begin;
+
+create index problem_radians_latitude_longitude_idx on problem(radians(latitude), radians(longitude));
+
+drop function angle_between(double precision, double precision);
+
+create or replace function problem_find_nearby(double precision, double precision, double precision)
+ returns setof problem_nearby_match as
+ -- Write as SQL function so that we don't have to construct a temporary
+ -- table or results set in memory. That means we can't check the values of
+ -- the parameters, sadly.
+ -- Through sheer laziness, just use great-circle distance; that'll be off
+ -- by ~0.1%.
+ -- We index locations on lat/lon so that we can select the locations which lie
+ -- within a wedge of side about 2 * DISTANCE. That cuts down substantially
+ -- on the amount of work we have to do.
+ -- http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates
+'
+ -- trunc due to inaccuracies in floating point arithmetic
+ select problem.id,
+ R_e() * acos(trunc(
+ (sin(radians($1)) * sin(radians(latitude))
+ + cos(radians($1)) * cos(radians(latitude))
+ * cos(radians($2 - longitude)))::numeric, 14)
+ ) as distance
+ from problem
+ where
+ longitude is not null and latitude is not null
+ and radians(latitude) > radians($1) - ($3 / R_e())
+ and radians(latitude) < radians($1) + ($3 / R_e())
+ and (
+ abs(radians($1)) + ($3 / R_e()) > pi() / 2 -- case where search pt is near pole
+ or (
+ radians(longitude) > radians($2) - asin(sin($3 / R_e())/cos(radians($1)))
+ and radians(longitude) < radians($2) + asin(sin($3 / R_e())/cos(radians($1)))
+ )
+ )
+ -- ugly -- unable to use attribute name "distance" here, sadly
+ and R_e() * acos(trunc(
+ (sin(radians($1)) * sin(radians(latitude))
+ + cos(radians($1)) * cos(radians(latitude))
+ * cos(radians($2 - longitude)))::numeric, 14)
+ ) < $3
+ order by distance desc
+' language sql stable;
+
+commit;
diff --git a/perllib/FixMyStreet/DB/ResultSet/Nearby.pm b/perllib/FixMyStreet/DB/ResultSet/Nearby.pm
index a0ccb8a6d..670673ab3 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Nearby.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Nearby.pm
@@ -36,16 +36,4 @@ sub nearby {
return \@problems;
}
-# XXX Not currently used, so not migrating at present.
-#sub fixed_nearby {
-# my ($dist, $mid_lat, $mid_lon) = @_;
-# mySociety::Locale::in_gb_locale { select_all(
-# "select id, title, latitude, longitude, distance
-# from problem_find_nearby(?, ?, $dist) as nearby, problem
-# where nearby.problem_id = problem.id and state='fixed'
-# site_restriction
-# order by lastupdate desc", $mid_lat, $mid_lon);
-# }
-#}
-
1;