Как эффективно хранить все данные OpenStreetMap в индексированном виде?

Примечание. Хотя я ориентируюсь на Windows Phone 7, в нем нет ничего, кроме ограничений по размеру.

Пытаясь написать приложение GPS/маршрутизации/карты для Windows Phone 7, я пытаюсь использовать OpenStreetMap для этого, и я хочу, чтобы мои данные хранились в SQL Server База данных Compact Edition на моей Windows Phone 7. Это доставляет мне много неприятностей, поэтому я не знаю, как правильно...

Вот мой прогресс:

  1. Я скачал Belgium.osm.pbf, который содержит все данные OSM Бельгии в формат PBF.

    Обратите внимание, что Бельгия не такая большая, это страна, в которой я живу, так что это хорошее начало.

    Было бы неплохо, если бы моя база данных была размером с этот PBF-файл, потому что она всего 80 МБ...

  2. Используя protobuf-net Марка Гравелла, я написал синтаксический анализатор, который дает мне все данные ОСМ.

  3. При первой попытке я попытался просто загрузить все это в память, но это кажется слишком большим для моего Windows Phone 7, так как в результате получается размер> 512 МБ. Тогда идея заключалась в том, что мне нужна база данных для хранения этой информации, поэтому кажется логичным хранить ее в файле SQL Server Compact Edition sdf.

  4. Следовательно, я создал следующие DataContext и таблицы в LINQ to SQL:

    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; }
    }
    
  5. Сначала я использовал InsertOnSubmitTour() с SubmitChanges() время от времени, но, по-видимому, это слишком медленно, так как SubmitChanges() вставляет строку за строкой. Затем я попробовал SqlBulkCopy, который, по-видимому, не работает для SQL Server Compact Edition, в результате чего я остановился на SqlCeBulkCopy который кажется быстрее, но все же медленный.

Есть две проблемы, которые я испытываю с этим решением:

  1. Он по-прежнему довольно медленный.

  2. Результирующий размер во много раз больше. Обратите внимание, что Belgium.osm.pbf составляет всего ~80 МБ. Однако .sdf составляет ~ 592 МБ, могу ли я что-нибудь с этим поделать?

Итак, вот мои вопросы:

  1. В чем я ошибся? Что мне делать вместо этого?

    Я нахожу это действительно странным, что так сложно правильно обработать файл размером 80 МБ. Также обратите внимание, что в данный момент я выполняю все эти вычисления на своем компьютере, и как только он будет нормально работать на компьютере, я попробую его на Windows Phone 7.

  2. Если действительно нет удобного решения LINQ, имеет ли смысл создавать индексированный PBF?

    Это, однако, требует, чтобы я заново изобретал то, что база данных уже могла мне предоставить.

  3. Есть ли смысл увеличить размер на моем компьютере, по сути, написав конвертер, а затем отправить файл базы данных размером ~592 МБ .sdf на мой телефон?

    Кажется, это последнее средство, промежуточное между вариантами 1 и 2, но это не делает приложение доступным для загрузки в MarketPlace, поскольку довольно неприятно предварительно конвертировать на компьютере, а затем каким-то образом получить его на телефон.

Обратите внимание, что я фокусируюсь на вопросе 1, а остальные вопросы являются просто решениями, если окажется, что это невозможно, я просто упустил что-то, что сделало бы это беглым, но я понятия не имею.. .


person Tamara Wijsman    schedule 05.02.2012    source источник
comment
Часть меня думает, что вы должны загрузить все данные в базу данных, прежде чем загружать приложение.   -  person surfasb    schedule 07.02.2012
comment
@surfasb: Я знаю, это то, что я планирую. Но моя база данных на данный момент довольно неэффективна, см. пример здесь, я знаю, что импортируется много бесполезных данных, но это трудно получить эти данные из базы данных. При импорте мне пришлось бы хранить отдельный список идентификаторов узлов в памяти, чтобы отфильтровать узлы для дорог, которые мне не нужны (потому что они загружаются отдельно), или мне нужно удалить их впоследствии, но это также очень медленно. Другими словами, я еще не нашел правильного способа хранить это.   -  person Tamara Wijsman    schedule 07.02.2012


Ответы (1)


Имеет смысл использовать для этого базу данных. Размер может быть из-за компактности файла pbf, также имейте в виду, что все данные в SQL CE в юникоде. Ваш вопрос неясен - что тормозит? Кроме того, вы можете попробовать сжать файл базы данных после импорта, это может немного уменьшить файл. В зависимости от полученного размера ваш .xap может оказаться достаточно маленьким для MarketPlace. (Поскольку .xap также заархивирует файл sdf)

person ErikEJ    schedule 06.02.2012
comment
WriteToServer работает медленно, но я думаю, что я не могу сделать ничего большего, кроме как попытаться разобрать мои данные и сохранить в базе данных только то, что мне действительно нужно, что еще больше оптимизирует дисковое пространство. Мои вопросы об этом ответе: могу ли я изменить его, чтобы он не был юникодом? Разве Compact не оказывает нулевого влияния только на вставки? Я не думаю, что MarketPlace принимает такие большие файлы... - person Tamara Wijsman; 06.02.2012
comment
Я написал SqlCeBulkCopy, и меня беспокоит, что WriteToServer работает медленно, не могли бы вы поделиться кодом? Максимальный размер XAP составляет 225 МБ! - person ErikEJ; 06.02.2012
comment
О каком компакте идет речь? Это SqlCeEngine или вы написали свой собственный? Поскольку SqlCeEngine, похоже, ничего не делал во время работы, кроме некоторого зондирования, это связано с тем, что операторы вставки не генерируют нераспределенные или свободные страницы. Я вижу, что могу передать сопоставление, которое позволяет использовать строки ASCII, но я не думаю, что проблема связана со строками. Есть ли у вас Reflector, чтобы я мог упаковать выходной каталог вместо исходного каталога? Или вам просто нужен код без библиотек? И да, я заметил, что вы автор, хорошая поддержка... :) - person Tamara Wijsman; 06.02.2012
comment
Я имею в виду SqlCeEngine.Compact. Данные SQL Compact представляют собой Unicode независимо от того, что вы передаете или определяете сопоставление. Да, у меня есть отражатель - person ErikEJ; 06.02.2012
comment
RoutingLibrary.exe находится в этом zip-файле, поместите belgium.osm.pbf в той же папке. В пространстве имен Structure у меня есть класс RoutingLoader, в котором LoadCountry выполняет всю работу; в последнем, если вы увидите вызовы AddBulk, которая является функцией в этом классе, которая вызывает ваш SqlCeBulkCopy. - person Tamara Wijsman; 06.02.2012
comment
Я собираюсь обратиться к Programmers.SE, чтобы посмотреть, смогу ли я найти подход, основанный на тайлах, в котором я сохраняю только конечные точки дорог, хотя у меня возникнут проблемы с выяснением того, на какой дороге я нахожусь (например, повороты шоссе). Дайте мне знать, если вы нашли что-то, что может быть проблемой. Это очень сложно... :( - person Tamara Wijsman; 06.02.2012