Ищите более подробную информацию о «Групповом кодировании / декодировании вариаций», представленном на слайдах Джеффа - PullRequest
3 голосов
/ 06 июня 2010

Я заметил, что на слайдах Джеффа «Проблемы создания крупномасштабных систем поиска информации», которые также можно скачать здесь: http://research.google.com/people/jeff/WSDM09-keynote.pdf, был упомянут метод сжатия целых чисел, называемый «групповое кодирование переменных». Говорят, намного быстрее, чем целочисленное кодирование 7 бит на байт (в 2 раза больше). Я очень заинтересован в этом и ищу реализацию этого или любые другие подробности, которые могли бы помочь мне реализовать это самостоятельно.

Я не профессионал и не новичок в этом, и любая помощь приветствуется!

Ответы [ 4 ]

5 голосов
/ 06 июня 2010

Это относится к «переменному целочисленному кодированию», где число битов, используемых для хранения целого числа при сериализации, не фиксировано в 4 байта. В документации к буферу протокола есть хорошее описание varint .

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

CodedOutputStream содержит точную функцию кодирования WriteVarint32FallbackToArrayInline :

inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline(
    uint32 value, uint8* target) {
  target[0] = static_cast<uint8>(value | 0x80);
  if (value >= (1 << 7)) {
    target[1] = static_cast<uint8>((value >>  7) | 0x80);
    if (value >= (1 << 14)) {
      target[2] = static_cast<uint8>((value >> 14) | 0x80);
      if (value >= (1 << 21)) {
        target[3] = static_cast<uint8>((value >> 21) | 0x80);
        if (value >= (1 << 28)) {
          target[4] = static_cast<uint8>(value >> 28);
          return target + 5;
        } else {
          target[3] &= 0x7F;
          return target + 4;
        }
      } else {
        target[2] &= 0x7F;
        return target + 3;
      }
    } else {
      target[1] &= 0x7F;
      return target + 2;
    }
  } else {
    target[0] &= 0x7F;
    return target + 1;
  }
}

Каскадные if s будут добавлять дополнительные байты только в конец массива target, если величина value гарантирует эти дополнительные байты. 0x80 маскирует записываемый байт, а value смещается вниз. Из того, что я могу сказать, маска 0x7f заставляет ее обозначать «последний байт кодировки». (Когда OR'ing 0x80, старший бит всегда будет 1, тогда последний байт очищает старший бит (с помощью AND'ing 0x7f). Таким образом, при чтении varints вы читаете, пока не получите байт с ноль в старшем бите.

Я только что понял, что вы спрашивали о "кодировке группы VarInt" специально. Извините, этот код был о базовом кодировании VarInt (все еще быстрее, чем 7-битный). Основная идея выглядит похожей. К сожалению, это , а не , что используется для хранения 64-битных чисел в буферах протокола. Я не удивлюсь, если бы этот код был где-то с открытым исходным кодом.

Используя идеи varint и диаграммы "Групповая вариация" из слайдов, не должно быть слишком сложно приготовить свою собственную:)

Вот еще одна страница, описывающая Сжатие группы VarInt , которая содержит код декодирования. К сожалению, они ссылаются на общедоступные реализации, но не дают ссылок.

void DecodeGroupVarInt(const byte* compressed, int size, uint32_t* uncompressed) {
  const uint32_t MASK[4] = { 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF };
  const byte* limit = compressed + size;
  uint32_t current_value = 0;
  while (compressed != limit) {
    const uint32_t selector = *compressed++;
    const uint32_t selector1 = (selector & 3);
    current_value += *((uint32_t*)(compressed)) & MASK[selector1];
    *uncompressed++ = current_value;
    compressed += selector1 + 1;
    const uint32_t selector2 = ((selector >> 2) & 3);
    current_value += *((uint32_t*)(compressed)) & MASK[selector2];
    *uncompressed++ = current_value;
    compressed += selector2 + 1;
    const uint32_t selector3 = ((selector >> 4) & 3);
    current_value += *((uint32_t*)(compressed)) & MASK[selector3];
    *uncompressed++ = current_value;
    compressed += selector3 + 1;
    const uint32_t selector4 = (selector >> 6);
    current_value += *((uint32_t*)(compressed)) & MASK[selector4];
    *uncompressed++ = current_value;
    compressed += selector4 + 1;
  }
}
1 голос
/ 02 января 2012

Вместо декодирования с помощью битовой маски, в c / c ++ вы могли бы использовать предопределенные структуры, которые соответствуют значению в первом байте. Полный пример, который использует это: http://www.oschina.net/code/snippet_12_5083

1 голос
/ 07 ноября 2011

Я искал то же самое и нашел этот проект GitHub на Java: https://github.com/stuhood/gvi/ Выглядит многообещающе!

0 голосов
/ 22 сентября 2014

Другая реализация Java для groupvarint: https://github.com/catenamatteo/groupvarint Но я подозреваю, что очень большой переключатель имеет некоторые недостатки в Java

...