102 votes

Générer des identifiants courts mais uniques, lisibles et utilisables par des humains.

  • Doit gérer > 1000 mais < 10000 nouveaux enregistrements par jour

  • Ne peut pas utiliser GUID / UUID, nombres d'incrémentation automatique, etc.

  • Idéalement devrait être de 5 ou 6 caractères de long, peut être alpha bien sûr

  • Je voudrais réutiliser des algorithmes existants bien connus, si disponibles

Y a-t-il quelque chose là-bas?

0 votes

Pourquoi ne pas utiliser un INT ou BIGINT qui est auto-incrémenté ? C'est probablement le plus lisible et peut facilement gérer le volume.

0 votes

Selon la question ci-dessus, essayez de limiter à 5/6 caractères maximum et prenez en charge jusqu'à 9999 nouveaux enregistrements par jour.

0 votes

@Kumar - Et si vous avez besoin de plus de 9999 enregistrements en un jour ? Votre solution proposée ne semble pas réalisable.

175voto

Paul Sasik Points 37766

Base 62 est utilisé par tinyurl et bit.ly pour les URL abrégées. C'est une méthode bien comprise pour créer des identifiants "uniques", lisibles par l'homme. Bien sûr, vous devrez stocker les identifiants créés et vérifier les doublons lors de la création pour garantir l'unicité. (Voir le code en bas de la réponse)

Métriques d'unicité en base 62

5 caractères en base 62 vous donneront 62^5 identifiants uniques = 916,132,832 (~1 milliard) En générant 10 000 identifiants par jour, vous serez bon pour 91k+ jours

6 caractères en base 62 vous donneront 62^6 identifiants uniques = 56,800,235,584 (56+ milliards) En générant 10 000 identifiants par jour, vous serez bon pour 5+ millions de jours

Métriques d'unicité en base 36

6 caractères vous donneront 36^6 identifiants uniques = 2,176,782,336 (2+ milliards)

7 caractères vous donneront 36^7 identifiants uniques = 78,364,164,096 (78+ milliards)

Code:

