我试图计算最近的邻居。为此,我需要传递一个参数来限制与邻居的最大距离。例如,哪些是半径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,则会显示所有条目。
所以,我想知道这里有什么问题?
答案 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,它可以在短距离内正常工作。