16

要件は次のとおりです。

ユーザーフレンドリーにするために、英数字、8〜10文字である必要があります。これらは、データベースに一意のキーとして保存されます。私は主キーとしてGuidを使用しているので、これらの一意のIDを生成するためにGUidを使用するオプションが望ましいでしょう。

Guidを受け取り、8文字の一意の文字列に変換するbase-nコンバーターの行について考えています。

非常に頻繁に呼び出されるため、短くて軽量のアルゴリズムが推奨されます。

4

5 に答える 5

10
8 characters - perfectly random - 36^8 = 2,821,109,907,456 combinations
10 characters - perfectly random - 36^10 = 3,656,158,440,062,976 combinations
GUID's - statistically unique* - 2^128 = 340,000,000,000,000,000,000,000,000,000,000,000,000 combinations

* GUID は常に 100% 一意ですか? [スタックオーバーフロー]

GUID の問題 -> 文字変換; GUID は統計的に一意ですが、任意のサブセットを取得すると、ランダム性が低下し、衝突の可能性が高くなります。一意でない SKU を作成したくないことは確かです。


解決策 1:

オブジェクトとビジネス ルールに関連するデータを使用して SKU を作成します。

つまり、オブジェクトを一意にする属性の小さな組み合わせ(自然キー)が存在する可能性があります。自然キーの要素を組み合わせ、エンコードおよび圧縮して SKU を作成します。多くの場合、必要なのは日時フィールド (つまり、CreationDate) と、これを実現するための他のいくつかのプロパティだけです。Sku の作成には多くの穴がある可能性がありますが、Sku はユーザーにとってより関連性があります。

仮説的に:

Wholesaler, product name, product version, sku
Amazon,     IPod Nano,    2.2,             AMIPDNN22
BestBuy,    Vaio,         3.2,             BEVAIO32

解決策 2:

数値の範囲を予約してから順次解放し、同じ数値を 2 回返さないメソッド。それでも、範囲内に穴が開く可能性があります。おそらく十分な数の SKU を生成する必要はありませんが、要件でこれが可能であることを確認してください。

実装はkey、カウンターを持つデータベースにテーブルを持つことです。カウンタはトランザクションで増加します。重要な点は、1 ずつインクリメントするのではなく、ソフトウェアのメソッドがブロックを取得することです。疑似 c# コードは次のとおりです。

-- what the key table may look like
CREATE TABLE Keys(Name VARCHAR(10) primary key, NextID INT)
INSERT INTO Keys Values('sku',1)

// some elements of the class
public static SkuKeyGenerator 
{
    private static syncObject = new object();
    private static int nextID = 0;
    private static int maxID = 0;
    private const int amountToReserve = 100;

    public static int NextKey()
    {
        lock( syncObject )
        {
            if( nextID == maxID )
            {
                ReserveIds();
            }
            return nextID++;
        }
    }
    private static void ReserveIds()
    {
        // pseudocode - in reality I'd do this with a stored procedure inside a transaction,
        // We reserve some predefined number of keys from Keys where Name = 'sku'
        // need to run the select and update in the same transaction because this isn't the only
        // method that can use this table.
        using( Transaction trans = new Transaction() ) // pseudocode.
        {
             int currentTableValue = db.Execute(trans, "SELECT NextID FROM Keys WHERE Name = 'sku'");
             int newMaxID = currentTableValue + amountToReserve;
             db.Execute(trans, "UPDATE Keys SET NextID = @1 WHERE Name = 'sku'", newMaxID);

             trans.Commit();

             nextID = currentTableValue;
             maxID = newMaxID;
        }
    } 

ここでの考え方は、キー範囲の取得はコストのかかる操作であるため、コードがデータベースに頻繁にアクセスしないように十分なキーを予約することです。キーの損失 (アプリケーションの再起動) とキーの消耗が早すぎてデータベースに戻ることとのバランスを取るために、予約する必要があるキーの数をよく把握する必要があります。この単純な実装では、失われたキーを再利用する方法がありません。

この実装はデータベースとトランザクションに依存しているため、アプリケーションを同時に実行し、データベースに頻繁にアクセスする必要なく、すべてのアプリケーションで一意のキーを生成できます。

上記は、 Patterns of Enterprise Application Architecture (Fowler) のkey table222 ページに大まかに基づいていることに注意してください。この方法は通常、データベース ID 列を必要とせずに主キーを生成するために使用されますが、目的に合わせてどのように適応できるかを確認できます。

于 2008-10-20T21:26:27.803 に答える
8

文字と数字を処理できるという点で、基数 36と考えることができます。I (目) と O (オー) をセットから削除して、1 (1) と 0 (ゼロ) と混同しないようにすることを検討してください。2 と Z についても不満を言う人がいるかもしれません。

于 2008-10-20T01:10:30.707 に答える
4

「ユーザーフレンドリー」を探している場合は、単に短い/英数字にするのではなく、単語全体を使用してみることをお勧めします。したがって、次のようになります。

words = [s.strip().lower() for s in open('/usr/share/dict/canadian-english') if "'" not in s]
mod = len(words)

def main(script, guid):
    guid = hash(guid)

    print "+".join(words[(guid ** e) % mod] for e in (53, 61, 71))

if __name__ == "__main__":
    import sys
    main(*sys.argv)

次のような出力が生成されます。

oranjestad+compressing+wellspring
padlock+discommoded+blazons
pt+olenek+renews

これは面白いです。それ以外の場合は、GUID の最初の 8 ~ 10 文字を取得するか、GUID の sha1/md5 ハッシュを取得するのがおそらく最善の方法です。

于 2008-10-20T01:12:20.393 に答える
3

おそらく機能する可能性のある最も単純なことは、値が必要になるたびにインクリメントされるカウンターです。8桁(左ゼロが埋め込まれた)の数字は、1億の可能な値00000000から99999999を示します(ただし、000-000-00のように、人間が読みやすいようにスペースまたはハイフンを挿入することもできます)。

1億を超える値が必要な場合は、長さを長くするか、別の位置に文字を使用することができます。A0A0A0A0からZ9Z9Z9Z9を使用すると、45億を超える可能な値(4,569,760,000)が利用可能になります。長整数を取り、そのようなエンコーディングを生成するのは簡単なコードです(右端の桁の場合はmod 10、右端の文字の場合はdiv by 10、次にmod 26など)。書き込みメモリがある場合は、最速の方法です。カウンタをmod260配列に変換し、各mod 260値を2文字の文字列( "A0"、 "A1"、 "A2"などから"A9"、 " B0 "、" B1"などから"Z9")。

ベース36(別の返信で言及)の問題は、類似した文字(1対I、0対O、2対Z、5対S)の読者の混乱だけでなく、組み合わせについても心配する必要があることです。不快またはわいせつな単語や略語のスペルとして読者に認識される可能性のある隣接する文字の数。

于 2008-10-20T01:33:32.393 に答える
2

CRC32 ハッシュ アルゴリズムを試してみることをお勧めします。CRC32 は 8 文字の文字列を生成します。

http://en.wikipedia.org/wiki/Cyclic_redundancy_check

http://textop.us/Hashing/CRC

于 2008-10-20T01:05:58.360 に答える