public void TestRandomIdGenerator()
{
    // créer cinq identifiants de six caractères en base 62
    for (int i=0; i<5; i++) Console.WriteLine(RandomIdGenerator.GetBase62(6));

    // créer cinq identifiants de huit caractères en base 36
    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

`Sortie:

z5KyMg
wd4SUp
uSzQtH
UPrGAT
UIf2IS

QCF9GNM5
0UV3TFSS
3MG91VKP
7NTRF10T
AJK3AJU7`

22voto

Slawa Points 137

Je recommande http://hashids.org/ qui convertit n'importe quel nombre (par exemple, un ID de base de données) en une chaîne (en utilisant un sel).

Cela permet de décoder cette chaîne en de retourner au nombre. Vous n'avez donc pas besoin de le stocker dans la base de données.

Dispose de librairies pour JavaScript, Ruby, Python, Java, Scala, PHP, Perl, Swift, Clojure, Objective-C, C, C++11, Go, Erlang, Lua, Elixir, ColdFusion, Groovy, Kotlin, Nim, VBA, CoffeeScript et pour Node.js et .NET.

1 votes

Pouvez-vous fournir d'autres options similaires à votre proposition ? - - C'est très intéressant. J'aimerais savoir s'il y a des options par défaut comme ça dans PostgreSQL.

1 votes

Voici la version .NET de cela, mais pouvez-vous expliquer comment cela fonctionne sans avoir besoin de le stocker dans la base de données ? Puis-je générer simplement des aléatoires uniques sans fournir de nombres en entrée et sans sel ?

0 votes

@Slawa J'ai besoin de quelque chose comme hashids pour .NET mais le hash final sera stocké dans la base de données dans une colonne de longueur fixe, est-il possible de dire toujours générer un hash avec une longueur maximale de N?

8voto

Stijn de Witt Points 3515

J'avais des exigences similaires à celles de l'OP. J'ai examiné les bibliothèques disponibles, mais la plupart d'entre elles sont basées sur le hasard et je ne voulais pas cela. Je n'ai pas vraiment trouvé quelque chose qui n'était pas basé sur le hasard et toujours très court... Alors j'ai fini par développer le mien basé sur la technique utilisée par Flickr, mais modifiée pour nécessiter moins de coordination et permettre des périodes hors ligne plus longues.

En bref:

  • Un serveur central émet des blocs d'identifiants composés de 32 identifiants chacun
  • Le générateur d'identifiants local maintient un pool de blocs d'identifiants pour générer un identifiant à chaque fois qu'il est demandé. Lorsque le pool est faible, il récupère d'autres blocs d'identifiants auprès du serveur pour le remplir à nouveau.

Inconvénients:

  • Requiert une coordination centrale
  • Les identifiants sont plus ou moins prévisibles (moins que les identifiants de base de données réguliers mais ils ne sont pas aléatoires)

Avantages:

  • Reste dans les 53 bits (taille maximale pour les nombres entiers en Javascript / PHP)
  • très courts identifiants
  • Encodé en base 36 donc très facile à lire, écrire et prononcer pour les humains
  • Les identifiants peuvent être générés localement pendant très longtemps avant d'avoir besoin de contacter à nouveau le serveur (selon les paramètres du pool)
  • Théoriquement aucun risque de collisions

J'ai publié à la fois une bibliothèque Javascript pour le côté client, ainsi qu'une implémentation de serveur Java EE. Implémenter des serveurs dans d'autres langues devrait également être facile.

Voici les projets:

suid - Identifiants uniques de service distribué qui sont courts et simples

suid-server-java - Implémentation de Suid-server pour la pile technologique Java EE.

Les deux bibliothèques sont disponibles sous une licence open source Creative Commons libérale. J'espère que cela pourra aider quelqu'un d'autre à la recherche d'identifiants uniques et courts.

4voto

Warren Smith Points 31

J'ai utilisé base 36 lorsque j'ai résolu ce problème pour une application que je développais il y a quelques années. J'avais besoin de générer un numéro raisonnablement unique lisible par un humain (dans l'année civile en cours de toute façon). J'ai choisi d'utiliser le temps en millisecondes depuis minuit le 1er janvier de l'année en cours (donc chaque année, les horodatages pourraient se reproduire) et de le convertir en un nombre en base 36. Si le système en cours de développement rencontrait un problème fatal, il générait le nombre en base 36 (7 caractères) qui était affiché à un utilisateur final via l'interface web, qui pouvait ensuite transmettre le problème rencontré (et le nombre) à une personne du support technique (qui pouvait alors l'utiliser pour trouver le point dans les journaux où la trace de la pile a commencé). Un nombre comme 56af42g7 est infiniment plus facile à lire et à relayer pour un utilisateur qu'un horodatage comme 2016-01-21T15:34:29.933-08:00 ou un UUID aléatoire comme 5f0d3e0c-da96-11e5-b5d2-0a1d41d68578.

1voto

Ekus Points 101

J'aime vraiment la simplicité d'encoder un GUID en utilisant le format Base64 et de tronquer les == finaux pour obtenir une chaîne de 22 caractères (cela prend une seule ligne de code, et vous pouvez toujours le convertir en GUID).

Malheureusement, cela inclut parfois des caractères + et /. OK pour la base de données, moins bon pour les URLs, mais cela m'a aidé à apprécier les autres réponses :-)

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

Nous avons constaté qu'en convertissant le Guid (16 octets) en une représentation ASCII en utilisant Base64, nous obtenions un messageID utilisable et toujours unique de seulement 22 caractères.

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

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

Par exemple: Le Guid 'e6248889-2a12-405a-b06d-9695b82c0a9c' (longueur de la chaîne: 36) aura une représentation Base64: 'iYgk5hIqWkCwbZaVuCwKnA==' (longueur de la chaîne: 24)

La représentation Base64 se termine par les caractères '=='. Vous pourriez simplement les tronquer, sans aucun impact sur l'unicité. Vous laissant ainsi avec un identifiant de seulement 22 caractères de longueur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X