POSTGIS:高效查询最近点
POSTGIS: querying for nearest point efficiently
我有以下问题:我有数百万个条目(地图中的点),我想将它们映射到最近的道路(OSM 数据)。我在 java 中实施了一种蛮力方法,我在其中查询 OSM 数据库以定位最近的道路,然后将 osm 对象 (road-id) 分配给相应的条目。
但是这种方法效率低下,因为对每个条目的查询需要将近 1 秒,这使得整个过程无休止。
PreparedStatement psWithLastPosition = this.conn.prepareStatement(sql);
int i = 0;
for (FCDEntry entry : dataset.getEntries()) {
i += 1;
String sqlQueryRoad = "SELECT osm_id,highway FROM planet_osm_roads ORDER BY "
+ "ST_DISTANCE('SRID=4326;"
+ ST_SetSRID.setSRID(new ST_MakePoint().createPoint(entry.getLongitude(),entry.getLatitude()), 4326).toString()
+ "'::geometry, "
+ "ST_Transform(way::geometry,4326)) ASC LIMIT 1;";
PreparedStatement psID = this.conn.prepareStatement(sqlQueryRoad);
ResultSet rs = psID.executeQuery();
String osm_id ="";
while (rs.next()) {
osm_id = rs.getString("osm_id");
}
log.info(osm_id);
PreparedStatement ps = psWithLastPosition;
ps.setString(1, entry.getAssetId());
...
ps.setInt(18, Integer.valueOf(osm_id));
ps.addBatch();
// Execute every 1000 items
if (i % 1000 == 0 || i == dataset.getEntries().size()) {
log.info(i + "/" + dataset.getEntries().size());
psWithLastPosition.executeBatch();
psWithoutLastPosition.executeBatch();
}
关于如何加快映射过程的任何想法?
解决方案基于评论(感谢@JGH)。
我不得不用 <-> 运算符更改 st_distance 命令。现在的查询速度几乎快了 x1000。
也就是说,我现在的查询是:
String sqlQueryRoad = "SELECT osm_id,highway FROM planet_osm_roads ORDER BY "
+ "way <-> ST_Transform(ST_GeomFromText('POINT ("+ entry.getLongitude() + " "
+ entry.getLatitude()+ ")',4326), 3857) ASC LIMIT 1;";
出于某种原因,我有 way 列而不是 geom 列与几何相关联(几乎我发现的所有帖子都有 geom 列,最好猜测他们更改了 OSM 数据的 osm2pgsql 插入功能)。
我有以下问题:我有数百万个条目(地图中的点),我想将它们映射到最近的道路(OSM 数据)。我在 java 中实施了一种蛮力方法,我在其中查询 OSM 数据库以定位最近的道路,然后将 osm 对象 (road-id) 分配给相应的条目。
但是这种方法效率低下,因为对每个条目的查询需要将近 1 秒,这使得整个过程无休止。
PreparedStatement psWithLastPosition = this.conn.prepareStatement(sql);
int i = 0;
for (FCDEntry entry : dataset.getEntries()) {
i += 1;
String sqlQueryRoad = "SELECT osm_id,highway FROM planet_osm_roads ORDER BY "
+ "ST_DISTANCE('SRID=4326;"
+ ST_SetSRID.setSRID(new ST_MakePoint().createPoint(entry.getLongitude(),entry.getLatitude()), 4326).toString()
+ "'::geometry, "
+ "ST_Transform(way::geometry,4326)) ASC LIMIT 1;";
PreparedStatement psID = this.conn.prepareStatement(sqlQueryRoad);
ResultSet rs = psID.executeQuery();
String osm_id ="";
while (rs.next()) {
osm_id = rs.getString("osm_id");
}
log.info(osm_id);
PreparedStatement ps = psWithLastPosition;
ps.setString(1, entry.getAssetId());
...
ps.setInt(18, Integer.valueOf(osm_id));
ps.addBatch();
// Execute every 1000 items
if (i % 1000 == 0 || i == dataset.getEntries().size()) {
log.info(i + "/" + dataset.getEntries().size());
psWithLastPosition.executeBatch();
psWithoutLastPosition.executeBatch();
}
关于如何加快映射过程的任何想法?
解决方案基于评论(感谢@JGH)。
我不得不用 <-> 运算符更改 st_distance 命令。现在的查询速度几乎快了 x1000。
也就是说,我现在的查询是:
String sqlQueryRoad = "SELECT osm_id,highway FROM planet_osm_roads ORDER BY "
+ "way <-> ST_Transform(ST_GeomFromText('POINT ("+ entry.getLongitude() + " "
+ entry.getLatitude()+ ")',4326), 3857) ASC LIMIT 1;";
出于某种原因,我有 way 列而不是 geom 列与几何相关联(几乎我发现的所有帖子都有 geom 列,最好猜测他们更改了 OSM 数据的 osm2pgsql 插入功能)。