RU:PBF Format

From OpenStreetMap Wiki
Jump to navigation Jump to search

broom

Help (89606) - The Noun Project.svg

Формат PBF ("Protocolbuffer Binary Format") предназначен в первую очередь для замены Формата XML. Файл всей планеты в формате PBF примерно в два раза меньше по размеру чем OSM XML, сжатый архиватором gzip и примерно на 30% меньше чем OSM XML, сжатый архиватором bzip2. По сравнению с OSM XML, сжатый gzip, запись файла формата PBF происходит примерно в 5 раз быстрее, а чтение в 6 раз быстрее. Формат PBF был разработан для поддержки лучшей расширяемости и гибкости в будущем.

Формат, лежащий в основе файла, поддерживает доступ к произвольному блоку файлу. Каждый блок файла декодируется независимо и содержит ~8k объектов OSM в стандартной конфигурации. Теги элементов не кодируются; все ключи и значения хранятся в неизменном виде как строки. Для масштабируемости в будущем, допускаются 64-битные идентификаторы точек, линий и отношений. Текущий сериализатор (RU:Osmosis) сохраняет порядок элементов OSM, и их тегов. Чтобы гибко работать с разными разрешениями, разрешение (детализация) используемая для записи местоположения и временных меток регулируется до 1 милисекунды и 1 наноградуса. По умолчанию используется разрешение 1000 милисекунд и 100 наноградусов, соответствующих приблизительно 1 см в районе экватора. Такая детализация сейчас используется в базе OSM.

Файлы имеют расширение *.osm.pbf

В настоящее время, эталонная реализация PBF представленная в RU:Osmosis, разделена на две части, специфическая часть osmosis, хранится в Osmosis repository [1], и общая часть, хранящаяся в[2]. Эта общая часть используется для построения osmpbf.jar (используется в osmosis и других java-ридерах PBF) и также содержит определения используемого PBF протокола (файлы *.proto).

Программы, поддерживающие PBF

Множество программ, используемых в OSM уже поддерживают PBF в добавление к оригинальному формату XML, также существуют инструменты для конвертирования из PBF в OSM XML и наоборот.

Смотрите PBF/Software Compliance для более детальной информации о том, какие виды файлов PBF какой программой поддерживаются.

Внутреннее устройство

Низкоуровневое кодирование

Google protocol buffers (далее Protobuf) используется на низшем уровне хранения данных. Учитывая спецификацию файла, который может состоять из одного или нескольких сообщений, компилятор Protobuf создает алгоритм низкоуровневой сериализации. Сообщения могут содержать другие сообщения, формируя иерархические структуры. Protobuf также поддерживает расширяемость; новые поля могут быть добавлены к сообщению и старые клиенты могут читать эти сообщения без перекомпиляции. Для большей информации, смотрите http://code.google.com/p/protobuf/ или читайте the respective article на Google's Opensource Blog. Google официально поддерживает C++, Java, и Python, но компиляторы существуют и для других языков. Вот пример структуры сообщения:

message Node {
   required sint64 id = 1;
   required sint64 lat = 7;
   required sint64 lon = 8;
   repeated uint32 keys = 9 [packed = true]; // Denote strings 
   repeated uint32 vals = 10 [packed = true];// Denote strings
   optional Info info = 11; // Contains metadata
}

Protobuf использует разное количество бит для записи целых чисел. Целое число кодируется в 7 битах на байт, где старший бит указывает на наличие или отсутствие следующего байта для чтения. Когда сообщения содержат небольшие целые числа, размер файла минимален. Существуют 2 кодировки, одна предназначена для натуральных чисел и другая для целых чисел со знаком. В стандартной кодировке числа [0,127] требуют один байт, числа [128,16383] требуют 2 байта и так далее. В кодировке со знаком, бит знака помещается в наименее значащую позицию; числа [-64,63] требуют один байт, числа [-8192,8191] требуют 2 байта и так далее. Для более подробной информации о формате сериализации сообщений Protobuf, смотрите вышеприведенный сайт.

Создаваемые файлы на Java используют пакет crosby.binary. На других языках, создаваемые файлы используют пакет OSMPBF.

Формат файла

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

Формат представлен повторяющейся последовательностью:

  • int4: длина сообщения BlobHeader в сетевом порядке байтов
  • сериализованное сообщение BlobHeader
  • сериализованное сообщение Blob (его размер указан в заголовоке)

