Generieren von lesbaren / verwendbaren, kurzen, aber eindeutigen IDs

85
  • Müssen> 1000 aber <10000 neue Datensätze pro Tag verarbeiten

  • GUID / UUIDs, automatische Inkrementierungsnummern usw. können nicht verwendet werden.

  • Idealerweise sollte es 5 oder 6 Zeichen lang sein, kann natürlich Alpha sein

  • Möchte vorhandene, bekannte Algen wiederverwenden, falls verfügbar

Irgendwas da draußen?

Kumar
quelle
Warum nicht ein INT oder BIGINT verwenden, das automatisch inkrementiert wird? Es ist wahrscheinlich das am besten lesbare und kann die Lautstärke leicht handhaben.
Malk
gemäß dem obigen Q, versuchen, es auf maximal 5/6 Zeichen zu halten und bis zu 9999 neue Rekorde pro Tag zu unterstützen
Kumar
@ Kumar - Was ist, wenn Sie mehr als 9999 Datensätze an einem Tag benötigen? Ihre vorgeschlagene Lösung klingt nicht haltbar.
ChaosPandion
@ChaosPandion: Ich denke, dies sind wahrscheinlich eher grobe Vermutungen von Last / Verkehr als harte Grenzen. Ich bin mir nicht sicher, warum Sie eine beliebige Obergrenze für die Anzahl der täglichen Transaktionen festlegen möchten.
Paul Sasik
Sie könnten es in Basis 64 codieren und verwenden. Ich bin mir nicht sicher, ob Sie es kleiner machen und trotzdem lesbare Zeichen verwenden könnten. Aber ich würde argumentieren, dass Basis 64 weitaus weniger lesbar ist als Basis 32, da für die meisten Zeichen ein zusätzliches Qualifikationsmerkmal erforderlich ist (Großbuchstabe f, niedrigeres o, niedrigeres o gegenüber nur f, oo).
Malk

Antworten:

116

Base 62 wird von tinyurl und bit.ly für die abgekürzten URLs verwendet. Es ist eine gut verstandene Methode zum Erstellen "eindeutiger", für Menschen lesbarer IDs. Natürlich müssen Sie die erstellten IDs speichern und bei der Erstellung nach Duplikaten suchen, um die Eindeutigkeit sicherzustellen. (Siehe Code unten in der Antwort)

Basis 62 Eindeutigkeitsmetriken

5 Zeichen in Basis 62 geben Ihnen 62 ^ 5 eindeutige IDs = 916.132.832 (~ 1 Milliarde) Bei 10.000 IDs pro Tag sind Sie für mehr als 91.000 Tage in Ordnung

6 Zeichen in Basis 62 geben Ihnen 62 ^ 6 eindeutige IDs = 56.800.235.584 (56+ Milliarden) Bei 10.000 IDs pro Tag sind Sie für mehr als 5 Millionen Tage in Ordnung

Basis 36 Eindeutigkeitsmetriken

6 Zeichen geben Ihnen 36 ^ 6 eindeutige IDs = 2.176.782.336 (2+ Milliarden)

7 Zeichen geben Ihnen 36 ^ 7 eindeutige IDs = 78.364.164.096 (78+ Milliarden)

Code:

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

Ausgabe:

z5KyMg
wd4SUp
uSzQtH
UPrGAT
UIf2IS

