Generazione di ID leggibili / utilizzabili, brevi ma univoci


89
  • È necessario gestire> 1000 ma <10000 nuovi record al giorno

  • Non è possibile utilizzare GUID / UUID, numeri di incremento automatico ecc.

  • Idealmente dovrebbe essere lungo 5 o 6 caratteri, ovviamente può essere alfa

  • Vorrei riutilizzare gli algoritmi esistenti e noti, se disponibili

Qualcosa là fuori?


Perché non utilizzare INT o BIGINT autoincrementato? È probabilmente il più leggibile e può facilmente gestire il volume.
Malk

secondo la Q sopra, cercando di mantenerlo a 5/6 caratteri max e supportare fino a 9999 nuovi record al giorno
Kumar

@Kumar - Cosa succede se hai bisogno di più di 9999 record in un giorno? La tua soluzione proposta non sembra sostenibile.
ChaosPandion

@ ChaosPandion: Penso che queste siano probabilmente ipotesi approssimative di carico / traffico piuttosto che limiti difficili. Non sono sicuro del motivo per cui vorresti impostare un limite arbitrario al numero di transazioni giornaliere.
Paul Sasik

Potresti codificarlo in base 64 e usarlo. Non sono sicuro che potresti ridurlo più piccolo di così e utilizzare ancora caratteri leggibili. Ma direi che la base 64 è molto meno leggibile della base 32 perché richiede l'aggiunta di un qualificatore extra alla maggior parte dei caratteri (f maiuscola, o inferiore, o inferiore contro solo f, oo).
Malk

Risposte:


122

La base 62 è usata da tinyurl e bit.ly per gli URL abbreviati. È un metodo ben noto per creare ID "univoci" leggibili dall'uomo. Ovviamente dovrai memorizzare gli ID creati e controllare i duplicati durante la creazione per assicurarne l'unicità. (Vedi il codice in fondo alla risposta)

Base 62 metriche di unicità

5 caratteri in base 62 ti daranno 62 ^ 5 ID univoci = 916.132.832 (~ 1 miliardo) A 10k ID al giorno starai bene per 91k + giorni

6 caratteri in base 62 ti daranno 62 ^ 6 ID univoci = 56.800.235.584 (più di 56 miliardi) Con 10.000 ID al giorno starai bene per 5+ milioni di giorni

Base 36 metriche di unicità

6 caratteri ti daranno 36 ^ 6 ID univoci = 2.176.782.336 (2+ miliardi)

7 caratteri ti daranno 36 ^ 7 ID univoci = 78.364.164.096 (78+ miliardi)

Codice:

public void TestRandomIdGenerator()
{
    // create five IDs of six, base 62 characters
    for (int i=0; i<5; i++) Console.WriteLine(RandomIdGenerator.GetBase62(6));

    // create five IDs of eight base 36 characters
    for (int i=0; i<5; i++) Console.WriteLine(RandomIdGenerator.GetBase36(8));
}

public static class RandomIdGenerator 
{
    private static char[] _base62chars = 
        "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
        .ToCharArray();

    private static Random _random = new Random();

    public static string GetBase62(int length) 
    {
        var sb = new StringBuilder(length);

        for (int i=0; i<length; i++) 
            sb.Append(_base62chars[_random.Next(62)]);

        return sb.ToString();
    }       

    public static string GetBase36(int length) 
    {
        var sb = new StringBuilder(length);

        for (int i=0; i<length; i++) 
            sb.Append(_base62chars[_random.Next(36)]);

        return sb.ToString();
    }
}

Produzione:

z5KyMg
wd4SUp
uSzQtH
UPrGAT
UIf2IS

QCF9GNM5
0UV3TFSS
3MG91VKP
7NTRF10T
AJK3AJU7

3
sembra fantastico, qualcosa che non fa distinzione tra maiuscole e minuscole?
Kumar

2
Se vuoi evitare la distinzione tra maiuscole e minuscole puoi usare la base 36: codeproject.com/Articles/10619/Base-36-type-for-NET-C ma per ottenere così tante permutazioni come base 62 dovresti usare più caratteri nel tuo ID. È un compromesso. Oppure potresti provare a usare altri caratteri oltre all'alfa, ma questo diventa brutto per gli utenti.
Paul Sasik


12
Un pensiero. Forse elimina le vocali per evitare la generazione accidentale di parolacce. Soprattutto se è rivolto al pubblico.
Damien Sawyer

4
A seconda di dove lo stai usando (in particolare se ci si aspetta che gli umani leggano e reimmettano i codici) potresti prendere in considerazione la rimozione di caratteri spesso confusi dalla considerazione: 0 / O e I / l / 1. Questo può essere mitigato in alcuni casi da una buona scelta dei caratteri, ma non posso dire dalla domanda se l'OP avrà il controllo su questo.
GrandOpener

18

Raccomando http://hashids.org/ che converte qualsiasi numero (es. DB ID) in una stringa (usando salt).

Consente di decodificare questa stringa nel numero. Quindi non è necessario archiviarlo nel database.

Ha librerie per JavaScript, Ruby, Python, Java, Scala, PHP, Perl, Swift, Clojure, Objective-C, C, C ++ 11, Go, Erlang, Lua, Elixir, ColdFusion, Groovy, Kotlin, Nim, VBA, CoffeeScript e per Node.js e .NET.


1
Potete fornire altre opzioni simili alla vostra proposta? - - È molto interessante. Vorrei sapere se ci sono opzioni predefinite come quella in PostgreSQL.
Léo Léopold Hertz 준영

