17

私は、Guid/UID に代わる人間が読める形式についての小さな記事を書いています。たとえば、TinyURL で URL ハッシュに使用されるものです (雑誌に掲載されることが多いため、短くする必要があります)。

私が生成している単純な uid は、小文字 (az) または 0-9 の 6 文字です。

「私の計算によるとキャプテン」、これは相互に排他的な 6 つのイベントですが、衝突の確率の計算は P(A または B) = P(A) + P(B) よりも少し難しくなります。以下のコードでは、50/50 を使用して数字または文字を使用するかどうかがうまくいくことがわかります。

私は衝突率に興味があります。以下のコードが予想される衝突率の現実的なシミュレーションである場合、ハッシュの生成から得られるでしょう。平均して、100 万回あたり 40 ~ 50 回のクラッシュが発生しますが、uid が一度に 100 万回生成されることはなく、おそらく 1 分間に 10 ~ 1000 回程度しか生成されないことを念頭に置いてください。

毎回のクラッシュの確率はどのくらいですか? また、より良い方法を提案できる人はいますか?

static Random _random = new Random();

public static void main()
{
    // Size of the key, 6
    HashSet<string> set = new HashSet<string>();
    int clashes = 0;
    for (int n=0;n < 1000000;n++)
    {
        StringBuilder builder = new StringBuilder();

        for (int i =0;i < 7;i++)
        {
            if (_random.NextDouble() > 0.5)
            {
                builder.Append((char)_random.Next(97,123));
            }
            else
            {
                builder.Append(_random.Next(0,9).ToString());
            }
        }

        if (set.Contains(builder.ToString()))
        {
            clashes++;
            Console.WriteLine("clash: (" +n+ ")" +builder.ToString());
        }

        set.Add(builder.ToString());
        _random.Next();
        //Console.Write(builder.ToString());
    }

    Console.WriteLine("Clashes: " +clashes);
    Console.ReadLine();
}

更新: この質問から得られた記事は次のとおりです

ここで本当に 2 つの質問をしたので、ごまかしていました。私が求めていた答えはrcarのものでしたが、Sklivvzのものも2番目の部分に対する答えです(代替)。データベースでカスタムの一意の ID ジェネレーターを作成することは可能ですか、それともクライアント側でしょうか (最初に 2 回の読み取りが可能です)。

私が求めていた一般的なアイデアは、巨大な 16 バイトの GUID ではなく、電話や印刷物で使用できるデータベースやその他のストアで ID を使用することでした。

更新 2: 2 つの独立したイベントの代わりに、相互に排他的な 2 つのイベントの式を上に置きました (最初に「a」を取得しても、2 回目に「a」を取得できないという意味ではないため)。P(A and B) = P(A) x P(B) であるべきだった

4

8 に答える 8

31

なぜ乱数関数を使用したいのですか? tinyurl は、シーケンシャル ID のベース 62 (0-9A-Za-z) 表現を使用すると常に想定していました。衝突はなく、URL は常にできるだけ短くします。

次のようなDBテーブルがあります

Id  URL
 1  http://google.com
 2  ...
... ...
156 ...
... ...

対応する URL は次のようになります。

http://example.com/1
http://example.com/2
...
http://example.com/2W
...
于 2008-10-10T10:20:18.773 に答える
6

誕生日のパラドックスを調べてください。まさにあなたが直面している問題です。

問題は、1 つの部屋に何人の人が集まる必要があるかということです。その結果、2 人が同じ生年月日を持つ確率は 50% になります。答えはあなたを驚かせるかもしれません。

于 2008-10-10T10:18:41.960 に答える
5