QCF9GNM5
0UV3TFSS
3MG91VKP
7NTRF10T
AJK3AJU7
Paul Sasik
quelle
3
sieht fantastisch aus, etwas, das nicht zwischen Groß- und Kleinschreibung unterscheidet?
Kumar
2
Wenn Sie vermeiden möchten, dass zwischen Groß- und Kleinschreibung unterschieden wird, können Sie die Basis 36 verwenden: codeproject.com/Articles/10619/Base-36-type-for-NET-C. Um jedoch so viele Permutationen als Basis 62 zu erhalten, müssen Sie mehr Zeichen in Ihrer verwenden ICH WÜRDE. Es ist ein Kompromiss. Oder Sie könnten versuchen, andere Zeichen als Alpha zu verwenden, aber das wird für Benutzer hässlich.
Paul Sasik
2
hier stackoverflow.com/questions/9543892/… & vielen Dank
Kumar
11
Ein Gedanke. Nehmen Sie vielleicht die Vokale heraus, um die versehentliche Erzeugung von Schimpfwörtern zu verhindern. Vor allem, wenn es öffentlich ist.
Damien Sawyer
4
Abhängig davon, wo Sie dies verwenden (insbesondere wenn von Menschen erwartet wird, dass sie die Codes lesen und erneut eingeben), sollten Sie in Betracht ziehen, häufig verwirrte Zeichen aus der Betrachtung zu entfernen: 0 / O und I / l / 1. Dies kann in einigen Fällen durch eine gute Auswahl der Schriftarten gemildert werden, aber ich kann anhand der Frage nicht sagen, ob das OP die Kontrolle darüber haben wird.
GrandOpener
17

Ich empfehle http://hashids.org/ , das eine beliebige Zahl (z. B. DB-ID) in eine Zeichenfolge (mit Salz) konvertiert.

Es ermöglicht das Dekodieren dieser Zeichenfolge zurück in die Nummer. Sie müssen es also nicht in der Datenbank speichern.

Hat Bibliotheken für JavaScript, Ruby, Python, Java, Scala, PHP, Perl, Swift, Clojure, Ziel-C, C, C ++ 11, Go, Erlang, Lua, Elixier, ColdFusion, Groovy, Kotlin, Nim, VBA, CoffeeScript und für Node.js & .NET.

Slawa
quelle
1
Können Sie andere Optionen angeben, die Ihrem Vorschlag ähneln? - - Es ist sehr interessant. Ich würde gerne wissen, ob es in PostgreSQL solche Standardoptionen gibt.
Léo Léopold Hertz 28
1
Hier ist die .NET- Version davon, aber können Sie erklären, wie es funktioniert, ohne es in der Datenbank speichern zu müssen? Kann ich nur eindeutige Zufälle generieren, ohne Zahlen als Eingabe und ohne Salz anzugeben?
Shaijut
@Slawa Ich brauche so etwas wie Hashids für .NET, aber der endgültige Hash wird in der Datenbank in einer Spalte mit fester Länge gespeichert. Kann man sagen, dass immer Hash mit einer maximalen Länge von N generiert wird?
Anon Dev
6

Ich hatte ähnliche Anforderungen wie das OP. Ich habe nach verfügbaren Bibliotheken gesucht, aber die meisten basieren auf Zufälligkeit, und das wollte ich nicht. Ich konnte nicht wirklich etwas finden, das nicht zufällig und dennoch sehr kurz war ... Also rollte ich mein eigenes basierend auf der von Flickr verwendeten Technik , modifizierte es jedoch, um weniger Koordination zu erfordern und längere Zeiträume offline zu ermöglichen.

Zusamenfassend:

  • Ein zentraler Server gibt ID-Blöcke aus, die jeweils aus 32 IDs bestehen
  • Der lokale ID-Generator verwaltet einen Pool von ID-Blöcken, um bei jeder Anforderung eine ID zu generieren. Wenn der Pool zur Neige geht, werden mehr ID-Blöcke vom Server abgerufen, um ihn wieder aufzufüllen.

Nachteile:

  • Erfordert eine zentrale Koordination
  • IDs sind mehr oder weniger vorhersehbar (weniger als normale DB-IDs, aber nicht zufällig)

Vorteile

  • Bleibt innerhalb von 53 Bit (maximale Javascript / PHP-Größe für Ganzzahlen)
  • sehr kurze IDs
  • Die Basis 36 ist so einfach zu lesen, zu schreiben und auszusprechen
  • IDs können sehr lange lokal generiert werden, bevor erneut Kontakt mit dem Server benötigt wird (abhängig von den Pooleinstellungen).
  • Theoretisch keine Chance auf Kollisionen

Ich habe sowohl eine Javascript-Bibliothek für die Client-Seite als auch eine Java EE-Server-Implementierung veröffentlicht. Die Implementierung von Servern in anderen Sprachen sollte ebenfalls einfach sein.

Hier sind die Projekte:

