You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无内存压力分析德国OpenStreetMap PBF文件并构建街道与城镇名称数据库?

解决Pyrosm处理德国OSM道路数据时的内存不足问题

嘿,我完全理解你的困扰——德国的OSM道路数据体量确实很大,一次性加载整个数据集到内存里肯定会爆内存。你之前尝试用生成器的思路是对的,但问题在于get_network()方法本身是一次性把所有数据加载成GeoDataFrame,所以直接迭代它的行其实还是先把整个数据读进内存了,没从根源解决问题。下面给你几个可行的方案:

方案1:按行政区批量处理(最容易上手)

既然你已经确认处理单个行政区的数据是可行的,那可以自动化遍历德国的所有行政区,逐个处理后合并结果。Pyrosm支持直接下载单个州/行政区的数据,不用先下载整个德国的大文件:

from pyrosm import get_data, OSM
import pandas as pd

# 德国的州列表,你可以按需调整更细的行政区
german_states = ["baden-wuerttemberg", "bayern", "berlin", "brandenburg", 
                 "bremen", "hamburg", "hessen", "mecklenburg-vorpommern", 
                 "niedersachsen", "nordrhein-westfalen", "rheinland-pfalz", 
                 "saarland", "sachsen", "sachsen-anhalt", "schleswig-holstein", "thueringen"]

all_road_names = []

for state in german_states:
    print(f"正在处理 {state}...")
    # 下载单个州的数据
    state_data = get_data(state)
    osm = OSM(state_data)
    # 提取驾驶道路
    roads = osm.get_network(network_type="driving")
    # 提取非空的道路名称并添加到总列表
    state_roads = roads["name"].dropna().tolist()
    all_road_names.extend(state_roads)
    # 手动释放内存
    del roads, osm, state_data

# 去重(可选,根据你的需求)
unique_road_names = list(set(all_road_names))

这个方法的好处是完全复用你已经熟悉的Pyrosm API,每个批次的数据量小,不会爆内存。

方案2:用Pyrosm的过滤参数减少加载的数据

get_network()其实支持通过filter参数只加载你需要的字段,不用把所有道路属性都读进来,这样能大幅减少内存占用:

from pyrosm import get_data, OSM

# 下载德国数据
de = get_data("germany")
osm = OSM(de)

# 只提取道路名称和必要的基础字段,过滤掉不需要的属性
roads = osm.get_network(
    network_type="driving",
    filter={"name": True, "highway": True}  # 只保留name和highway字段
)

road_names = roads["name"].dropna().tolist()

这样加载的GeoDataFrame会小很多,因为默认get_network()会加载很多额外的属性(比如宽度、表面材质等),这些你如果不需要的话可以直接过滤掉。

方案3:用Osmium做流式处理(最省内存)

如果上面的方法还是不够,那可以直接用Pyrosm底层依赖的osmium库,它支持流式读取OSM文件,不需要把整个数据集加载到内存里。这样你可以逐行处理每个道路元素,只提取名称:

import osmium

class RoadNameHandler(osmium.SimpleHandler):
    def __init__(self):
        super().__init__()
        self.road_names = []
    
    def way(self, w):
        # 只处理驾驶道路(根据OSM的highway标签判断)
        if w.tags.get("highway") in ["motorway", "trunk", "primary", "secondary", 
                                     "tertiary", "unclassified", "residential", 
                                     "service", "motorway_link", "trunk_link", 
                                     "primary_link", "secondary_link", "tertiary_link"]:
            name = w.tags.get("name")
            if name:
                self.road_names.append(name)

# 初始化处理器并处理文件
handler = RoadNameHandler()
handler.apply_file("germany-latest.osm.pbf")  # 替换成你的PBF文件路径

# 去重后的道路名称列表
unique_road_names = list(set(handler.road_names))

这个方法是真正的流式处理,内存占用极低,因为它每次只处理一个OSM元素,处理完就丢弃,只保留你需要的名称。你需要先确保安装了osmium:pip install osmium。

为什么你之前的生成器尝试失败?

你之前的两个尝试都没解决问题,原因是:

  • 尝试1里的(OSM(obj) for obj in de)完全不对,de是PBF文件的路径字符串,不是可迭代的对象,所以这个生成器根本没用。
  • 尝试2里的for i in OSM(de).get_network(...)其实是迭代GeoDataFrame的行,但get_network()已经把整个数据集加载到内存里了,所以迭代行并没有减少内存占用。

希望这些方案能帮到你!

内容的提问来源于stack exchange,提问作者MatthiasHerp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 06:32:36