[英]Postgis SQL for nearest neighbors
I'm trying to calculate the nearest neighbors. 我正在尝试计算最近的邻居。 For that, I need to pass a parameter to limit the maximum distance from the neighbors. 为此,我需要传递一个参数来限制与邻居的最大距离。 For example, which are the nearest neighbors within a radius of 1000 meters? 例如,哪些是半径1000米内最近的邻居?
I did the following : 我做了以下事情:
I created my table with the data: 我用数据创建了我的表:
id | name | latitude | longitude
After that, I executed the following query : 之后,我执行了以下查询:
SELECT AddGeometryColumn ( 'public' , ' green ', ' geom ' , 4326 , ' POINT' , 2 );
UPDATE season
SET geom = ST_Transform(ST_PointFromText ('POINT (' || longitude || ' ' || latitude || ')', 4269), 4326);
First question, Is the SRID of Brazil 4326? 第一个问题,巴西的SRID是4326吗? What would be 4269 ? 什么是4269?
Second question, by doing the following SQL 第二个问题,通过执行以下SQL
SELECT id, name
FROM season
WHERE ST_DWithin (
geom ,
ST_GeomFromText ('POINT(-49.2653819 -25.4244287 )', 4326),
1000
);
This returns nothing. 这什么都不返回。 From what I understand, this SQL would further point the radius of the maximum distance, right? 据我所知,这个SQL会进一步指向最大距离的半径,对吧?
It appears if you put 1000 results for 100000000, all my entries appear . 如果您将1000个结果显示为100000000,则会显示所有条目。
So, I wonder what is wrong here? 所以,我想知道这里有什么问题?
First, If you are using latitude, longitude, you need to use 4326. 首先,如果您使用纬度,经度,则需要使用4326。
UPDATE season SET geom = ST_PointFromText ('POINT(' || longitude || ' ' || latitude || ')' , 4326 ) ;
Then you create an index on the geom field 然后在geom字段上创建索引
CREATE INDEX [indexname] ON [tablename] USING GIST ( [geometryfield] );
Then you get the kNN neightbors: 然后你会得到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;
This query will take advantage of kNN functionality of the gist index ( http://workshops.boundlessgeo.com/postgis-intro/knn.html ). 此查询将利用gist索引的kNN功能( http://workshops.boundlessgeo.com/postgis-intro/knn.html )。
Still the distance returned will be in degrees, not meters (projection 4326 uses degrees). 返回的距离仍然是度数,而不是米(投影4326使用度数)。
To fix this: 解决这个问题:
SELECT *,ST_Distance(geography(geom),ST_GeographyFromText('POINT(newLon newLat)')
FROM yourDbTable
ORDER BY
yourDbTable.geom <->'SRID=4326;POINT(newLon newLat)'::geometry
LIMIT 10;
When you calculate the ST_distance use the geography type. 计算ST_distance时使用地理类型。 There distance is always in meters: 距离总是以米为单位:
http://workshops.boundlessgeo.com/postgis-intro/geography.html http://workshops.boundlessgeo.com/postgis-intro/geography.html
All this functionality will probably need a recent Postgis version (2.0+). 所有这些功能可能都需要最新的Postgis版本(2.0+)。 I am not sure though. 我不确定。
Check this for reference https://gis.stackexchange.com/questions/91765/improve-speed-of-postgis-nearest-neighbor-query/ 请查看此参考https://gis.stackexchange.com/questions/91765/improve-speed-of-postgis-nearest-neighbor-query/
If you want to find information in Postgis on spatial reference systems look in the table spatial_ref_sys. 如果要在空间参考系统上查找Postgis中的信息,请查看表spatial_ref_sys。 Based on that and to answer you first question, 基于此并回答你的第一个问题,
select * from spatial_ref_sys where srid=4629
returns the following: 返回以下内容:
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
This indicates that it is a North American Datum, and not Brasil, using the GRS80 ellipse, which is not the same as the WGS84 one used by 4326, which is the standard used by GPS. 这表明它是使用GRS80椭圆的北美基准,而不是巴西,这与4326使用的WGS84不同,后者是GPS使用的标准。 This information is what is used by the Proj4 projections library, which is included as part of a Postgis build on Postgres. 这些信息是Proj4投影库使用的,它是作为Postgis Postgis构建的一部分包含在Postgres中的。
I searched for Brasil in spatial_ref_sys, 我在spatial_ref_sys中搜索了Brasil,
select * from spatial_ref_sys where auth_name ilike '%Bras%';
and this returned no results. 这没有结果。
I did find a reference to 29101 on the web, which uses a South American datum, with a Brazilian Polyconic projection and units in metres. 我确实在网上找到了对29101的引用,它使用的是南美数据,其中包含巴西Polyconic投影和以米为单位的单位。
To convert you original example to this, you could use: 要将原始示例转换为此,您可以使用:
select ST_Astext(ST_Transform(ST_SetSrid(ST_Makepoint(-49.265, -25.424),4326), 29101));
which returns: 返回:
POINT(5476247.04359163 7178517.77380949) 要点(5476247.04359163 7178517.77380949)
and would allow you to use ST_Distance or ST_DWithin in meters. 并允许您以米为单位使用ST_Distance或ST_DWithin。 I only put the ST_AsText so you can see the output, you obviously wouldn't actually use that in an update using ST_Transform. 我只放了ST_AsText以便你可以看到输出,你显然不会在使用ST_Transform的更新中实际使用它。
Note the use of ST_Makepoint instead of concatenating coordinates -- the same thing, but easier to read, imho. 注意使用ST_Makepoint而不是连接坐标 - 同样的事情,但更容易阅读,imho。
To answer your second question, because you are effectively working in 4326, lat/lon, which ranges from -180 to 180 and -90 to 90, if you used 1000 as the distance in ST_DWithin, you will get every record returned, because the 1000 is not meters, but degrees, so you would have to use something like the system above. 要回答你的第二个问题,因为你有效地工作在4326,lat / lon,范围从-180到180和-90到90,如果你在ST_DWithin中使用1000作为距离,你将获得返回的每条记录,因为1000不是米,而是度,所以你必须使用类似上面的系统。
If you want to take distance in lat/lon, have a look at the haversine formula which will work fine for short distances. 如果你想在纬度/经度上取一段距离,可以看一下在短距离内可以正常使用的半正式公式 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.