使用ThreadPoolExecutor调用OSMnx查询POI时如何规避Overpass限制并提速?
提速方案与同半径查询实现建议
一、解决OSMNX查询越跑越慢的核心问题
- 开启缓存+控制请求频率:你跑100个簇后速度骤降,本质是OpenStreetMap(OSM)API触发了限流机制——频繁请求会被限制访问速度。给OSMNX开启本地缓存,重复查询的区域直接读本地文件,不用每次请求API:
同时别开太多线程,OSM建议每秒最多1-2个请求,线程数设2-4足够,多了反而会被限流拖慢。import osmnx as ox ox.config(cache_folder="./osm_local_cache", use_cache=True) - 批量拉取替代单点查询:别每个簇中心单独调用
features_from_point,先收集所有簇的坐标范围,生成一个覆盖所有簇的大包围盒,用ox.features_from_bbox一次性拉取所有需要的POI类型,之后在本地用空间索引(比如rtree库)给每个簇快速匹配对应的POI。这样能把几百次API请求压缩成1-2次,速度直接起飞。
二、实现聚类与查询半径一致的方法
如果想让聚类半径和查询半径都用1000米,别用BallTree划分簇,换DBSCAN聚类更合适:
- 先把经纬度转成UTM投影(纽约对应EPSG:32618),因为DBSCAN用欧氏距离计算,转成米单位后半径更准确。然后用
sklearn.cluster.DBSCAN,设置eps=1000(单位米)、min_samples=1,这样每个簇就是1000米范围内的点位集合,簇中心取簇内点位的平均坐标即可。 - 之后用上面的批量查询方法,拉取所有1000米范围的POI,再给每个簇匹配对应区域的POI,完美实现同半径查询。
三、并发编程的正确打开方式
作为并发新手,别盲目堆线程/进程,推荐用concurrent.futures.ThreadPoolExecutor,注意这几点:
- 线程数控制在2-4,避免触发OSM限流。
- 每个查询任务里加0.5-1秒的短暂延迟,降低请求频率。
- 优先用多线程而非多进程——OSMNX的缓存是进程隔离的,多进程会重复缓存浪费空间,反而拖慢速度。
四、其他细节优化
- 坐标投影统一:全程用UTM投影(米单位)做聚类和距离计算,避免经纬度转米的误差,OSMNX查询时也可以指定投影,减少转换耗时。
- 精准过滤POI类型:查询时直接指定需要的标签,比如地铁用
{'railway': ['station', 'subway_entrance']},公交用{'highway': ['bus_stop']},博物馆用{'tourism': ['museum']},别拉取所有POI再过滤,减少数据传输和处理量。 - 及时释放内存:处理完每个簇的POI后,删除没用的变量,避免内存占用过高拖慢后续操作。
内容的提问来源于stack exchange,提问作者Soren V. Raben
相关产品推荐
相关产品推荐