少し前に私はまさにこれを行い、Sklivvz が言及した方法に従いました。ロジック全体は、SQL サーバーのストアド プロシージャといくつかの UDF (ユーザー定義関数) を使用して開発されました。手順は次のとおりです。

  • この URL を短縮したいとします:独自の Tinyurl スタイルの uid を作成する
  • 表に URL を挿入する
  • 最後の挿入の @@identity 値を取得します (数値 ID)
  • 文字と数字の「ドメイン」に基づいて、対応する英数字の値にIDを変換します(実際にこのセットを使用しました:「0123456789abcdefghijklmnopqrstuvwxyz」)
  • 「cc0」のような値を返します

変換は、いくつかの非常に短い UDF によって実現されました。

2 つの変換を次々に呼び出すと、次のような「連続した」値が返されます。

select dbo.FX_CONV (123456) -- returns "1f5n"

select dbo.FX_CONV (123457) -- returns "1f5o"

興味があれば、UDF のコードを共有できます。

于 2008-10-10T13:01:40.933 に答える
4

1つの特定のIDに対する衝突の確率は次のとおりです。

p = ( 0.5 * ( (0.5*1/10) + (0.5*1/26) ) )^6

これは約1.7×10^-9です。

n個のIDを生成した後の衝突の確率は1-p^nであるため、100万個のIDが挿入された後、新しい挿入ごとに約0.17%の衝突の可能性があり、1,000万個のIDが挿入された後は約1.7%、 1億回後に約16%。

1000 ID /分は約4,300万/月になります。したがって、Sklivvzが指摘したように、この場合は、増分IDを使用する方がおそらく良い方法です。

編集:

数学を説明するために、彼は基本的にコインを投げてから、数字または文字を6回選びます。コイントスが一致する確率は0.5で、50%の確率で1/10の確率で一致し、50%の確率で1/26の確率で一致します。これは独立して6回発生するため、これらの確率を掛け合わせます。

于 2008-10-10T10:37:55.463 に答える
0

azと0-9の6文字を使用している場合、合計36文字になります。したがって、順列の数は36 ^ 6であり、2176782336 ..であるため、衝突するのは1/2176782336回だけです。

于 2008-10-10T10:32:59.653 に答える
0

ウィキペディアから:

より少ない文字を印刷する必要がある場合、GUIDはbase64またはAscii85文字列にエンコードされることがあります。Base64でエンコードされたGUIDは、22〜24文字(パディングによって異なります)で構成されます。例:

7QDBkvCA1+B9K/U0vrQx1A
7QDBkvCA1+B9K/U0vrQx1A==

Ascii85エンコーディングでは、20文字しか使用できません。例:

5:$Hj:Pf\4RLB9%kU\Lj 

したがって、一意性に関心がある場合は、base64でエンコードされたGUIDを使用すると、6文字ではありませんが、必要なものにいくらか近づけることができます。

文字を直接操作するのではなく、最初にバイト単位で作業してから、それらのバイトを16進数に変換して表示するのが最善です。

于 2008-10-10T10:34:56.140 に答える
0

手動で作成したランダムなハッシュでシミュレートするのではなく、ハッシュするデータを表すランダムな値を生成し、それをハッシュしてクラスをチェックします。これにより、より良い指標が得られます。また、ランダム化する必要があるため、ランダム性が高くなります(ハッシュされるデータの方が大きいと仮定します:))。

于 2008-10-10T10:27:54.483 に答える
0

ハッシュアルゴリズムを使用しないのはなぜですか? URLのハッシュを使用しますか?

乱数を使用している場合、不確定であるため衝突が発生する可能性があります。

ハッシュは証明できるほど一意ではありませんが、文字列のハッシュが一意になる可能性はかなりあります。

修正

実際には、それらを人間が読めるようにするのを待ってください...それらを16進数にすると、技術的に人間が読めるようになります。

または、ハッシュを人間が読める文字列に変換するアルゴリズムを使用できます。人間が読める文字列がハッシュの異なる表現である場合、それはハッシュと同じくらい「一意」である必要があります。つまり、元のハッシュの base 36 です。

于 2008-10-10T10:18:52.427 に答える