Для веб-приложения, поддерживаемого DynamoDB, мне нужно сгенерировать уникальные стабильные URL-адреса, которые надежно ссылаются на уникальные строки в таблице DynamoDB.
В прошлом для приложения, поддерживаемого PostgreSQL, у меня были хорошие результаты от использования автоинкрементного целого числа в качестве первичного ключа и использования хэш целого числа:
In [1]: import hashids
In [2]: hasher = hashids.Hashids(min_length=5, alphabet='abcdefghijklmnopqrstuvwxyz0123456789')
In [3]: hasher.encode(12345)
Out[2]: 'e763y'
Затем я бы использовал это в URL-адресе:
http://example.com/random-mutable-title-e763y/
Однако в DynamoDB нет автоматически увеличивающихся первичных ключей, и вместо них рекомендуются UUID.
Однако UUID содержат 128 бит, а хеш-код UUID намного длиннее:
In [3]: import uuid
In [4]: hasher.encode(uuid.uuid4().int)
Out[4]: '5j257lmv00xwo5pvo132783jv0qkq'
Это слишком долго для URL-адреса или, по крайней мере, просто уродливо:
http://example.com/random-mutable-title-5j257lmv00xwo5pvo132783jv0qkq/
Я видел, что рекомендуется просто маскировать UUID:
In [5]: hasher.encode((uuid.uuid4().int & (1 << 64) - 1))
Out[5]: 'v0qnq92ml7oj382'
Но даже это кажется немного длинным:
http://example.com/random-mutable-title-v0qnq92ml7oj382/
Я мог бы отпилить больше битов:
In [6]: hasher.encode((uuid.uuid4().int & (1 << 32) - 1))
Out[6]: 'lj044pkn'
Но это кажется немного опасным:
In [7]: len(set(uuid.uuid4().int & (1 << 32) - 1 for _ in range(100000)))
Out[7]: 99999
Что здесь лучше/безопаснее всего делать? Я не ожидаю большой нагрузки на запись в эту таблицу, так что мне нужно разбить и реализовать схему целочисленного автоинкремента с условной записью?
Обновление:
Я только что понял, что если я сдвину вправо 32 бита UUID1, он будет довольно уникальным:
In [8]: len(set(uuid.uuid1().int >> 32 for _ in range(1000000)))
Out[8]: 1000000
Но вернется ли это, чтобы укусить меня? :D
Обновление 2:
Чтобы ответить на некоторые вопросы из комментариев:
Мое приложение будет единственным, записывающим в эту таблицу.
Приложение написано на Python.
Схема данных для таблицы использует хэш-ключ для идентификатора пользователя и ключ сортировки, который зависит от того, что хранится в строке. Допустим, я храню записи пользователей, проекты пользователей и документы, содержащиеся в проектах. Я, вероятно, в конечном итоге получу глобальный вторичный индекс для поддержки запросов на основе хэша URL, если только хэш и первичный ключ записи не будут эквивалентны.
Общие запросы к таблице будут такими:
- Пользователь по электронной почте (для входа в систему), поддерживаемый другим GSI
- Все пользователи (по хеш-ключу)
- Все проекты пользователя (с использованием хеш-ключа и ключа сортировки
beginswith()
) - Конкретный проект (при поддержке обсуждаемой GSI)
- Все документы в конкретном проекте (ключ хеширования и ключ сортировки
beginswith()
) - Индивидуальный документ (поддерживается обсуждаемым GSI)