<refname><-></refname>
<refpurpose>
-Returns the 2D distance between A and B. Used in the "ORDER BY" clause to provide index-assisted nearest-neighbor result sets. For PostgreSQL below 9.5 only gives centroid distance of bounding boxes and for PostgreSQL 9.5+, does true KNN distance search giving true distance between geometries
+Returns the 2D distance between A and B. Used in the "ORDER BY" clause to provide index-assisted nearest-neighbor result sets. For PostgreSQL below 9.5 only gives centroid distance of bounding boxes and for PostgreSQL 9.5+, does true KNN distance search giving true distance between geometries, and distance sphere for geographies
</refpurpose>
</refnamediv>
<paramdef>
<type>geometry </type>
+ <parameter>B</parameter>
+ </paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>double precision <function><-></function></funcdef>
+
+ <paramdef>
+ <type>geography </type>
+
+ <parameter>A</parameter>
+ </paramdef>
+
+ <paramdef>
+ <type>geography </type>
+
<parameter>B</parameter>
</paramdef>
</funcprototype>
<note><para>Index only kicks in if one of the geometries is a constant (not in a subquery/cte). e.g. 'SRID=3005;POINT(1011102 450541)'::geometry instead of a.geom</para></note>
<para>Refer to <ulink url="http://workshops.opengeo.org/postgis-intro/knn.html">OpenGeo workshop: Nearest-Neighbour Searching</ulink> for real live example.</para>
- <para>Enhanced: 2.2.0 -- True KNN ("K nearest neighbor") behavior and geography support for PostgreSQL 9.5+</para>
+ <para>Enhanced: 2.2.0 -- True KNN ("K nearest neighbor") behavior for geometry and geography for PostgreSQL 9.5+. Note for geography KNN is based on sphere rather than spheroid. For PostgreSQL 9.4 and below, geography support is new but only supports centroid box.</para>
<para>Changed: 2.2.0 -- For PostgreSQL 9.5 users, old Hybrid syntax may be slower, so you'll want to get rid of that hack if you are running your code only on PostGIS 2.2+ 9.5+. See examples below.</para>
<para>Availability: 2.0.0 -- Weak KNN provides nearest neighbors based on geometry centroid distances instead of true distances. Exact results for points, inexact for all other types. Available for PostgreSQL 9.1+</para>
--- create table\r
+-- create table\r
CREATE TABLE knn_recheck_geom(gid serial primary key, geom geometry);\r
INSERT INTO knn_recheck_geom(gid,geom)\r
SELECT ROW_NUMBER() OVER(ORDER BY x,y) AS gid, ST_Point(x*0.777,y*0.777) As geom\r
WHERE gid IN(1000, 10000, 2000, 2614, 40000);\r
\r
\r
-SELECT gid, RANK() OVER(ORDER BY ST_Distance( 'POINT(95 10)'::geography, geog) )\r
+SELECT gid, RANK() OVER(ORDER BY ST_Distance( 'POINT(95 10)'::geography, geog,false) )\r
FROM knn_recheck_geog\r
ORDER BY 'POINT(95 10)'::geography <-> geog LIMIT 5;\r
\r
-SELECT gid, RANK() OVER(ORDER BY ST_Distance( 'POINT(-95 -10)'::geography, geog) )\r
+SELECT gid, RANK() OVER(ORDER BY ST_Distance( 'POINT(-95 -10)'::geography, geog, false) )\r
FROM knn_recheck_geog\r
ORDER BY 'POINT(-95 -10)'::geography <-> geog LIMIT 5;\r
\r
-- lateral check before index\r
-SELECT a.gid, b.gid As match, ROW_NUMBER() OVER(PARTITION BY a.gid ORDER BY ST_Distance(a.geog, b.geog, true)::numeric(16,0), b.gid ) As true_rn, ROW_NUMBER() OVER(PARTITION BY a.gid ORDER BY b.dist::numeric, b.gid) As knn_rn\r
+SELECT a.gid, ARRAY(SELECT gid\r
+ FROM knn_recheck_geog As g WHERE a.gid <> g.gid ORDER BY ST_Distance(a.geog, g.geog, false) LIMIT 5) = ARRAY(SELECT gid\r
+ FROM knn_recheck_geog As g WHERE a.gid <> g.gid ORDER BY a.geog <-> g.geog LIMIT 5) As dist_order_agree\r
FROM knn_recheck_geog As a \r
- LEFT JOIN \r
- LATERAL ( SELECT gid, geog, a.geog <-> g.geog As dist\r
- FROM knn_recheck_geog As g WHERE a.gid <> g.gid ORDER BY a.geog <-> g.geog, g.gid LIMIT 5) As b ON true\r
WHERE a.gid IN(500000,500010,1000,2614)\r
-ORDER BY a.gid, knn_rn;\r
+ORDER BY a.gid;\r
+\r
\r
-- create index and repeat\r
CREATE INDEX idx_knn_recheck_geog_gist ON knn_recheck_geog USING gist(geog);\r
\r
-SELECT gid, RANK() OVER(ORDER BY ST_Distance( 'POINT(95 10)'::geography, geog) )\r
+SELECT gid\r
FROM knn_recheck_geog\r
ORDER BY 'POINT(95 10)'::geography <-> geog LIMIT 5;\r
\r
-SELECT gid, RANK() OVER(ORDER BY ST_Distance( 'POINT(-95 -10)'::geography, geog) )\r
+SELECT gid\r
FROM knn_recheck_geog\r
ORDER BY 'POINT(-95 -10)'::geography <-> geog LIMIT 5;\r
\r
--- lateral check before index\r
-SELECT a.gid, b.gid As match, ROW_NUMBER() OVER(PARTITION BY a.gid ORDER BY ST_Distance(a.geog, b.geog, true)::numeric(16,0), b.gid ) As true_rn, ROW_NUMBER() OVER(PARTITION BY a.gid ORDER BY b.dist::numeric, b.gid) As knn_rn\r
+-- check after index\r
+set enable_seqscan = false; --sometimes doesn't want to use index\r
+SELECT a.gid, ARRAY(SELECT gid\r
+ FROM knn_recheck_geog As g WHERE a.gid <> g.gid ORDER BY ST_Distance(a.geog, g.geog, false) LIMIT 5) = ARRAY(SELECT gid\r
+ FROM knn_recheck_geog As g WHERE a.gid <> g.gid ORDER BY a.geog <-> g.geog LIMIT 5) As dist_order_agree\r
FROM knn_recheck_geog As a \r
- LEFT JOIN \r
- LATERAL ( SELECT gid, geog, a.geog <-> g.geog As dist\r
- FROM knn_recheck_geog As g WHERE a.gid <> g.gid ORDER BY a.geog <-> g.geog, g.gid LIMIT 5) As b ON true\r
WHERE a.gid IN(500000,500010,1000,2614)\r
-ORDER BY a.gid, knn_rn;\r
+ORDER BY a.gid;\r
\r
DROP TABLE knn_recheck_geog;\r
\r
--\r
-- Delete inserted spatial data\r
--\r
-DELETE FROM spatial_ref_sys WHERE srid = 4326;
\ No newline at end of file
+DELETE FROM spatial_ref_sys WHERE srid = 4326;\r
+\r