使用 PostGIS 查找最近点
Find nearest point using PostGIS
在带有 PostGIS 扩展的 PostgreSQL 12 上,我有两个表定义如下:
CREATE TABLE table_a (
id_a integer,
id_b integer,
coord geometry,
);
CREATE INDEX table_a_coord_idx ON table_a USING gist (coord);
CREATE TABLE table_b (
id_b integer,
coord geometry,
);
CREATE INDEX table_b_coord_idx ON table_b USING gist (coord);
两个表都有大约 300 万个条目。 coord
列仅包含点几何。 id_b
的值最初为空。
我的目标是为 table_a
中的每个点找到距离 table_b
最近的点并填写 id_b
列。
我写了一个小 Python 脚本来通过基于索引的 KNN 搜索来实现这一点:
import psycopg2 as pg
conn = pg.connect()
cur = conn.cursor()
cnt = 0
cur.execute('SELECT id_a, coord FROM table_a WHERE id_b IS NULL')
for row in cur.fetchall():
cnt += 1
cur.execute('SELECT id_b FROM table_b ORDER BY geom <-> %s LIMIT 1;', (row[1],))
nearest_vertex = cur.fetchone()
cur.execute('UPDATE table_a SET id_b=%s WHERE id_a=%s', (nearest_vertex[0], row[0]))
if cnt % 1000 == 0:
conn.commit()
conn.commit()
此代码有效。但是处理一个条目平均需要0.6s,因此处理所有条目需要大约三周的时间。
有人知道如何加快这个过程吗?
在一个循环中,1 条 1 条地处理记录,给数据库带来大量网络流量。
相反,尝试在一条语句中一次更新所有条目(如果您愿意,可以从 pyton 脚本发送)。
UPDATE table_a
SET id_b = (
SELECT id_b
FROM table_b
ORDER BY table_b.geom <-> table_a.geom
LIMIT 1
)
WHERE id_b IS NULL;
有点晚了,但我的第一个镜头是检查这样的查询:
-- Find the nearest hospital to each school
-- that is within 3000 units of the school.
SELECT DISTINCT ON (s.gid) s.gid, s.school_name, s.geom, h.hospital_name
FROM schools s
LEFT JOIN hospitals h ON ST_DWithin(s.the_geom, h.geom, 3000)
ORDER BY s.gid, ST_Distance(s.geom, h.geom);
来自 postgis 手册 http://postgis.net/docs/manual-3.0/ST_DWithin.html。只要确保你在几何列上有索引并避免大半径。半径越大查询越慢
在带有 PostGIS 扩展的 PostgreSQL 12 上,我有两个表定义如下:
CREATE TABLE table_a (
id_a integer,
id_b integer,
coord geometry,
);
CREATE INDEX table_a_coord_idx ON table_a USING gist (coord);
CREATE TABLE table_b (
id_b integer,
coord geometry,
);
CREATE INDEX table_b_coord_idx ON table_b USING gist (coord);
两个表都有大约 300 万个条目。 coord
列仅包含点几何。 id_b
的值最初为空。
我的目标是为 table_a
中的每个点找到距离 table_b
最近的点并填写 id_b
列。
我写了一个小 Python 脚本来通过基于索引的 KNN 搜索来实现这一点:
import psycopg2 as pg
conn = pg.connect()
cur = conn.cursor()
cnt = 0
cur.execute('SELECT id_a, coord FROM table_a WHERE id_b IS NULL')
for row in cur.fetchall():
cnt += 1
cur.execute('SELECT id_b FROM table_b ORDER BY geom <-> %s LIMIT 1;', (row[1],))
nearest_vertex = cur.fetchone()
cur.execute('UPDATE table_a SET id_b=%s WHERE id_a=%s', (nearest_vertex[0], row[0]))
if cnt % 1000 == 0:
conn.commit()
conn.commit()
此代码有效。但是处理一个条目平均需要0.6s,因此处理所有条目需要大约三周的时间。
有人知道如何加快这个过程吗?
在一个循环中,1 条 1 条地处理记录,给数据库带来大量网络流量。
相反,尝试在一条语句中一次更新所有条目(如果您愿意,可以从 pyton 脚本发送)。
UPDATE table_a
SET id_b = (
SELECT id_b
FROM table_b
ORDER BY table_b.geom <-> table_a.geom
LIMIT 1
)
WHERE id_b IS NULL;
有点晚了,但我的第一个镜头是检查这样的查询:
-- Find the nearest hospital to each school
-- that is within 3000 units of the school.
SELECT DISTINCT ON (s.gid) s.gid, s.school_name, s.geom, h.hospital_name
FROM schools s
LEFT JOIN hospitals h ON ST_DWithin(s.the_geom, h.geom, 3000)
ORDER BY s.gid, ST_Distance(s.geom, h.geom);
来自 postgis 手册 http://postgis.net/docs/manual-3.0/ST_DWithin.html。只要确保你在几何列上有索引并避免大半径。半径越大查询越慢