Подтвердить что ты не робот

URL-компактное представление GUID/UUID?

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

Прямо сейчас, вместо использования стандартного представления abcd-efgh -..., вместо этого я использую необработанные байты и base64-кодировку, что приводит к несколько более короткой строке.

Но возможно ли это сделать еще короче?

Я в порядке, теряя некоторую степень уникальности и сохраняя счетчик, но сканирование всех существующих ключей не является вариантом. Предложения?

4b9b3361

Ответ 1

Я использовал кодировку Ascii85 для написания указателя в столбце базы данных в 20 символах ASCII. Я написал код С#, если это полезно. Конкретный набор символов может отличаться для кодировки URL, но вы можете выбрать, какие символы подходят вашему приложению. Он доступен здесь: Каков наиболее эффективный способ кодирования произвольного GUID в читаемый ASCII (33-127)?

Ответ 2

Конечно, просто используйте базу размером больше 64. Вам нужно будет закодировать их с помощью пользовательского алфавита, но вы сможете найти еще несколько "ур-безопасных" печатных символов ASCII.

Base64 кодирует 6 бит с использованием 8, поэтому значение 16-байтного GUID становится 22 байтами. Вы можете уменьшить это символом или двумя, но не намного больше.

Ответ 3

Я не уверен, что это возможно, но вы можете поместить все созданные GUID в таблицу и использовать в URL-адрес только индекс GUID в таблице.

Вы также можете уменьшить длину указателя - например, используйте 2 байта, чтобы указать количество дней с 2010 года, например, и 4 байта для количества милисекунд с начала текущего дня. У вас будут столкновения только для 2 GUID, сгенерированных в том же миллисекунде. Вы также можете добавить еще 2 случайных байта, которые сделают это еще лучше.

Ответ 4

Вы можете приблизиться к этому с другого направления. Произведите кратчайшее строковое представление и переведите его в Guid.

Сгенерируйте ключ, используя определенный алфавит, как показано ниже:

В psuedocode:

string RandomString(char[] alphabet, int length)
{
  StringBuilder result = new StringBuilder();
  for (int i = 0; i < length; i++)
    result.Append(alphabet[RandomInt(0, alphabet.Length)]);

  return result;
}

Если вы сохраняете длину строки < 16, вы можете просто шестнадцатеричный кодировать результат и передать его конструктору Guid для синтаксического анализа.

Ответ 5

не для одной и той же проблемы, но очень близко - я использовал CRC64, Base64, и вы получили 11 байт, CRC64 был протестирован (не доказан), чтобы НЕ производить дубликаты в широком диапазоне строк.

И поскольку по определению это 64-битная длина, вы получаете ключ, который вдвое меньше.

Чтобы напрямую ответить на исходный вопрос - вы можете CRC64 кодировать любое представление ваших GUID.

Или просто запустите CRC64 на бизнес-ключ, и у вас будет уникальная 64-битная вещь, которую вы можете затем base64.

Ответ 6

Я нашел это обсуждение интересным: https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/

В основном вы берете 36 символов и превращаете их в 16 байт двоичных файлов, но сначала сортируете три временных фрагмента с помощью хранимой процедуры:

set @uuid:= uuid();
select @uuid;
+--------------------------------------+
| @uuid                                |
+--------------------------------------+
| 59f3ac1e-06fe-11e6-ac3c-9b18a7fcf9ed |
+--------------------------------------+

CREATE DEFINER=`root`@`localhost`
    FUNCTION `ordered_uuid`(uuid BINARY(36))
    RETURNS binary(16) DETERMINISTIC
    RETURN UNHEX(CONCAT(SUBSTR(uuid, 15, 4),SUBSTR(uuid, 10, 4),SUBSTR(uuid, 1, 8),SUBSTR(uuid, 20, 4),SUBSTR(uuid, 25)));

select hex(ordered_uuid(@uuid));
+----------------------------------+
| hex(ordered_uuid(@uuid))         |
+----------------------------------+
| 11e606fe59f3ac1eac3c9b18a7fcf9ed |
+----------------------------------+

Ответ 7

(долгое время, но в то же время приходило к такой же потребности)

UUID имеют длину 128 бит, представленную 32 шестью плюс 4 дефисами. Если мы используем словарь из 64 (2 ^ 6) печатных ascii `s, это просто вопрос преобразования из 32 групп из 4 бит (длина шестнадцатеричного) в 22 группы из 6 бит.

Вот краткое описание UUID. Вместо 36 символов вы получаете 22, не теряя исходных бит.

https://gist.github.com/tomlobato/e932818fa7eb989e645f2e64645cf7a5

class UUIDShortner
    IGNORE = '-'
    BASE6_SLAB = ' ' * 22

    # 64 (6 bits) items dictionary
    DICT = 'a'.upto('z').to_a +
        'A'.upto('Z').to_a +
        '0'.upto('9').to_a +
        ['_', '-'] 

    def self.uuid_to_base6 uuid
        uuid_bits = 0

        uuid.each_char do |c|
            next if c == IGNORE
            uuid_bits = (uuid_bits << 4) | c.hex
        end

        base6 = BASE6_SLAB.dup

        base6.size.times { |i|
            base6[i] = DICT[uuid_bits & 0b111111]
            uuid_bits >>= 6
        }

        base6
    end
end

# Examples:

require 'securerandom'
uuid = ARGV[0] || SecureRandom.uuid
short = UUIDShortner.uuid_to_base6 uuid
puts "#{uuid}\n#{short}"

# ruby uuid_to_base6.rb
# c7e6a9e5-1fc6-4d5a-b889-4734e42b9ecc
# m75kKtZrjIRwnz8hLNQ5hd