suid - Distributed Service - Eindeutige IDs, die kurz und bündig sind

suid-server-java - Suid-Server-Implementierung für den Java EE-Technologie-Stack.

Beide Bibliotheken stehen unter einer liberalen Open-Source-Lizenz von Creative Commons zur Verfügung. In der Hoffnung, dass dies jemand anderem hilft, nach kurzen eindeutigen IDs zu suchen.

Stijn de Witt
quelle
Können Sie bitte den stackoverflow.com/a/29372036/54964 mit Ihrem Vorschlag vergleichen suid?
Léo Léopold Hertz 준영
1
Es basiert auf Zufallszahlen. Eigentlich ist es ziemlich gut. Aber Ihre IDs werden nicht so kurz wie möglich sein. Ich habe SUID geschrieben, um mit der Nummerierung bei 1 zu beginnen, damit Sie mit extrem kurzen IDs beginnen können. Denken Sie an 3 oder 4 Zeichen. Außerdem hat es einige andere nette Vorteile, (grob) inkrementell geordnete IDs zu haben, abgesehen davon, dass Sie mit den wirklich kurzen beginnen.
Stijn de Witt
3

Ich habe Base 36 verwendet, als ich dieses Problem für eine Anwendung gelöst habe, die ich vor ein paar Jahren entwickelt habe. Ich musste eine von Menschen lesbare, einigermaßen eindeutige Nummer generieren (jedenfalls innerhalb des aktuellen Kalenderjahres). Ich habe mich dafür entschieden, die Zeit in Millisekunden ab Mitternacht am 1. Januar des laufenden Jahres zu verwenden (damit die Zeitstempel jedes Jahr dupliziert werden können) und sie in eine Basiszahl 36 umzuwandeln. Wenn das zu entwickelnde System auf ein schwerwiegendes Problem stieß, wurde die Basis-36-Nummer (7 Zeichen) generiert, die einem Endbenutzer über die Weboberfläche angezeigt wurde. Dieser konnte das aufgetretene Problem (und die Nummer) an eine Person des technischen Supports weiterleiten könnte es dann verwenden, um den Punkt in den Protokollen zu finden, an dem der Stacktrace gestartet wurde). Eine Zahl wie 56af42g7ist für einen Benutzer unendlich einfacher zu lesen und weiterzuleiten als ein Zeitstempel wie 2016-01-21T15: 34: 29.933-08: 00 oder eine zufällige UUID wie 5f0d3e0c-da96-11e5-b5d2-0a1d41d68578 .

Warren Smith
quelle
4
Können Sie bitte einen strukturierten Pseudocode zu Ihrem Vorschlag bereitstellen? Das klingt interessant.
Léo Léopold Hertz 28
0

Ich mag die Einfachheit, eine GUID einfach im Base64-Format zu codieren und die nachfolgende == abzuschneiden, um eine Zeichenfolge mit 22 Zeichen zu erhalten (es wird eine Codezeile benötigt, und Sie können sie jederzeit wieder in eine GUID konvertieren). Leider enthält es manchmal + und / Zeichen. OK für die Datenbank, nicht gut für URLs, aber es hat mir geholfen, die anderen Antworten zu schätzen :-)

Von https://www.codeproject.com/Tips/1236704/Reduzieren-der-String-Länge-von-a-Guid von Christiaan van Bergen

Wir haben festgestellt, dass die Konvertierung der Guid (16 Byte) in eine ASCII-Darstellung mit Base64 zu einer verwendbaren und immer noch eindeutigen Nachrichten-ID mit nur 22 Zeichen führte.

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

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

Beispiel: Die Guid 'e6248889-2a12-405a-b06d-9695b82c0a9c' (Zeichenfolgenlänge: 36) erhält eine Base64-Darstellung: 'iYgk5hIqWkCwbZaVuCwKnA ==' (Zeichenfolgenlänge: 24)

Die Base64-Darstellung endet mit den Zeichen '=='. Sie können diese einfach abschneiden, ohne die Einzigartigkeit zu beeinträchtigen. Sie haben nur eine Kennung mit einer Länge von 22 Zeichen.

Ekus
quelle