在C#中对osm-File(osm.pbf)的处理和过滤时间太长

问题描述 投票:2回答:1

场景:我想编写自己的地址自动完成API,就像一个Google提供的那样。 (非常基本:街道,门牌号,城市,邮政编码,国家/地区)。它仅供私人使用和培训用途。我想从一开始就涵盖大约100万个地址。

使用的技术: .Net Framework(不是Core),C#,Visual Studio,OSMSharp,Microsoft SQL-Server,Web Api 2(尽管将来我可能会切换到ASP.Net Core。)

方法:

  • 设置项目(用于演示目的的Web Api 2或控制台项目)
  • 使用DownloadClient()(https://download.geofabrik.de/)从OpenStreetMaps下载相关文件
  • 使用OSMSharp读取文件并过滤掉相关数据。
  • 将过滤后的数据转换为数据表。
  • 使用DataTable馈送SQLBulkCopy方法以将数据导入数据库。

问题:步骤4花费的时间太长。对于格式为osm.pbf的“ RegierungsbezirkKöln”之类的文件,大约为160MB(未压缩的osm文件大约为2.8 GB),大约需要4-5个小时。我想对此进行优化。另一方面,将DataTable批量复制到数据库(大约100万行)仅需5秒钟。 (哇,太棒了。)

最小复制量: https://github.com/Cr3pit0/OSM2Database-Minimal-Reproduction

我尝试过的事情:

  • 在SQL Server中使用存储过程。这带来了完全不同的问题集,我并没有设法使其正常工作(主要是因为未压缩的osm.pbf文件超过2GB,而SQL Server却不喜欢这样)

  • 请采用其他方法来过滤数据并将其从文件转换为数据表(或CSV)。

  • 使用Overpass-API。尽管我在某处读到Overpass-API不适用于10,000个以上的数据集。

  • 向StackOverflow上的Jedi-Grandmasters寻求帮助。 (当前正在处理中...:D)

代码提取:

public static DataTable getDataTable_fromOSMFile(string FileDownloadPath)
{

    Console.WriteLine("Finished Downloading. Reading File into Stream...");

    using (var fileStream = new FileInfo(FileDownloadPath).OpenRead())
    {
        PBFOsmStreamSource source = new PBFOsmStreamSource(fileStream);

        if (source.Any() == false)
        {
            return new DataTable();
        }

        Console.WriteLine("Finished Reading File into Stream. Filtering and Formatting RawData to Addresses...");
        Console.WriteLine();

        DataTable dataTable = convertAdressList_toDataTable(
                    source.Where(x => x.Type == OsmGeoType.Way && x.Tags.Count > 0 && x.Tags.ContainsKey("addr:street"))
                    .Select(Address.fromOSMGeo)
                    .Distinct(new AddressComparer())
                );

        return dataTable;
    }
};
private static DataTable convertAdressList_toDataTable(IEnumerable<Address> addresses)
{
    DataTable dataTable = new DataTable();

    if (addresses.Any() == false)
    {
        return dataTable;
    }

    dataTable.Columns.Add("Id");
    dataTable.Columns.Add("Street");
    dataTable.Columns.Add("Housenumber");
    dataTable.Columns.Add("City");
    dataTable.Columns.Add("Postcode");
    dataTable.Columns.Add("Country");

    Int32 counter = 0;

    Console.WriteLine("Finished Filtering and Formatting. Writing Addresses From Stream to a DataTable Class for the Database-SQLBulkCopy-Process ");

    foreach (Address address in addresses)
    {
        dataTable.Rows.Add(counter + 1, address.Street, address.Housenumber, address.City, address.Postcode, address.Country);
        counter++;

        if (counter % 10000 == 0 && counter != 0)
        {
            Console.WriteLine("Wrote " + counter + " Rows From Stream to DataTable.");
        }
    }

    return dataTable;
};
c# .net openstreetmap large-data large-files
1个回答
0
投票

好吧,我想我明白了。筛选后,文件大小大约为600mb且大约310万行数据的时间大约为12分钟。

我尝试的第一件事是用FastMember替换填充DataTable的逻辑。哪个可行,但没有提供我希望的性能提升(3小时后我取消了该过程...)。经过更多研究后,我偶然发现了一个旧项目,名为“ osm2mssql”(https://archive.codeplex.com/?p=osm2mssql)。我使用了一部分代码,直接从osm.pbf文件中读取数据,并将其修改为我的用例(→从Ways中提取地址数据)。实际上,我确实使用FastMember向数据表中写入IEnumerable<Address>,但是我不需要OSM-Sharp以及它们具有的任何其他依赖项。非常感谢您对FastMember的建议。在以后的项目中,我一定会记住该图书馆。

对于那些感兴趣的人,我相应地更新了我的Github-Project(https://github.com/Cr3pit0/OSM2Database-Minimal-Reproduction)(尽管我没有彻底对其进行测试,因为我从Test-Project转移到了Real Deal,这是一个Web Api)

我很确定它可以进一步优化,但是我不认为我现在处于关注状态。我猜一个方法可能需要每月12分钟才能更新整个数据库,这需要12分钟。现在,我可以继续优化自动完成的查询。

所以非常感谢写“ osm2mssql”的人。

© www.soinside.com 2019 - 2024. All rights reserved.