BlobHeader в настоящее время определен как:

 message BlobHeader {
   required string type = 1;
   optional bytes indexdata = 2;
   required int32 datasize = 3;
 }
  • type содержит тип данных в сообщение блока.
  • indexdata - это некоторый произвольный блок, который может включать метаданные о последующем блоке данных (например для данных OSM, он может содержать координаты ограничивающей рамки). Это "заглушка", предназначенная для использования в будущем устройстве индексированных *.osm.pbf файлов.
  • datasize содержит сериализованный размер последующего сообщения Blob.

(Пожалуйста, обратите внимание что сообщение BlobHeader раньше называлось BlockHeader. Оно было переименовано в версии 1.1 чтобы не путать его с HeaderBlock, о котором сказано ниже)

Сообщение Blob в настоящий момент используется для хранения произвольного блока данных, either uncompressed or in zlib/deflate compressed format.

 message Blob {
   optional bytes raw = 1; // No compression
   optional int32 raw_size = 2; // Only set when compressed, to the uncompressed size
   optional bytes zlib_data = 3;
   // optional bytes lzma_data = 4; // PROPOSED.
   // optional bytes OBSOLETE_bzip2_data = 5; // Deprecated.
 }

Примечание (Декабрь 2010): В настоящий момент не cуществует кодировщиков, поддерживающих lzma или bzip2. Чтобы упростить реализацию декодеров, bzip2 был объявлен устаревшим и LZMA has become relegated to a proposed extension.

Для быстрого обнаружения неправильных или поврежденных файлов, я ограничил максимальный размер сообщений BlobHeader и Blob. Длина сообщения BlobHeader *should* be меньше чем 32 Кб и *must* be меньше чем 64 Кб. Несжатая длина сообщения Blob *should* be меньше чем 16 Мб и *must* be меньше чем 32 Мб.

Кодирование элементов OSM в блоках файла

В настоящий момент я определил два типа блоков файла для данных OSM. Это строки текстового типа, которые хранятся в поле type в сообщении BlobHeader.

  • 'OSMHeader': Сообщение Blob содержит сериализованное сообщение HeaderBlock (Смотрите osmformat.proto). Каждый файл должен содержать один из этих блоков до первого блока'OSMData'.
  • 'OSMData': Сообщение Blob содержит сериализованное сообщение PrimitiveBlock. (Смотрите osmformat.proto). Эти блоки содержат элементы OSM.

Такая конструкция позволяет другим программам расширять формат, включая блоки файлов или дополнительные типы для их собственных целей. Парсеры должны игнорировать и пропускать блоки файлов, которые они не распознают.

Определение блоков файла OSMHeader

message HeaderBlock {
  optional HeaderBBox bbox = 1;
  /* Additional tags to aid in parsing this dataset */
  repeated string required_features = 4;
  repeated string optional_features = 5;

  optional string writingprogram = 16; 
  optional string source = 17; // From the bbox field.
}

To offer forward and backward compatibility, a parser needs to know if it is able to parse a file. This is done by required features. If a file contains a required feature that a parser does NOT understand, it must reject the file with an error, and report which required features it does not support.

Currently the following features are defined:

  • "OsmSchema-V0.6" -- File contains data with the OSM v0.6 schema.
  • "DenseNodes" -- File contains dense nodes and dense info.

In addition, a file may have optional properties that a parser can exploit. For instance, the file may be pre-sorted, and not need sorting before being used. Or, the ways in the file may have bounding boxes precomputed. If a program encounters an optional feature it does not know, it can still safely read the file. If a program expects an optional feature that is not there, it can error out. I propose the following optional features:

  • "Has_Metadata" -- Does the file contain author and timestamp metadata?
  • "Sort.Type_then_ID" -- Entities are sorted by type then ID.
  • "Sort.Geographic" -- Entities are in some form of geometric sort.

However, they are unused.

Definition of OSMData fileblock

To encode OSM entities into protocol buffers, I collect 8k entities to form a PrimitiveBlock, which is serialized into the Blob portion of an 'OsmData' fileblock.

