2010-11-24 11 views
44

UUIDライブラリは32文字のUUIDを生成します。8文字のUUIDを生成する

8文字のUUIDを生成したいのですが可能ですか?

+0

しかし、実際にはそれほど単純ではない可能性は低いです。なぜ? – delnan

+0

@delnan、組み込み環境で使用するには? –

答えて

38

UUIDは、定義ごとに16バイトの数であるので、それが不可能です。もちろん、8文字の長い一意の文字列を生成することができます(他の回答を参照)。

IDの一部に固定バイトが含まれる可能性があるため、長いUUIDを生成して部分文字列を入力することにも注意してください(MAC、DCE、MD5 UUIDの場合など)。

+0

how about timestamp –

+0

@annapoorani:タイムスタンプがマルチスレッドアクセスのために衝突する – peaceUser

-8

私はそれは可能だとは思わないが、良い回避策があります。

  1. カットあなたのUUID使用して、サブストリング()
  2. 利用コードnew Random(System.currentTimeMillis()).nextInt(99999999); の終わりには、これは長い8つの文字にランダムなIDを生成します。
  3. は、英数字のIDを生成する:

    char[] chars = "abcdefghijklmnopqrstuvwxyzABSDEFGHIJKLMNOPQRSTUVWXYZ1234567890".toCharArray(); 
    Random r = new Random(System.currentTimeMillis()); 
    char[] id = new char[8]; 
    for (int i = 0; i < 8; i++) { 
        id[i] = chars[r.nextInt(chars.length)]; 
    } 
    return new String(id); 
    
+11

残念ながら、これらのアプローチはすべて、あなたが望むよりも早くリピート(つまり固有でないID)を与える可能性があります。 –

+0

空のコンストラクタを使用するよりも現在の日付をランダムに生成するのがより少ないですか? – for3st

13

最初:java UUID.randomUUIDまたは.net GUIDによって生成された一意のIDであっても100%ユニークではありません。特にUUID.randomUUIDは128ビット(安全な)ランダム値の「唯一の」ものです。したがって、64ビット、32ビット、16ビット(または1ビット)に縮小すると、一意性が低下します。

少なくともリスクに基づく決定、あなたのuuidがどれぐらい長くなければならないか、ということです。

2番目:「8文字のみ」と言えば、通常の8文字の印刷可能文字列を意味します。

長さ8の印刷可能な文字で一意の文字列を使用する場合は、base64エンコーディングを使用できます。 6バイトのランダム配列を作成

SecureRandom rand; 
// ... 
byte[] randomBytes = new byte[16]; 
rand.nextBytes(randomBytes); 

: - (しかし、多分それはあなたのアプリケーションのためokです非常にユニークなことができない)ので、方法は簡単です

を使用すると、合計で48ビットを取得するのでこれは、文字ごとに6ビットを意味し、

BTW: "uuid"を作成してランダムに作成する方が良い場合は、アプリケーションによって異なります。 (UUIDを1秒に1回だけ作成する場合は、タイムスタンプを追加することをお勧めします) (ちなみに、2つのランダムな値を組み合わせると、結果は常に少なくとも両者のほとんどはランダム)。

-1

これはどうですか。実際には、このコードは最大13文字を返しますが、UUIDよりも短くなります。

import java.nio.ByteBuffer; 
import java.util.UUID; 

/** 
* Generate short UUID (13 characters) 
* 
* @return short UUID 
*/ 
public static String shortUUID() { 
    UUID uuid = UUID.randomUUID(); 
    long l = ByteBuffer.wrap(uuid.toString().getBytes()).getLong(); 
    return Long.toString(l, Character.MAX_RADIX); 
} 
+2

'getLong()'はバッファの最初の8バイトだけを読み取っていることを知っています。 UUIDには少なくとも36バイトが必要です。私に何かが見当たらないのは、これは決してうまくいかないからです。 –

+2

