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

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

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

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

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

Ответы [ 5 ]

10 голосов
/ 21 октября 2008
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's - statistically unique* - 2^128 = 340,000,000,000,000,000,000,000,000,000,000,000,000 combinations

* Является ли GUID уникальным в 100% случаев? [StackOverflow]

Проблема с вашим GUID -> преобразование символов; в то время как ваш GUID является статистически уникальным, взяв любое подмножество, вы уменьшаете случайность и увеличиваете вероятность столкновений. Вы, конечно, не хотите создавать неуникальные 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 захватывает блок. псевдо-c # -код выглядит следующим образом.

-- 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) . Этот метод обычно используется для генерации первичных ключей без использования столбца идентификаторов базы данных, но вы можете увидеть, как его можно адаптировать для ваших целей.

8 голосов
/ 20 октября 2008

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

3 голосов
/ 20 октября 2008

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

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

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

3 голосов
/ 20 октября 2008

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

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 хеша guid.

2 голосов
/ 20 октября 2008

Вы можете попробовать алгоритм хэширования CRC32. CRC32 генерирует строку из 8 символов.

http://en.wikipedia.org/wiki/Cyclic_redundancy_check

http://textop.us/Hashing/CRC

...