I am solving the following problem:
I have a map with many points in it and I need to find the nearest point to given location. Each point carries information about it's latitude and longitude. This is for the routing algorithm to find an origin and destination point closest to the user selected locations.
I wanted to use the "<->" operator for finding the nearest neighbour. But when testing I encountered the difficulty. It seems that the <-> is not always working properly for ordering points by distance.
When running the following query, for the first two SELECT pairs it seems that point p1 is closer to location L. While from other two query pairs the result shows that in fact p2 is closer to location L. I checked that p1 is closer to p2 using http://www.movable-type.co.uk/scripts/latlong.html. This site return the distance in km similar to the result of the third SELECT pair, which is correct, they are both using spherical model of the Earth.
By p1 I mean 14.452601,50.076207. By p2 I mean 14.452789,50.075481. By L I mean 14.451722068277277,50.07564315647511 (longitude,latitude).
Is this correct, or am i making some mistake?
SELECT
(SELECT ST_Distance(st_setsrid(st_makepoint(14.452601,50.076207),4326),st_setsrid(st_makepoint(14.451722068277277,50.07564315647511),4326)))AS geometrical_from_p1,
(SELECT ST_Distance(st_setsrid(st_makepoint(14.452789,50.075481),4326),st_setsrid(st_makepoint(14.451722068277277,50.07564315647511),4326)))AS geometrical_from_p2,
(SELECT (st_setsrid(st_makepoint(14.452601,50.076207),4326) <-> st_setsrid(st_makepoint(14.451722068277277,50.07564315647511),4326)))AS geometrical_from_p1,
(SELECT (st_setsrid(st_makepoint(14.452789,50.075481),4326) <-> st_setsrid(st_makepoint(14.451722068277277,50.07564315647511),4326)))AS geometrical_from_p2,
(SELECT ST_Distance_sphere(st_setsrid(st_makepoint(14.452601,50.076207),4326),st_setsrid(st_makepoint(14.451722068277277,50.07564315647511),4326)))AS geomethrical_from_p1,
(SELECT ST_Distance_sphere(st_setsrid(st_makepoint(14.452789,50.075481),4326),st_setsrid(st_makepoint(14.451722068277277,50.07564315647511),4326)))AS geometrical_from_p2,
(SELECT ST_Distance(ST_GeographyFromText('POINT(14.452601 50.076207)'),ST_GeographyFromText('POINT(14.451722068277277 50.07564315647511)')))AS geographical_from_p1,
(SELECT ST_Distance(ST_GeographyFromText('POINT(14.452789 50.075481)'),ST_GeographyFromText('POINT(14.451722068277277 50.07564315647511)')))geographical_from_p2
;
the 8 results for the 4 query pairs are:
0.00104424158783511; 0.00107918396178276;
0.00104493638333828; 0.00108122276233257;
88.6845186250299; 78.2447351379485;
88.8360501337395; 78.4754154775416
My application is written in java with connection to PostgreSQL 9.2 and PostGIS 2.0.3 .
Now I am using simple solution written in java which is fast and accurate enough: I just go through all the points P loaded in RAM, calculate their distance from location L and remember the one with minimal distance. I use following formula:
simple_distance = SQRT[((L.longitude-P.longitude)*LON_DEG_M)^2 + ((L.latitude-P.latitude)*LAT_DEG_M)^2]
LON_DEG_M and LAT_DEG_M represent length(in meters) of one degree of longitude/latitude at a latitude of L. I calculate them only once for L and use these values for all points P. This does not give exact distance but I use it just to find the nearest point. (SQRT is not necessary.) On my laptop it takes about 2 milliseconds to find the nearest node this way.
In the future I would like to PostGIS to calculate the nearest neighbour(s). On the internet I found the soulution suggesting using <-> operator and I tried ST_distance(geometry,geometry) function as well. As I described earlier I did not manage to make these work properly. Now I have implemented versions using ST_distance_sphere(geometry,geometry) and ST_distance(geography,geography) which seem to work properly but are slower for me.
I am using following queries:
SELECT osmid FROM nearest_node_geom_sphere ORDER BY ST_Distance_sphere(geometry,st_setsrid(st_makepoint(L.longitude,L.latitude),4326)) LIMIT 1;
SELECT osmid FROM nearest_node ORDER BY ST_Distance(geography,ST_GeographyFromText('POINT(L.longitude L.latitude)')) LIMIT 1;
Is there a way to use the <-> operator properly to return the order the distances. If no how can I improve the performance of ST_distance_sphere(geometry,geometry) and ST_distance(geography,geography). Which should be fastest to use?
For the current number of nodes I am getting the following times: (2 milliseconds for the simple java algorithm described earlier, 50 ms for St_distance_sphere(geometry,geometry), 90 ms for ST_distance(geography,geography)). I have around 9000 points in db running locally.