最初の8バイトはUUIDの最上位ビットです。 [この回答](http://stackoverflow.com/a/325457/851344)によると、下位ビットはよりランダムです。だから 'Long.toString(uuid.getLessSignificantBits()、Character.MAX_RADIX)'が優れています。 – DouO

0

あなたはRandomStringUtilsclass from apache.commonsを試すことができます@Cephalopodはそれができません述べていますが、22文字

public static String encodeUUIDBase64(UUID uuid) { 
     ByteBuffer bb = ByteBuffer.wrap(new byte[16]); 
     bb.putLong(uuid.getMostSignificantBits()); 
     bb.putLong(uuid.getLeastSignificantBits()); 
     return StringUtils.trimTrailingCharacter(BaseEncoding.base64Url().encode(bb.array()), '='); 
} 
15

にUUIDを短縮することができたよう:

import org.apache.commons.lang3.RandomStringUtils; 

final int SHORT_ID_LENGTH = 8; 

// all possible unicode characters 
String shortId = RandomStringUtils.random(SHORT_UID_LENGTH); 

心に留めておいてください、それは、URLでも人間にも優しいものではない可能性のあるすべての文字を含むことになる。

だから、あまりにも他の方法をチェックアウト:

// HEX: 0-9, a-f. For example: 6587fddb, c0f182c1 
shortId = RandomStringUtils.random(8, "abcdef"); 

// a-z, A-Z. For example: eRkgbzeF, MFcWSksx 
shortId = RandomStringUtils.randomAlphabetic(8); 

// 0-9. For example: 76091014, 03771122 
shortId = RandomStringUtils.randomNumeric(8); 

// a-z, A-Z, 0-9. For example: WRMcpIk7, s57JwCVA 
shortId = RandomStringUtils.randomAlphanumeric(8); 

他は小さいIDを持つIDの衝突の確率が大きくなる可能性が言ったように。あなたのケースにどのようにbirthday problemが適用されるかを確認してください。あなたはthis answerで近似を計算する方法を説明しています。

+1

'org.apache.commons.lang3.RandomStringUtils'は廃止予定ですので、https://commons.apache.org/proper/commons-text/で' org.apache.commons.text.RandomStringGenerator'を使うほうがよいでしょう。 – BrunoJCM

+0

'RandomStringGenerator'の新しい答えが追加されました。全く異なるコードです。 – BrunoJCM

+1

将来の視聴者のためのちょっとした一言、偶然性は一意性を保証するものではありません。ランダムジェネレータはランダム性を保証します。繰り返し値を持つ有効な乱数のセットを生成することができます。 –

0

実際にタイムスタンプベースのより短い一意の識別子が必要なので、以下のプログラムを試してみてください。

nanosecond + (endians.length * endians.length)の組み合わせで推測できます。

public class TimStampShorterUUID { 

    private static final Character [] endians = 
      {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 
      'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 
      'u', 'v', 'w', 'x', 'y', 'z', 
      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 
      'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 
      'U', 'V', 'W', 'X', 'Y', 'Z', 
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 
      }; 

    private static ThreadLocal<Character> threadLocal = new ThreadLocal<Character>(); 

    private static AtomicLong iterator = new AtomicLong(-1); 


    public static String generateShorterTxnId() { 
     // Keep this as secure random when we want more secure, in distributed systems 
     int firstLetter = ThreadLocalRandom.current().nextInt(0, (endians.length)); 

     //Sometimes your randomness and timestamp will be same value, 
     //when multiple threads are trying at the same nano second 
     //time hence to differentiate it, utilize the threads requesting 
     //for this value, the possible unique thread numbers == endians.length 
     Character secondLetter = threadLocal.get(); 
     if (secondLetter == null) { 
      synchronized (threadLocal) { 
       if (secondLetter == null) { 
        threadLocal.set(endians[(int) (iterator.incrementAndGet() % endians.length)]); 
       } 
      } 
      secondLetter = threadLocal.get(); 
     } 
     return "" + endians[firstLetter] + secondLetter + System.nanoTime(); 
    } 


    public static void main(String[] args) { 

     Map<String, String> uniqueKeysTestMap = new ConcurrentHashMap<>(); 

     Thread t1 = new Thread() { 
      @Override 
      public void run() { 
       while(true) { 
        String time = generateShorterTxnId(); 
        String result = uniqueKeysTestMap.put(time, ""); 
        if(result != null) { 
         System.out.println("failed! - " + time); 
        } 
       } 
      }  
     }; 

     Thread t2 = new Thread() { 
      @Override 
      public void run() { 
       while(true) { 
        String time = generateShorterTxnId(); 
        String result = uniqueKeysTestMap.put(time, ""); 
        if(result != null) { 
         System.out.println("failed! - " + time); 
        } 
       } 
      }  
     }; 

     Thread t3 = new Thread() { 
      @Override 
      public void run() { 
       while(true) { 
        String time = generateShorterTxnId(); 
        String result = uniqueKeysTestMap.put(time, ""); 
        if(result != null) { 
         System.out.println("failed! - " + time); 
        } 
       } 
      }  
     }; 

     Thread t4 = new Thread() { 
      @Override 
      public void run() { 
       while(true) { 
        String time = generateShorterTxnId(); 
        String result = uniqueKeysTestMap.put(time, ""); 
        if(result != null) { 
         System.out.println("failed! - " + time); 
        } 
       } 
      }  
     }; 

     Thread t5 = new Thread() { 
      @Override 
      public void run() { 
       while(true) { 
        String time = generateShorterTxnId(); 
        String result = uniqueKeysTestMap.put(time, ""); 
        if(result != null) { 
         System.out.println("failed! - " + time); 
        } 
       } 
      } 
     }; 

     Thread t6 = new Thread() { 
      @Override 
      public void run() { 
       while(true) { 
        String time = generateShorterTxnId(); 
        String result = uniqueKeysTestMap.put(time, ""); 
        if(result != null) { 
         System.out.println("failed! - " + time); 
        } 
       } 
      } 
     }; 

     Thread t7 = new Thread() { 
      @Override 
      public void run() { 
       while(true) { 
        String time = generateShorterTxnId(); 
        String result = uniqueKeysTestMap.put(time, ""); 
        if(result != null) { 
         System.out.println("failed! - " + time); 
        } 
       } 
      } 
     }; 

     t1.start(); 
     t2.start(); 
     t3.start(); 
     t4.start(); 
     t5.start(); 
     t6.start(); 
     t7.start(); 
    } 
} 

UPDATE:このコードは、単一のJVM上で動作しますが、我々は、分散JVM上で考えなければならない、それゆえ私は2つの解決策DBと1とDBのない別のものを考えています。 DB

会社名(短縮名3文字)---- ---- RANDOM_NUMBERキー特定Redisのカウンターで


(3文字)-------------- ----------------------------------(2文字)------------ ----(11 CHAR)

DB

せずIPADDRESS ---- ---- THREAD_NUMBER INCR_NUMBER ----エポックミリ秒
(5文字)を--------- --------(2char)-----------------------(2char)------------ -----(6文字)

は、コーディングが完了すると更新されます。

1

これは私がアントンプリンの回答に基づいて、固有のエラーコードを生成するために、ここで使用している同様の方法であるが、代わりに非推奨org.apache.commons.lang3.RandomStringUtilsorg.apache.commons.text.RandomStringGenerator頼る:まだ適用

@Singleton 
@Component 
public class ErrorCodeGenerator implements Supplier<String> { 

    private RandomStringGenerator errorCodeGenerator; 

    public ErrorCodeGenerator() { 
     errorCodeGenerator = new RandomStringGenerator.Builder() 
       .withinRange('0', 'z') 
       .filteredBy(t -> t >= '0' && t <= '9', t -> t >= 'A' && t <= 'Z', t -> t >= 'a' && t <= 'z') 
       .build(); 
    } 

    @Override 
    public String get() { 
     return errorCodeGenerator.generate(8); 
    } 

} 

衝突に関する全てのアドバイスを、それらに注意してください。

関連する問題