2008-10-20 13 views
15

Oto wymagania:Jakie są opcje generowania przyjazne dla użytkownika alfa identyfikatory numeryczne (jak id biznesu, SKU)

Musi być alfanumeryczny, 8-10 znaków tak, że jest przyjazny dla użytkownika. Będą one przechowywane jako unikalne klucze w bazie danych. Używam Guidów jako kluczy podstawowych, więc preferowana byłaby opcja używania GUID do generowania tych unikatowych identyfikatorów.

Myślę o liniach konwertera bazowego n, który pobiera Guid i konwertuje na unikatowy ciąg 8 znaków.

Krótki, lekki algorytm preferowany, jak by się go nazywało dość często.

Odpowiedz

8

Można rozważyć base 36. że może to zrobić, litery i cyfry. Rozważ usunięcie I (oka) i O (Oh) ze swojego zestawu, aby nie pomieszały się z 1 (jeden) i 0 (zero). Niektórzy ludzie mogą narzekać również na 2 i Z.

+2

Jest to prawdopodobnie najlepszy zakład, ale niestety 128-bitowy identyfikator GUID kończy się w dalszym ciągu ponad 20 znaków w bazie 36. Być może GUID nie jest najlepszym punktem wyjścia. –

+0

Guid jest łatwo dostępny z moich obiektów modelu, więc uważam, że będzie to bardzo wygodne. – Mank

+3

cóż, możesz przejść do A-Z i a-z i 0-9 do tej bazy 62. Być może to zadziała lepiej. – EvilTeach

3

Jeśli szukasz „przyjazny dla użytkownika” można spróbować użyć całych słów, zamiast po prostu czyni go krótki/alphanumberic zatem coś takiego:

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) 

która produkuje wyjście jak:

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

Co jest zabawne. W przeciwnym razie, po prostu pierwsze 8-10 znaków guid lub sha1/md5 z guid jest prawdopodobnie najlepszym rozwiązaniem.

+0

Czy szyfrowanie md5/sha1 identyfikatora GUID jest unikalne? – Mank

+0

Nie, ale pierwsze z pierwszych 10 znaków daje przestrzeń 2 ** 40 możliwości (około 1 tryliona), więc w zależności od tego, ile identyfikatorów, których szukasz, liczba kolizji * powinna * być dość niska. Dodaj ograniczenie unikalności, wycofanie i kolizje dzienników. –

3

Najprostszą rzeczą, która może pracować, jest licznik, który jest zwiększany za każdym razem, gdy wymagana jest wartość. Osiem (lewy-zero-wyściełane) cyfr daje ci 100 milionów możliwych wartości od 00000000 do 99999999 (chociaż możesz wtrącać spacje lub myślniki dla ludzkiej czytelności, jak w 000-000-00).

Jeśli potrzebujesz więcej niż 100 milionów wartości, możesz zwiększyć długość lub użyć liter na alternatywnych pozycjach. Korzystanie z A0A0A0A0 poprzez Z9Z9Z9Z9 daje ponad cztery i pół miliarda możliwych wartości (4,569,760,000) dostępnych. Jest to trywialny fragment kodu, który przyjmuje długą liczbę całkowitą i produkuje takie kodowanie (mod 10 dla cyfry po prawej stronie, div przez 10, a następnie 26 dla prawej litery, itd.) Jeśli masz pamięć do nagrywania, najszybszy sposób jest konwersja licznika na tablicę mod 260 i użycie każdej wartości mod 260 jako indeksu do tablicy ciągów dwuznakowych ("A0", "A1", "A2" itd. od "A9", " B0 "," B1 "itd. Do" Z9 ").

Problem z bazą 36 (wymienioną w innej odpowiedzi) polega na tym, że nie tylko musisz martwić się o błąd czytelnika o podobnych postaciach (jeden vs. I, zero vs. O, dwa vs. Z, pięć vs. S) ale także o kombinacjach sąsiednich liter, które mogą być postrzegane przez czytelników jako ortograficzne niesmaczne lub nieprzyzwoite słowa lub skróty.

+0

Podoba mi się Twoja sugestia. Moją jedyną obawą jest konieczność zarządzania globalnym licznikiem w aplikacji. To jeden z powodów, dla których chciałbym użyć Guida jako sekwencji, nie jest problemem. – Mank

10
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 

* Is a GUID unique 100% of the time? [stackoverflow]

Problem z GUID - konwersja> znaków; podczas gdy GUID jest statystycznie unikalny, biorąc dowolny podzbiór, zmniejszasz losowość i zwiększasz ryzyko kolizji. Na pewno nie chcesz tworzyć nie-unqiue SKU.


Rozwiązanie 1:

Tworzenie SKU wykorzystując dane odnoszące się do reguł i obiektów biznesowych.

tj. Prawdopodobnie istnieje mała kombinacja atrybutów, które czynią obiekt niepowtarzalnym (a natural key). Połącz elementy klucza naturalnego, zakoduj i skompresuj je, aby utworzyć SKU. Często potrzebne jest tylko pole daty i czasu (np. CreationDate) i kilka innych właściwości, aby to osiągnąć. Prawdopodobnie masz dużo dziur w tworzeniu sku, ale sku są bardziej odpowiednie dla twoich użytkowników.

teoretycznie:

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

Roztwór 2:

Sposób że rezerwuje zakres numerów, a następnie prowadzi się kolejno do ich uwolnienia, i nigdy nie powraca do tej samej liczby dwa. Wciąż możesz skończyć z dziurami w zasięgu. Prawdopodobnie nie musisz generować wystarczającej liczby sku, ale upewnij się, że pozwalają na to Twoje wymagania.

Implementacją jest posiadanie tabeli key w bazie danych z licznikiem. Licznik jest inkrementowany w transakcji. Ważnym punktem jest to, że zamiast inkrementować o 1, metoda w oprogramowaniu chwyta blok. kod pseudo-C# jest następujący.

-- 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; 
     } 
    } 

Chodzi o to, że zarezerwować wystarczającą ilość klawiszy tak, że kod nie wychodzi z bazy danych często, jak się kluczowy zakres jest kosztowna operacja. Musisz mieć dobry pomysł na liczbę kluczy, które musisz zarezerwować, aby zrównoważyć utratę klucza (restart aplikacji) i wyczerpanie kluczy zbyt szybko i powrót do bazy danych. Ta prosta implementacja nie ma możliwości ponownego użycia zgubionych kluczy.

Ponieważ ta implementacja opiera się na bazie danych i transakcjach, aplikacje mogą działać jednocześnie, a wszystkie generują unikalne klucze bez konieczności częstego odwiedzania bazy danych.

Uwaga powyższe jest luźno oparte na key table, strona 222 z Patterns of Enterprise Application Architecture (Fowler). Metoda ta jest zwykle używana do generowania kluczy podstawowych bez potrzeby korzystania z kolumny tożsamości bazy danych, ale można zobaczyć, w jaki sposób można ją dostosować do własnych potrzeb.

Powiązane problemy