message PrimitiveBlock {
  required StringTable stringtable = 1;
  repeated PrimitiveGroup primitivegroup = 2;

  // Granularity, units of nanodegrees, used to store coordinates in this block
  optional int32 granularity = 17 [default=100]; 

  // Offset value between the output coordinates coordinates and the granularity grid, in units of nanodegrees.
  optional int64 lat_offset = 19 [default=0];
  optional int64 lon_offset = 20 [default=0]; 

  // Granularity of dates, normally represented in units of milliseconds since the 1970 epoch.
  optional int32 date_granularity = 18 [default=1000]; 


  // Proposed extension:
  //optional BBox bbox = XX;
}

Within each block, I extract all strings (key, value, role, user) into a separate string table. Thereafter, strings are referred to by their index into this table, except that index=0 is used as a delimiter when encoding DenseNodes. This means that I can not safely store a useful string in that slot. At present, I store an empty string at index=0 and never use that slot. To ensure that frequently used strings have small indexes, I sort the string table by the use frequency for each string. To improve deflate compressibility of the stringtable I then sort strings that have the same frequency lexicographically.

Each PrimitiveBlock is independently decompressable, containing *all* of the information to decompress the entities it contains. It contains a string table, it also encodes the granularity for both position and timestamps. A block may contain any number of entities, as long as the size limits for a block are obeyed. However, for simplicity, the current osmosis (0.38) implementation always uses 8k entities in a block.

In addition to granularity, the primitive block also encodes a latitude and longitude offset value. These values, measured in units of nanodegrees, must be added to each coordinate.

latitude = .000000001 * (lat_offset + (granularity * lat))
longitude = .000000001 * (lon_offset + (granularity * lon))

Where latitude is the latitude in degrees, granularity is the granularity given in the PrimitiveBlock, lat_offset is the offset given in the PrimitiveBlock, and lat/lon is encoded in a Node or delta-encoded in a DenseNode. The explanation of the equation for longitude is analogous.

The reason that lat_offset and lon_offset exist is for concisely representing isohypsis data (contour lines) or other data that occurs in a regular grid. Say we wished to represent such data that was at a 100 microdegree grid. We would like to use a granularity of 100000 nanodegrees for the highest compression, except that that could only represent points of the form (.0001*x,.0001*y), when the real gridded data may be of the form (.00003345+.0001*x, .00008634+.0001*y). By using lat_offset=3345 and lon_offset=8634, we can represent this 100 microdegree grid exactly.

For datestamps,

millisec_stamp = timestamp*date_granularity.

Where timestamp is the timestamp encoded in an Info or delta encoded in a DenseInfo, date_granularity is given in the PrimitiveBlock, and millisec_stamp is the date of the entity, measured in number of seconds since the 1970 epoch. To get the date measured in seconds since the 1970 epoch, divide millisec_stamp by 1000.

Within each primitiveblock, I then divide entities into groups that contain consecutive messages all of the same type (node/way/relation).

message PrimitiveGroup {
  repeated Node     nodes = 1;
  optional DenseNodes dense = 2;
  repeated Way      ways = 3;
  repeated Relation relations = 4;
  repeated ChangeSet changesets = 5;
}

After being serialized into a string, each primitiveblock is optionally gzip/deflate compressed individually when stored in the Blob fileblock.

Ways and Relations

For ways and relations, which contain the ID's of other nodes, I exploit the tendency of consecutive nodes in a way or relation to have nearby node ID's by using delta compression, resulting in small integers. (I.E., instead of encoding x_1, x_2, x_3, I encode x_1, x_2-x_1, x_3-x_2, ...). Except for that, ways and relations are mostly encoded in the way one would expect. Tags are encoded as two parallel arrays, one array of string-id's of the keys, and the other of string-id's of the values.


message Way {
   required int64 id = 1;
   // Parallel arrays.
   repeated uint32 keys = 2 [packed = true];
   repeated uint32 vals = 3 [packed = true];

   optional Info info = 4;

   repeated sint64 refs = 8 [packed = true];  // DELTA coded
}

Relations use an enum to represent member types.

message Relation {
  enum MemberType {
    NODE = 0;
    WAY = 1;
    RELATION = 2;
  } 
   required int64 id = 1;

   // Parallel arrays.
   repeated uint32 keys = 2 [packed = true];
   repeated uint32 vals = 3 [packed = true];

   optional Info info = 4;

   // Parallel arrays
   repeated int32 roles_sid = 8 [packed = true];
   repeated sint64 memids = 9 [packed = true]; // DELTA encoded
   repeated MemberType types = 10 [packed = true];
}

Metadata includes non-geographic information about an object, such as:

message Info {
   optional int32 version = 1 [default = -1];
   optional int32 timestamp = 2;
   optional int64 changeset = 3;
   optional int32 uid = 4;
   optional int32 user_sid = 5; // String IDs
}

Nodes

Nodes can be encoded one of two ways, as a Node (defined above) and a special dense format. In the dense format, I store the group 'columnwise', as an array of ID's, array of latitudes, and array of longitudes. Each column is delta-encoded. This reduces header overheads and allows delta-coding to work very effectively.

Keys and values for all nodes are encoded as a single array of stringid's. Each node's tags are encoded in alternating <keyid> <valid>. We use a single stringid of 0 to delimit when the tags of a node ends and the tags of the next node begin. The storage pattern is: ((<keyid> <valid>)* '0' )*

message DenseNodes {
   repeated sint64 id = 1 [packed = true]; // DELTA coded

   //repeated Info info = 4;
   optional DenseInfo denseinfo = 5;

   repeated sint64 lat = 8 [packed = true]; // DELTA coded
   repeated sint64 lon = 9 [packed = true]; // DELTA coded

   // Special packing of keys and vals into one array. May be empty if all nodes in this block are tagless.
   repeated int32 keys_vals = 10 [packed = true]; 
}

DenseInfo does a similar delta coding on metadata.

Format example

In the following, we will have a look into the bytes of an OSM PBF file. The small regional extract bremen.osm.pbf (geofabrik.de, 2011-01-13) is used as an example.

Every data is preceded by a variable identifier. This identifier consists of type and id; the bits 0 through 2 stand for the type, bits 3 abd above for the id. These types may be used:

  • 0: V (Varint) int32, int64, uint32, uint64, sint32, sint64, bool, enum
  • 1: D (64-bit) fixed64, sfixed64, double
  • 2: S (Length-delimited) string, bytes, embedded messages, packed repeated fields
  • 5: I (32-bit) fixed32, sfixed32, float
00000000  00 00 00 0d - длина в байтах блока для BlobHeader, порядок байт сетевой
00000000  __ __ __ __ 0a - тип S 1
00000000  __ __ __ __ __ 09 - длина 9 байт
00000000  __ __ __ __ __ __ 4f 53  4d 48 65 61 64 65 72 - "OSMHeader"
00000000  __ __ __ __ __ __ __ __  __ __ __ __ __ __ __ 18 - V 3 'datasize'
00000010  7c - длина 124 байта
00000010  __ 10 - V 2 'raw_size'
00000010  __ __ 71 - длина 113 байт
00000010  __ __ __ 1a - S 3 'zlib_data'
00000010  __ __ __ __ 78 - длина 120 байт

--- упакованная секция:
00000010  __ __ __ __ __ 78 9c e3  92 e2 b8 70 eb da 0c 7b  ||.q.xx.....p...{|
00000020  81 0b 7b 7a ff 39 49 34  3c 5c bb bd 9f 59 a1 61  |..{z.9I4<\...Y.a|
00000030  ce a2 df 5d cc 4a 7c fe  c5 b9 c1 c9 19 a9 b9 89  |...].J|.........|
00000040  ba 61 06 7a 66 4a 5c 2e  a9 79 c5 a9 7e f9 29 a9  |.a.zfJ\..y..~.).|
00000050  c5 4d 8c fc c1 7e 8e 01  c1 1e fe 21 ba 45 46 26  |.M...~.....!.EF&|
00000060  96 16 26 5d 8c 2a 19 25  25 05 56 fa fa e5 e5 e5  |..&].*.%%.V.....|
00000070  7a f9 05 40 a5 25 45 a9  a9 25 b9 89 05 7a f9 45  |z..@.%E..%...z.E|
00000080  e9 fa 89 05 99 fa 40 43  00 c0 94 29 0c
--- распаковано --->
00000000  0a - тип S 1 
00000000  __ 1a - длина 26 байт
00000000  __ __ 08 d0 da d6 98 3f  10 d0 bc 8d fe 42 18 80
00000010  e1 ad b7 8f 03 20 80 9c  a2 fb 8a 03 - BBOX (4*Varint)
00000010  __ __ __ __ __ __ __ __  __ __ __ __ 22 - S 4 'required_features'
00000010  __ __ __ __ __ __ __ __  __ __ __ __ __ 0e - длина 14 байт
00000010  __ __ __ __ __ __ __ __  __ __ __ __ __ __ 4f 73
00000020  6d 53 63 68 65 6d 61 2d  56 30 2e 36 - "OsmSchema-V0.6"
00000020  __ __ __ __ __ __ __ __  __ __ __ __ 22 - S 4 'required_features'
00000020  __ __ __ __ __ __ __ __  __ __ __ __ __ 0a - длина 10 байт
00000020  __ __ __ __ __ __ __ __  __ __ __ __ __ __ 44 65
00000030  6e 73 65 4e 6f 64 65 73 - "DenseNodes"
00000030  __ __ __ __ __ __ __ __  82 01 - S 16 'writingprogram'
00000030  __ __ __ __ __ __ __ __  __ __ 0f - длина 15 байт
00000030  __ __ __ __ __ __ __ __  __ __ __ 53 4e 41 50 53
00000040  48 4f 54 2d 72 32 34 39  38 34 - "SNAPSHOT-r24984"
00000040  __ __ __ __ __ __ __ __  __ __ 8a 01 - S 17 'source'
00000040  __ __ __ __ __ __ __ __  __ __ __ __ 24 - длина 36 байт
00000040  __ __ __ __ __ __ __ __  __ __ __ __ __ 68 74 74
00000050  70 3a 2f 2f 77 77 77 2e  6f 70 65 6e 73 74 72 65
00000060  65 74 6d 61 70 2e 6f 72  67 2f 61 70 69 2f 30 2e
00000070  36 - "http://www.openstreetmap.org/api/0.6"
<--- распаковано ---