1
Ecco la versione .NET di esso, ma puoi spiegare come funziona senza bisogno di memorizzarlo nel database? Posso generare solo casuali unici senza dare numeri come input e senza sale?
Shaiju T

@Slawa Ho bisogno di qualcosa come hashid per .NET ma l'hash finale verrà archiviato nel db in una colonna con lunghezza fissa, è possibile dire che genera sempre hash con una lunghezza massima di N?
Anon Dev

6

Avevo requisiti simili a quelli dell'OP. Ho esaminato le librerie disponibili ma la maggior parte di esse si basa sulla casualità e non lo volevo. Non sono riuscito a trovare nulla che non fosse basato sul casuale e comunque molto breve ... Così ho finito per creare il mio in base alla tecnica utilizzata da Flickr , ma modificata per richiedere meno coordinazione e consentire periodi più lunghi offline.

In breve:

  • Un server centrale emette blocchi di ID composti da 32 ID ciascuno
  • Il generatore di ID locale mantiene un pool di blocchi ID per generare un ID ogni volta che ne viene richiesto uno. Quando il pool si esaurisce, recupera più blocchi ID dal server per riempirlo di nuovo.

Svantaggi:

  • Richiede un coordinamento centrale
  • Gli ID sono più o meno prevedibili (meno dei normali ID DB ma non sono casuali)

Vantaggi

  • Rimane entro 53 bit (dimensione massima Javascript / PHP per numeri interi)
  • ID molto brevi
  • Base 36 codificata in modo molto facile da leggere, scrivere e pronunciare per gli esseri umani
  • Gli ID possono essere generati localmente per un tempo molto lungo prima di dover contattare nuovamente il server (a seconda delle impostazioni del pool)
  • Teoricamente nessuna possibilità di collisioni

Ho pubblicato sia una libreria Javascript per il lato client, sia un'implementazione del server Java EE. Anche l'implementazione di server in altre lingue dovrebbe essere facile.

Ecco i progetti:

suid - ID univoci del servizio distribuito che sono brevi e piacevoli

suid-server-java - Implementazione suid-server per lo stack tecnologico Java EE.

Entrambe le librerie sono disponibili con una licenza open source Creative Commons liberale. Sperando che questo possa aiutare qualcun altro a cercare ID univoci brevi.


Puoi confrontare stackoverflow.com/a/29372036/54964 con la tua proposta suid?
Léo Léopold Hertz 준영

1
Si basa su numeri casuali. È davvero fantastico. Ma i tuoi ID non saranno così brevi come possono essere. Ho scritto SUID per iniziare la numerazione da 1, quindi inizierai con ID estremamente brevi . Pensa a 3 o 4 caratteri. Inoltre, ha alcuni altri bei vantaggi avere ID ordinati (approssimativamente) in modo incrementale, oltre a iniziare con quelli veramente brevi.
Stijn de Witt

3

Ho usato la base 36 quando ho risolto questo problema per un'applicazione che stavo sviluppando un paio di anni fa. Avevo bisogno di generare un numero ragionevolmente univoco leggibile dall'uomo (entro l'anno solare in corso comunque). Ho scelto di utilizzare il tempo in millisecondi dalla mezzanotte del 1 ° gennaio dell'anno in corso (quindi ogni anno, i timestamp potrebbero duplicarsi) e convertirlo in un numero base 36. Se il sistema in fase di sviluppo ha riscontrato un problema irreversibile, ha generato il numero di base 36 (7 caratteri) che è stato visualizzato a un utente finale tramite l'interfaccia web che potrebbe quindi inoltrare il problema riscontrato (e il numero) a una persona del supporto tecnico (che potrebbe quindi usarlo per trovare il punto nei log in cui è iniziato lo stacktrace). Un numero come 56af42g7è infinitamente più facile per un utente leggere e trasmettere rispetto a un timestamp come 2016-01-21T15: 34: 29.933-08: 00 o un UUID casuale come 5f0d3e0c-da96-11e5-b5d2-0a1d41d68578 .


4
Potete fornire uno pseudocodice in una forma strutturata sulla vostra proposta? Sembra interessante.
Léo Léopold Hertz 준영

0

Mi piace molto la semplicità di codificare semplicemente un GUID utilizzando il formato Base64 e troncare il finale == per ottenere una stringa di 22 caratteri (ci vuole una riga di codice e puoi sempre riconvertirlo in GUID). Purtroppo, a volte include i caratteri + e /. OK per il database, non eccezionale per gli URL, ma mi ha aiutato ad apprezzare le altre risposte :-)

Da https://www.codeproject.com/Tips/1236704/Reducing-the-string-Length-of-a-Guid di Christiaan van Bergen

Abbiamo scoperto che la conversione del Guid (16 byte) in una rappresentazione ASCII utilizzando Base64 ha prodotto un messageID utilizzabile e ancora univoco di soli 22 caratteri.

var newGuid = Guid.NewGuid();
var messageID = Convert.ToBase64String(newGuid.ToByteArray());

var message22chars = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0,22);

Ad esempio: Il Guid 'e6248889-2a12-405a-b06d-9695b82c0a9c' (lunghezza della stringa: 36) otterrà una rappresentazione Base64: 'iYgk5hIqWkCwbZaVuCwKnA ==' (lunghezza della stringa: 24)

La rappresentazione Base64 termina con i caratteri "==". Potresti semplicemente troncarli, senza alcun impatto sull'unicità. Lasciandoti con un identificatore di soli 22 caratteri di lunghezza.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.