Postgis SQL为最近邻居

时间:2014-04-04 05:14:59

标签: sql postgresql postgis

我试图计算最近的邻居。为此,我需要传递一个参数来限制与邻居的最大距离。例如,哪些是半径1000米范围内最近的邻居?

我做了以下事情:

我用数据创建了我的表:

id | name | latitude | longitude

之后,我执行了以下查询:

SELECT AddGeometryColumn ( 'public' , ' green ', ' geom ' , 4326 , ' POINT' , 2 );

UPDATE season
SET geom = ST_Transform(ST_PointFromText ('POINT (' || longitude || ' ' || latitude || ')', 4269), 4326);

第一个问题,巴西的SRID是4326吗?什么是4269?

第二个问题,通过执行以下SQL

SELECT id, name
FROM season
WHERE ST_DWithin (
                 geom ,
                 ST_GeomFromText ('POINT(-49.2653819 -25.4244287 )', 4326),
                 1000
                 );

这不会返回任何内容。据我所知,这个SQL会进一步指向最大距离的半径,对吗?

如果您将1000个结果显示为100000000,则会显示所有条目。

所以,我想知道这里有什么问题?

2 个答案:

答案 0 :(得分:6)

首先,如果您使用纬度,经度,则需要使用4326。

UPDATE season SET geom = ST_PointFromText ('POINT(' || longitude || ' ' || latitude || ')' , 4326 ) ;

然后在geom字段

上创建索引
CREATE INDEX [indexname] ON [tablename] USING GIST ( [geometryfield] ); 

然后你得到了kNN的近处:

SELECT *,ST_Distance(geom,'SRID=4326;POINT(newLon newLat)'::geometry) 
FROM yourDbTable
ORDER BY
yourDbTable.geom <->'SRID=4326;POINT(newLon newLat)'::geometry
LIMIT 10;

此查询将利用gist索引(http://workshops.boundlessgeo.com/postgis-intro/knn.html)的kNN功能。

返回的距离仍然是度数,而不是米(投影4326使用度数)。

解决此问题:

SELECT *,ST_Distance(geography(geom),ST_GeographyFromText('POINT(newLon newLat)') 
FROM yourDbTable
ORDER BY
yourDbTable.geom <->'SRID=4326;POINT(newLon newLat)'::geometry
LIMIT 10;

计算ST_distance时,请使用地理类型。距离总是以米为单位:

http://workshops.boundlessgeo.com/postgis-intro/geography.html

所有这些功能可能都需要最新的Postgis版本(2.0+)。我不确定。

选中此项以获取参考https://gis.stackexchange.com/questions/91765/improve-speed-of-postgis-nearest-neighbor-query/

答案 1 :(得分:3)

如果要在空间参考系统上查找Postgis中的信息,请查看表spatial_ref_sys。基于此并回答第一个问题,

select * from spatial_ref_sys where srid=4629

返回以下内容:

4269 | EPSG      |      4269 | GEOGCS["NAD83",DATUM["North_American_Datum_1983"
,SPHEROID["GRS 1980",6378137,298.257222101,AUTHORITY["EPSG","7019"]],AUTHORITY["
EPSG","6269"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01
745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4269"]] | +proj=long
lat +ellps=GRS80 +datum=NAD83 +no_defs

这表明它是使用GRS80椭圆的北美基准,而不是巴西,这与4326使用的WGS84不同,后者是GPS使用的标准。这些信息是Proj4投影库使用的,它是作为Postgis Postgis构建的一部分包含在Postgres中。

我在spatial_ref_sys中搜索了Brasil,

select * from spatial_ref_sys where auth_name ilike '%Bras%';

并且没有返回任何结果。

我确实在网上找到了对29101的引用,它使用的是南美数据,带有巴西Polyconic投影和以米为单位的单位。

要将原始示例转换为此示例,您可以使用:

select ST_Astext(ST_Transform(ST_SetSrid(ST_Makepoint(-49.265, -25.424),4326), 29101));

返回:

POINT(5476247.04359163 7178517.77380949)

并允许您以米为单位使用ST_Distance或ST_DWithin。我只放了ST_AsText以便你可以看到输出,你显然不会在使用ST_Transform的更新中实际使用它。

注意使用ST_Makepoint而不是连接坐标 - 同样的东西,但更容易阅读,imho。

要回答你的第二个问题,因为你实际上是在4326,lat / lon中工作,范围从-180到180和-90到90,如果你在ST_DWithin中使用1000作为距离,你将获得返回的每条记录,因为1000不是米,而是度数,所以你必须使用类似上面的系统。

如果您想在纬度/经度上取距离,请查看haversine formula,它可以在短距离内正常工作。