人間が読める/使用できる、短いが一意のIDを生成する


89
  • 1日あたり1000を超えるが10000未満の新しいレコードを処理する必要がある

  • GUID / UUID、自動インクリメント番号などは使用できません。

  • 理想的には5または6文字の長さである必要があり、もちろんアルファにすることもできます

  • 可能であれば、既存のよく知られたアルゴを再利用したい

何かありますか?


自動インクリメントされるINTまたはBIGINTを使用してみませんか?おそらく最も読みやすく、ボリュームを簡単に処理できます。
2012

上記のQによると、最大5/6文字に維持し、1日あたり最大9999の新しいレコードをサポートしようとしています
Kumar

@Kumar-1日に9999を超えるレコードが必要な場合はどうなりますか?あなたの提案した解決策は持続可能に聞こえません。
ChaosPandion 2012

@ChaosPandion:これらはおそらくハードバウンドではなく、負荷/トラフィックの大まかな推測だと思います。1日のトランザクション数に任意の上限を設定する理由がわかりません。
Paul Sasik 2012

それをbase64にエンコードして使用することができます。それより小さくして、読みやすい文字を使用できるかどうかはわかりません。ただし、base 64はbase 32よりもはるかに読みにくいと思います。これは、ほとんどの文字に追加の修飾子を追加する必要があるためです(大文字のf、低いo、低いoとf、ooだけ)。
2012

回答:


122

ベース62は、省略されたURLのtinyurlおよびbit.lyによって使用されます。これは、「一意の」人間が読めるIDを作成するためのよく理解されている方法です。もちろん、作成されたIDを保存し、作成時に重複をチェックして一意性を確保する必要があります。(回答の下部にあるコードを参照してください)

ベース62の一意性メトリック

六十二進法の5文字は62 ^ 5の一意のIDを提供します= 916,132,832(〜10億)1日あたり10,000 IDで、91k +日は問題ありません

六十二進法の6文字は62 ^ 6の一意のIDを提供します= 56,800,235,584(560億以上)1日あたり10,000 IDで、500万日以上問題ありません

ベース36の一意性メトリック

6文字で36 ^ 6の一意のIDが得られます= 2,176,782,336(2+億)

7文字で36 ^ 7の一意のID = 78,364,164,096(780億以上)

コード:

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

出力:

z5KyMg
wd4SUp
uSzQtH
UPrGAT
UIf2IS

QCF9GNM5
0UV3TFSS
3MG91VKP
7NTRF10T
AJK3AJU7

3
見た目は素晴らしく、大文字と小文字を区別しないものはありますか?
クマール

2
大文字と小文字を区別しないようにする場合は、base 36を使用できます:codeproject.com/Articles/10619/Base-36-type-for-NET-Cが、base 62と同じ数の順列を取得するには、より多くの文字を使用する必要があります。 ID。これはトレードオフです。または、アルファ以外の文字を使用することもできますが、それはユーザーにとって醜いものになります。
Paul Sasik 2012


12
一つの考え。おそらく、誤って冒とく的な言葉が生成されるのを防ぐために、母音を取り出してください。特にそれが公に直面している場合。
ダミアンソーヤー

4
これを使用している場所によっては(特に、人間がコードを読み取って再入力することが予想される場合)、よく混乱する文字を考慮から除外することを検討してください:0 / OおよびI / l / 1。これは、適切なフォントを選択することで軽減できる場合もありますが、OPがそれを制御できるかどうかという質問からはわかりません。
GrandOpener 2016

18

任意の数値(DB IDなど)を文字列(saltを使用)に変換するhttp://hashids.org/をお勧めします。

これにより、この文字列をデコードして数値に戻すことができます。したがって、データベースに保存する必要はありません。

JavaScript、Ruby、Python、Java、Scala、PHP、Perl、Swift、Clojure、Objective-C、C、C ++ 11、Go、Erlang、Lua、Elixir、ColdFusion、Groovy、Kotlin、Nim、VBA、 CoffeeScriptおよびNode.jsおよび.NET用。


1
あなたの提案と同様に他のオプションを提供できますか?- - それは非常に興味深いです。PostgreSQLにそのようなデフォルトのオプションがあるかどうか知りたいのですが。
レオ・レオポルド・ヘルツ준 영

1
これは.NETバージョンですが、データベースに保存せずにどのように機能するかを説明できますか?入力として数値を指定せず、ソルトなしで、一意のランダムだけを生成できますか?
Shaiju T 2017

