Каковы варианты генерации удобных для пользователя буквенно-цифровых идентификаторов (например, бизнес-идентификатор, SKU)

Вот требования:

Должно быть буквенно-цифровое, 8-10 символов, чтобы оно было удобным для пользователя. Они будут храниться как уникальные ключи в базе данных. Я использую гиды в качестве первичных ключей, поэтому предпочтительнее использовать GUID для генерации этих уникальных идентификаторов.

Я думаю о строках базового-n конвертера, который берет Guid и преобразует в уникальную строку с 8 символами.

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

Ответы

Ответ 1

Вы можете рассмотреть base 36. в том, что он может делать буквы и цифры. Попробуйте удалить я (eye) и O (Oh) из вашего набора, чтобы они не смешивались с 1 (одним) и 0 (ноль). Некоторые люди могут также жаловаться на 2 и Z.

Ответ 2

8 characters - perfectly random - 36^8 = 2,821,109,907,456 combinations
10 characters - perfectly random - 36^10 = 3,656,158,440,062,976 combinations
GUID - statistically unique* - 2^128 = 340,000,000,000,000,000,000,000,000,000,000,000,000 combinations

* fooobar.com/questions/3947/...

Проблема с преобразованием символов GUID → ; в то время как ваш идентификатор GUID статистически уникален, принимая любое подмножество, вы уменьшаете случайность и увеличиваете вероятность столкновений. Вы, конечно же, не хотите создавать не-unqiue SKU.


Решение 1:

Создайте SKU, используя данные, относящиеся к объекту и бизнес-правилам.

то есть. Вероятно, будет небольшая комбинация атрибутов, которая делает объект уникальным (естественный ключ). Объедините элементы естественного ключа, закодируйте и сжимайте их, чтобы создать SKU. Часто для этого требуется всего лишь поле даты (т.е. CreationDate) и несколько других свойств. У вас, вероятно, будет много дыр в создании sku, но sku более актуальны для ваших пользователей.

гипотетически:

Wholesaler, product name, product version, sku
Amazon,     IPod Nano,    2.2,             AMIPDNN22
BestBuy,    Vaio,         3.2,             BEVAIO32

Решение 2:

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

Реализация должна иметь таблицу key в базе данных с счетчиком. Счетчик увеличивается в транзакции. Важным моментом является то, что вместо увеличения на 1 метод в программном обеспечении захватывает блок. pseudo-С# -код выглядит следующим образом.

-- what the key table may look like
CREATE TABLE Keys(Name VARCHAR(10) primary key, NextID INT)
INSERT INTO Keys Values('sku',1)

// some elements of the class
public static SkuKeyGenerator 
{
    private static syncObject = new object();
    private static int nextID = 0;
    private static int maxID = 0;
    private const int amountToReserve = 100;

    public static int NextKey()
    {
        lock( syncObject )
        {
            if( nextID == maxID )
            {
                ReserveIds();
            }
            return nextID++;
        }
    }
    private static void ReserveIds()
    {
        // pseudocode - in reality I'd do this with a stored procedure inside a transaction,
        // We reserve some predefined number of keys from Keys where Name = 'sku'
        // need to run the select and update in the same transaction because this isn't the only
        // method that can use this table.
        using( Transaction trans = new Transaction() ) // pseudocode.
        {
             int currentTableValue = db.Execute(trans, "SELECT NextID FROM Keys WHERE Name = 'sku'");
             int newMaxID = currentTableValue + amountToReserve;
             db.Execute(trans, "UPDATE Keys SET NextID = @1 WHERE Name = 'sku'", newMaxID);

             trans.Commit();

             nextID = currentTableValue;
             maxID = newMaxID;
        }
    } 

Идея здесь заключается в том, что вы резервируете достаточно ключей, чтобы ваш код не посещал базу данных часто, так как получение диапазона ключей - дорогостоящая операция. Вам нужно иметь представление о количестве ключей, которые вам нужно зарезервировать, чтобы сбалансировать потерю ключа (перезапуск приложения) по сравнению с изнурительными клавишами слишком быстро и вернуться к базе данных. Эта простая реализация не имеет возможности повторно использовать потерянные ключи.

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

Обратите внимание, что приведенное выше свободно основано на key table, с. 222 из Шаблоны архитектуры корпоративных приложений (Fowler). Этот метод обычно используется для генерации первичных ключей без необходимости в столбце идентификации базы данных, но вы можете видеть, как он может быть адаптирован для вашей цели.

Ответ 3

Если вы ищете "удобную для пользователя", вы можете попробовать использовать целые слова, а не просто делать его коротким/буквенно-числовым, таким образом, что-то вроде:

words = [s.strip().lower() for s in open('/usr/share/dict/canadian-english') if "'" not in s]
mod = len(words)

def main(script, guid):
    guid = hash(guid)

    print "+".join(words[(guid ** e) % mod] for e in (53, 61, 71))

if __name__ == "__main__":
    import sys
    main(*sys.argv)

Что производит вывод, например:

oranjestad+compressing+wellspring
padlock+discommoded+blazons
pt+olenek+renews

Это забавно. В противном случае, просто взяв первые 8-10 символов хэша guid или sha1/md5 руководства, вероятно, ваш лучший выбор.

Ответ 4

Простейшая вещь, которая могла бы работать, - это счетчик, который увеличивается каждый раз, когда требуется значение. Восемь цифр (с левым-ноль-дополнением) дают вам 100 миллионов возможных значений 00000000 через 99999999 (хотя вы можете вставлять пробелы или дефисы для удобства чтения, как в 000-000-00).

Если вам понадобится более 100 миллионов значений, вы можете либо увеличить длину, либо использовать буквы в альтернативных позициях. Использование A0A0A0A0 через Z9Z9Z9Z9 дает вам более четырех с половиной миллиардов возможных значений (4,569,760,000). Это тривиальный бит кода, который принимает длинное целое число и создает такую ​​кодировку (mod 10 для самой правой цифры, div на 10, затем mod 26 для самой правой буквы и т.д.). Если у вас есть память для записи, самый быстрый способ состоит в том, чтобы преобразовать счетчик в массив mod 260 и использовать каждое значение mod 260 как индекс в массив двухсимвольных строк ( "A0", "A1", "A2" и т.д. через "A9", B0 "," B1 "и т.д. Через" Z9 ").

Проблема с базой 36 (упомянутая в другом ответе) состоит в том, что вам нужно не только беспокоиться о путанице читателя с подобными символами (один против I, ноль против O, два против Z, пять против S), но также о комбинациях смежных букв, которые могут восприниматься читателями как орфографические отвратительные или непристойные слова или аббревиатуры.