00000080  __ __ __ __ __ __ __ __  __ __ __ __ __ 00 00 00
00000090  0d - длина в байтах блока для BlobHeader, порядок байт сетевой
00000090  __ 0a - тип S 1 
00000090  __ __ 07 - length 7 bytes
00000090  __ __ __ 4f 53 4d 44 61  74 61 "OSMData"
00000090  __ __ __ __ __ __ __ __  __ __ 18 - V 3 'datasize'
00000090  __ __ __ __ __ __ __ __  __ __ __ 90 af 05 - 87952 bytes long
00000090  __ __ __ __ __ __ __ __  __ __ __ __ __ __ 10 - V 2 'raw_size'
00000090  __ __ __ __ __ __ __ __  __ __ __ __ __ __ __ 8f
000000a0  84 08 - 131599 bytes long
000000a0  __ __ 1a - S 3 'zlib_data'
000000a0  __ __ __ 88 af 05 - length 87944 bytes

--- compressed section:
000000a0  __ __ __ __ __ __ 78 9c  b4 bc 09 5c 14 57 ba 28  |......x....\.W.(|
000000b0  5e 75 aa ba ba ba ba 69  16 11 d1 b8 90 b8 1b 41  |^u.....i.......A|
000000c0  10 11 97 98 c4 2d 31 1a  27 b9 9a 49 ee 64 ee 8c  |.....-1.'..I.d..|
000000d0  69 a0 95 8e 40 9b 06 62  32 f7 dd f7 5c 00 01 11  |i...@..b2...\...|
000000e0  11 05 11 11 71 43 45 44  40 05 44 54 14 17 44 44  |....qCED@.DT..DD|
000000f0  40 16 15 dc 00 37 50 44  05 c4 05 7d df 39 55 dd  |@....7PD...}.9U.|
etc.
--- decompressed --->
00000000  0a - S 1 'stringtable'
00000000  __ d4 2e - length 5972 bytes
00000000  __ __ __ 0a - S 1
00000000  __ __ __ __ 00 length 0 bytes
00000000  __ __ __ __ __ 0a - S 1
00000000  __ __ __ __ __ __ 07 length 7 bytes
00000000  __ __ __ __ __ __ __ 44  65 65 6c 6b 61 72 - "Deelkar"
00000000  __ __ __ __ __ __ __ __  __ __ __ __ __ __ 0a 0a  |.......Deelkar..|
00000010  63 72 65 61 74 65 64 5f  62 79 0a 04 4a 4f 53 4d  |created_by..JOSM|
00000020  0a 0b 45 74 72 69 63 43  65 6c 69 6e 65 0a 04 4b  |..EtricCeline..K|
00000030  6f 77 61 0a 05 55 53 63  68 61 0a 0d 4b 61 72 74  |owa..UScha..Kart|
00000040  6f 47 72 61 70 48 69 74  69 0a 05 4d 75 65 63 6b  |oGrapHiti..Mueck|
etc.
--- decompressed part form offset 5975 --->
00000000  12 - S 2 'primitivegroup'
00000000  __ ad d5 07 - length 125613 bytes
00000000  __ __ __ __ 12 - S 2 -- Tag #2 in a 'PrimitiveGroup', containing a serialized DenseNodes.
00000000  __ __ __ __ __ a9 d5 07 - of length 125609 bytes
00000000  __ __ __ __ __ __ __ __  0a - S 1 - Tag #1 in a DenseNodes, which is an array of packed varints. 
00000000  __ __ __ __ __ __ __ __  __ df 42 - of length 8543 bytes
00000000  __ __ __ __ __ __ __ __  __ __ __ ce ad 0f 02 02  |..........B.....|
00000010  02 02 04 02 02 02 02 02  02 02 02 02 02 02 02 02  |................|
00000020  02 02 02 c6 8b ef 13 02  02 02 02 02 02 02 02 f0  |................|
00000030  ea 01 02 02 02 02 02 02  02 02 02 02 02 02 02 02  |................|

    Each varint is stored consecutively. We process until we have read 8543 bytes worth, then resume parsing the DenseNodes. The varints are delta-encoded node id numbers.