@Slawa .NETのハッシュIDのようなものが必要ですが、最終的なハッシュはデータベースの固定長の列に格納されます。常に最大長Nのハッシュを生成すると言うことは可能ですか?
Anon Dev

6

OPと同様の要件がありました。私は利用可能なライブラリを調べましたが、それらのほとんどはランダム性に基づいており、私はそれを望んでいませんでした。ランダムに基づいておらず、まだ非常に短いものは実際には見つかりませんでした...そこで、Flickrが使用する手法に基づいて自分でローリングすることになりましたが、調整が少なくて済み、オフラインでの期間を長くできるように変更されました。

要するに:

  • 中央サーバーは、それぞれ32個のIDで構成されるIDブロックを発行します
  • ローカルIDジェネレーターは、IDブロックのプールを維持して、要求されるたびにIDを生成します。プールが少なくなると、サーバーからさらにIDブロックをフェッチして、プールを再び埋めます。

短所:

  • 中央調整が必要
  • IDは多かれ少なかれ予測可能です(通常のDB IDほどではありませんが、ランダムではありません)

利点

  • 53ビット以内に留まる(整数のJavascript / PHP最大サイズ)
  • 非常に短いID
  • ベース36は、人間が読み、書き、発音するのが非常に簡単にエンコードされています
  • IDは、サーバーとの接続を再度必要とする前に、非常に長い間ローカルで生成できます(プール設定によって異なります)
  • 理論的には衝突の可能性はありません

クライアント側のJavascriptライブラリとJavaEEサーバーの実装の両方を公開しました。他の言語でのサーバーの実装も簡単なはずです。

プロジェクトは次のとおりです。

suid-分散サービス-短くて甘いユニークなID

suid-server-java -JavaEEテクノロジースタックのSuidサーバー実装。

どちらのライブラリも、リベラルなクリエイティブコモンズオープンソースライセンスの下で利用できます。これが、他の誰かが短い一意のIDを探すのに役立つことを願っています。


stackoverflow.com/a/29372036/54964をあなたの提案と比較していただけますsuidか?
レオ・レオポルド・ヘルツ준 영

1
乱数に基づいています。実際、それはかなり素晴らしいです。ただし、IDは可能な限り短くなることはありません。非常に短いIDから始めるように、1から番号付けを開始するようにSUIDを作成しました。3文字か4文字だと思います。さらに、本当に短いIDから始める以外に、(大まかに)段階的に順序付けられたIDを持つことには他にもいくつかの優れた利点があります。
Stijn de Witt 2017

3

数年前に開発していたアプリケーションでこの問題を解決したとき、ベース36を使用しました。人間が読める形式の適度に一意の番号を生成する必要がありました(とにかく現在の暦年内)。今年の1月1日の深夜からのミリ秒単位の時間を使用して(毎年、タイムスタンプが重複する可能性があるため)、それをベース36の数値に変換することを選択しました。開発中のシステムで致命的な問題が発生した場合、ベース36の番号(7文字)が生成され、Webインターフェイスを介してエンドユーザーに表示され、発生した問題(および番号)をテクニカルサポート担当者(担当者)に中継できます。次に、それを使用して、スタックトレースが開始されたログ内のポイントを見つけることができます)。のような数56af42g7の2016-01-21T15:34:29.933-08:00のようなタイムスタンプや5f0d3e0c-da96-11e5-b5d2-0a1d41d68578のようなランダムなUUIDよりも、ユーザーが読み取りと中継を行うのは非常に簡単です。


4
提案について構造化された形式で擬似コードを提供していただけますか?それは面白そう。
レオ・レオポルド・ヘルツ준 영

0

Base64形式を使用してGUIDをエンコードし、末尾の==を切り捨てて22文字の文字列を取得するという単純さが本当に気に入っています(1行のコードが必要で、いつでもGUIDに戻すことができます)。残念ながら、+文字と/文字が含まれることがあります。データベースには問題ありませんが、URLには適していませんが、他の回答を評価するのに役立ちました:-)

Christiaan vanBergenによるhttps://www.codeproject.com/Tips/1236704/Reducing-the-string-Length-of-a-Guidから

Base64を使用してGuid(16バイト)をASCII表現に変換すると、22文字の使用可能で一意のmessageIDが生成されることがわかりました

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

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

例:Guid'e6248889-2a12-405a-b06d-9695b82c0a9c '(文字列の長さ:36)はBase64表現を取得します:' iYgk5hIqWkCwbZaVuCwKnA == '(文字列の長さ:24)

Base64表現は「==」文字で終わります。一意性に影響を与えることなく、これらを切り捨てることができます。長さがわずか22文字の識別子を残します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.