如何以索引方式有效地存储所有 OpenStreetMap 数据?

Posted

技术标签:

【中文标题】如何以索引方式有效地存储所有 OpenStreetMap 数据?【英文标题】:How do I efficiently store all OpenStreetMap data in an indexed way? 【发布时间】:2012-02-05 20:58:12 【问题描述】:

注意:虽然我的目标是 Windows Phone 7,但它除了大小限制之外没有引入任何东西。

在尝试为 Windows Phone 7 编写 GPS / 路由 / 地图应用程序时,我试图为此使用 OpenStreetMap,并且我想将我的数据存储在我的 SQL Server Compact Edition 数据库中Windows Phone 7。这给我带来了很多麻烦,所以我不知道正确的方法是什么......

这是我的进步:

    我已下载Belgium.osm.pbf,其中包含PBF format 中的所有比利时OSM 数据。

    请注意,比利时并没有那么大,这是我居住的国家,所以这似乎是一个好的开始。

    如果我的数据库接近那个 PBF 文件的大小就好了,因为它只有 80 MB...

    使用 Marc Gravell 的 protobuf-net,我现在编写了一个解析器,它可以为我提供所有 OSM 数据。

    在第一次尝试时,我尝试将其全部加载到内存中,但这对于我的 Windows Phone 7 来说似乎太大了,因为它导致大小 > 512 MB。然后我的想法是我需要一个数据库来存储这些信息,因此将其存储在 SQL Server Compact Edition sdf 文件中似乎是合乎逻辑的。

    因此,我在 LINQ to SQL 中创建了以下 DataContext 和表:

    public class RoutingContext : DataContext
    
        public RoutingContext()
    #if WINDOWS_PHONE
            : base("Data Source = 'isostore:/RoutingDB.sdf'; Max Database Size = 1024; Max Buffer Size = 65536")
    #else
            : base("Data Source = './RoutingDB.sdf'; Max Database Size = 1024; Max Buffer Size = 65536")
    #endif
        
    
        
    
        public Table<Node> Nodes;
        public Table<Road> Roads;
        public Table<RoadNode> RoadNodes;
        public Table<NodeProperty> NodeProperties;
        public Table<RoadProperty> RoadProperties;
        public Table<StringData> Strings;
    
    
    [Table]
    public class Node
    
        [Column(IsPrimaryKey = true)]
        public int Id  get; set; 
    
        [Column()]
        public int Lon  get; set; 
    
        [Column()]
        public int Lat  get; set; 
    
    
    [Table]
    public class NodeProperty
    
        [Column()]
        public int NodeId  get; set; 
    
        [Column(DbType = "NVarChar(255) NOT NULL")]
        public int Key  get; set; 
    
        [Column(DbType = "NVarChar(255) NOT NULL")]
        public int Value  get; set; 
    
    
    [Table]
    public class RoadProperty
    
        [Column()]
        public int RoadId  get; set; 
    
        [Column(DbType = "NVarChar(255) NOT NULL")]
        public int Key  get; set; 
    
        [Column(DbType = "NVarChar(255) NOT NULL")]
        public int Value  get; set; 
    
    
    [Table]
    public class Road
    
        [Column(IsPrimaryKey = true)]
        public int Id  get; set; 
    
    
    [Table]
    public class RoadNode
    
        [Column()]
        public int RoadId  get; set; 
    
        [Column()]
        public int NodeId  get; set; 
    
    
    [Table]
    public class StringData
    
        [Column(IsPrimaryKey = true)]
        public int Id  get; set; 
    
        [Column(DbType = "NVarChar(255) NOT NULL")]
        public String String  get; set; 
    
    

    首先,我不时地使用SubmitChanges() 继续InsertOnSubmitTour(),但这显然会因为SubmitChanges() 逐行插入而变慢。所以然后我去尝试SqlBulkCopy,这显然不适用于 SQL Server Compact Edition,这让我最终选择了SqlCeBulkCopy,它似乎更快但仍然很慢。

