Разбивается в hadoop с помощью двоичного файла переменной длины/без разделителей

Я только начал работать над сборщиком данных на основе хаупа для открытых данных карты улиц. Есть несколько форматов, но я ориентировался на формат, основанный на протокольном буфере (обратите внимание, это не чистый pb).

Мне кажется, что было бы более эффективно предварительно разделить файл на файл последовательности - в отличие от обработки кодирования переменной длины в пользовательском формате чтения/входа - но хотелось бы проверить работоспособность.

Этот формат более подробно описан в Описании формата PBF. Но в основном это коллекция [BlobHeader,Blob ] блоки.

Есть заголовок большого двоичного объекта

message BlobHeader {
   required string type = 1;
   optional bytes indexdata = 2;
   required int32 datasize = 3;
 }

А затем Blob (размер которого определяется параметром datasize в заголовке)

 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.
 }

Очевидно, что когда вы попадаете в блоб, становится больше структуры, но я бы справился с этим в сопоставителе - то, что я хотел бы сделать, это изначально иметь по одному блобу на сопоставитель (позже может быть несколько BLOB-объектов на сопоставитель).

Некоторые из других форматов ввода/считывателей записей используют «достаточно большой» размер разделения, а затем выполняют поиск вперед/назад к разделителю, но, поскольку нет разделителя, который позволил бы мне узнать смещение больших двоичных объектов/заголовков, и нет индекса, который также указывает на них - я не вижу никакого способа получить свои точки разделения без предварительной потоковой передачи через файл.

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

Есть ли лучший способ справиться с этим - или, если нет, мысли по поводу двух предложений?


person Chris B    schedule 17.11.2013    source источник


Ответы (1)


Что ж, я начал анализировать двоичный файл в методе getSplits, и, поскольку я пропускаю более 99% данных, это происходит достаточно быстро (~ 20 секунд для файла мира planet-osm 22 ГБ). Вот метод getSplits, если кто-то еще споткнется.

@Override
public List<InputSplit> getSplits(JobContext context){
    List<InputSplit> splits = new ArrayList<InputSplit>();
    FileSystem fs = null;
    Path file = OSMPBFInputFormat.getInputPaths(context)[0]; 
    FSDataInputStream in = null;
    try {
        fs = FileSystem.get(context.getConfiguration());
        in = fs.open(file);
        long pos = 0;
        while (in.available() > 0){
            int len = in.readInt(); 
            byte[] blobHeader = new byte[len]; 
            in.read(blobHeader);
            BlobHeader h = BlobHeader.parseFrom(blobHeader);
            FileSplit split = new FileSplit(file, pos,len + h.getDatasize(), new String[] {});
            splits.add(split);
            pos += 4;
            pos += len;
            pos += h.getDatasize();
            in.skip(h.getDatasize());
        }
    } catch (IOException e) {
        sLogger.error(e.getLocalizedMessage());
    } finally {
        if (in != null) {try {in.close();}catch(Exception e){}};
        if (fs != null) {try {fs.close();}catch(Exception e){}};
    }
    return splits;
}

пока работает нормально, хотя я еще не проверил вывод. Это определенно быстрее, чем копирование pbf в hdfs, преобразование в последовательность в одном преобразователе, а затем загрузка (преобладает время копирования). Это также примерно на 20% быстрее, чем копировать внешнюю программу в файл последовательности в hdfs, а затем запускать сопоставление с hdfs (последний сценарий). Так что тут претензий нет.

Обратите внимание, что это создает маппер для каждого блока, что составляет ~ 23 тыс. мапперов для файла мира планеты. На самом деле я объединяю несколько блоков в один сплит - просто прокручивайте x раз, прежде чем сплит будет добавлен в коллекцию.

Для BlobHeader я только что скомпилировал файл protobuf .proto из вики-ссылки OSM выше. Вы также можете вытащить его, предварительно сгенерированный из двоичного класса OSM, если хотите - фрагмент maven:

<dependency>
    <groupId>org.openstreetmap.osmosis</groupId>
    <artifactId>osmosis-osm-binary</artifactId>
    <version>0.43-RELEASE</version>
</dependency>
person Chris B    schedule 20.11.2013
comment
Очень заинтересован в том, чтобы что-нибудь загружало данные OSM в Hadoop — см. /pipermail/dev/2015-January/028227.html — у вас есть это на Github или что-то еще, или это личное? - person Stev_k; 16.02.2015