00000040  02 02 02 04 02 04 02 02  04 02 02 02 02 02 02 02  |................|
00000050  02 02 02 02 02 02 02 02  02 02 02 02 02 02 02 02  |................|
00000060  02 02 02 02 02 02 02 02  02 02 02 02 02 02 02 04  |................|
00000070  02 02 06 44 02 02 02 02  02 02 02 02 02 02 02 02  |...D............|
00000080  68 02 02 02 02 02 02 02  02 02 02 02 04 02 02 06  |h...............|
00000090  02 02 0c 02 02 02 0a 02  02 02 02 06 0c 06 02 04  |................|
000000a0  02 06 02 02 02 02 02 02  02 02 02 02 02 02 02 02  |................|
000000b0  02 02 02 02 02 02 02 02  04 04 02 06 04 04 10 02  |................|
000000c0  04 02 04 18 0a 02 02 02  02 02 02 02 02 02 02 02  |................|
000000d0  04 06 02 02 04 02 02 02  02 04 02 02 02 02 08 02  |................|
000000e0  02 02 02 02 02 02 02 02  02 02 02 cc 06 02 02 02  |................|
000000f0  02 02 02 02 02 02 02 02  04 02 02 02 02 02 02 02  |................|
00000100  02 02 02 02 02 02 02 02  02 02 02 02 02 02 02 02  |................|
00000110  02 02 02 02 02 02 02 02  36 02 02 04 04 04 02 02  |........6.......|
00000120  02 02 02 02 02 02 02 02  02 02 02 02 02 02 02 02  |................|
etc.
<--- decompressed ---

Of course, the protocol buffer library handles all of these low-level encoding details.

The code

The codebase is split into two pieces. Common code that is application-independent exists on github.

This includes the protocol buffer definitions, and Java
code that operates at the fileblock level.

http://github.com/scrosby/OSM-binary


Unfortunately, osmosis, mkgmap, and the splitter each use a different internal representation for OSM entities. This means that I have to reimplement the entity serialization and parsing code for each program and there is less common code between the implementations than I would like. The serializer and deserializer for osmosis are in trunk.

A deserializer for an older version of the mkgmap splitter (circa
5/2010), this is available on github at:
http://github.com/scrosby/OSM-splitter

Miscellaneous notes

Загрузить

Geofabrik.de предлагает вырезку OSM данных в protobuf двоичном формате для многих регионов.

Смотри также

  • PBF Perl Parser
  • Учебник, как как анализировать PBF с помощью Python [3]
  • Protocol Buffers в Википедии
  • OSMCompiler
  • Osmium C++/Javascript среда для работы с OSM файлами
  • Imposm Библиотека на Питоне для разбора OpenStreetMap данных в XML и PBF форматах
  • libosmpbfreader Простая библиотека на C++ читающая OpenStreetMap двоичные файлы
  • osm-read node.js библиотека для разбора OpenStreetMap данных в XML и PBF форматах
  • pbf_parser Руби модуль для легкого разбора файлов PBF
  • osmpbf2sqlite Преобразование osm pbf файла в sqlite базу данных.