我在使用此解决方案时遇到了两个问题:

    还是很慢。

    生成的大小要大很多倍。请注意,Belgium.osm.pbf 仅约为 80 MB。 .sdf 不过似乎是 ~592 MB,对此我有什么办法吗?

所以,这是我的问题:

    我哪里完全出错了?我应该怎么做?

    我觉得很难正确处理一个 80 MB 的文件真的很奇怪。另请注意,我目前正在我的计算机上进行所有这些计算,一旦它在计算机上正常运行,我将在 Windows Phone 7 上进行尝试。

    如果真的没有方便的 LINQ 解决方案,那么生成索引 PBF 是否有意义?

    然而,这需要我重新发明数据库已经可以提供给我的东西。

    在我的计算机上增加大小是否有意义,本质上是编写一个转换器,然后将 ~592 MB .sdf 数据库文件发送到我的手机?

    这似乎是介于选项 1 和 2 之间的最后手段,但这并不能使应用程序能够上传到 MarketPlace,因为必须提前在计算机上转换然后以某种方式将其加载到该应用程序上是非常令人讨厌的电话。

请注意,我专注于问题 1,如果证明不可能,其他问题只是解决方案,我只是遗漏了一些可以使问题变得流畅的东西,但我没有想法...

【问题讨论】:

部分我认为您应该在加载应用程序之前将所有数据放入数据库。 @surfasb:我知道,这就是我的计划。但是我的数据库目前效率很低,see an example here,我知道导入了很多无用的数据,但是很难将这些数据从数据库中取出。导入后,我必须保留一个单独的内存节点 ID 列表,以过滤掉我不需要的道路节点(因为它们是单独加载的),或者我需要在之后删除它们,但这也很慢。换句话说,我还没有找到正确的存储方式。 【参考方案1】:

为此使用数据库是有意义的。大小可能是由于 pbf 文件的紧凑性,还要记住 SQL CE 中的所有数据都是 unicode。你的问题不清楚 - 什么是慢?另外,您可以尝试在导入后压缩数据库文件,它可能会缩小文件一点。根据生成的大小,您的 .xap 可能仍然足够小以供 MarketPlace 使用。 (因为 .xap 也会压缩 sdf 文件)

【讨论】:

WriteToServer 很慢,但我想我只能尝试剥离我的数据并仅将我真正需要的内容存储在数据库中,这将进一步优化磁盘占用。我关于这个答案的问题:我可以把它改成不是 unicode 吗?紧凑型仅对插入没有零影响吗?我认为 MarketPlace 不接受这么大的文件... 我写了 SqlCeBulkCopy,我担心 WriteToServer 很慢,你能分享一些代码吗?最大 XAP 大小为 225 MB! 你在说哪个紧凑型? SqlCeEngine 的那个还是你自己写的?因为 SqlCeEngine 在运行时除了一些探测之外似乎没有做任何事情,这是因为插入语句不会生成未分配或空闲页面。我看到我可以传递允许 ASCII 字符串的排序规则,但我认为问题不在于字符串。您是否有可用的反射器,以便我可以打包输出目录而不是源目录?或者你只是想要没有库的代码?是的,我注意到你是作者,很好的支持...... :) 我的意思是 SqlCeEngine.Compact。无论您传递或定义什么排序规则,SQL Compact 数据都是 Unicode。是的,我有反射器 RoutingLibrary.exe 在this zip file,把belgium.osm.pbf放在同一个文件夹里。在命名空间 Structure 我有一个类 RoutingLoader 在其中 LoadCountry 完成所有工作;最后,如果您会看到对AddBulk 的调用,这是该类中调用您的SqlCeBulkCopy 的函数。

以上是关于如何以索引方式有效地存储所有 OpenStreetMap 数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何对聚合进行过滤以有效地使用索引?

如何有效地将用户添加到 GitLab 中的所有项目(以编程方式或其他方式)

ES6 Maps and Sets:如何有效地索引对象键?

python 有效地翻页查询以从Google App Engine数据存储中获取所有实体。

如何在给定索引列表的情况下有效地更新 numpy ndarray

Numpy:在给定索引的情况下,如何以有效的方式摆脱轴 = 1 的最小值?