केवल 8 UUIDs जनरेट कर रहा है


82

यूयूआईडी पुस्तकालय 32-चरित्र यूयूआईडी उत्पन्न करते हैं।

मैं केवल 8 UUIDs उत्पन्न करना चाहता हूं, क्या यह संभव है?


ज़रूर। लेकिन यह वास्तव में सीधा और छोटा नहीं है, वास्तव में अद्वितीय होने की संभावना कम है। तो क्यों?

@delnan, एम्बेडेड वातावरण में उपयोग किया जा सकता है?
एलन झांग

1
यदि परिणामस्वरूप स्ट्रिंग को UTF-8 में संग्रहीत किया जा सकता है, तो आपके पास संभावित रूप से प्रति वर्ण 4 बाइट्स होंगे। यदि आप उस संपूर्ण सीमा का उपयोग कर सकते हैं तो आपको उसी जानकारी का प्रतिनिधित्व करने के लिए केवल 4 UTF-8 वर्णों की आवश्यकता होगी।
EECOLOR

जवाबों:


72

यह संभव नहीं है क्योंकि यूयूआईडी प्रति परिभाषा 16-बाइट संख्या है। लेकिन निश्चित रूप से, आप 8-वर्ण लंबी अनूठी स्ट्रिंग्स उत्पन्न कर सकते हैं (अन्य उत्तर देखें)।

इसके अलावा अधिक समय तक यूयूआईडी उत्पन्न करने और उन्हें प्रतिस्थापित करने के साथ सावधान रहें, क्योंकि आईडी के कुछ हिस्सों में निश्चित बाइट्स हो सकते हैं (जैसे कि मैक, डीसीई और एमडी 5 यूयूआईडी के साथ यही स्थिति है)।


कैसे टाइमस्टैम्प के बारे में
anna गरीबानी

60

आप RandomStringUtils apache.commons से क्लास ट्राई कर सकते हैं :

import org.apache.commons.lang3.RandomStringUtils;

final int SHORT_ID_LENGTH = 8;

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

कृपया ध्यान रखें, इसमें सभी संभव अक्षर होंगे जो न तो URL है और न ही मानव के अनुकूल।

इसलिए अन्य तरीकों की भी जाँच करें:

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

// 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); 

जैसा कि अन्य लोगों ने कहा कि छोटी आईडी के साथ आईडी के टकराने की संभावना महत्वपूर्ण हो सकती है। देखें कि आपके मामले में जन्मदिन की समस्या कैसे लागू होती है। इस उत्तर में सन्निकटन की गणना कैसे करें, आप अच्छी व्याख्या पा सकते हैं ।


4
के बाद से org.apache.commons.lang3.RandomStringUtilsहटा दिया गया है, तो आप बेहतर उपयोग करते हुए हो जाएगा org.apache.commons.text.RandomStringGeneratorमें commons.apache.org/proper/commons-text
BrunoJCM

के लिए एक नया उत्तर जोड़ा गया RandomStringGenerator, क्योंकि यह काफी अलग कोड है।
BrunoJCM

2
भविष्य के दर्शकों के लिए बस एक FYI करें, Randomness विशिष्टता की गारंटी नहीं देता है। यादृच्छिक जनरेटर यादृच्छिकता की गारंटी देते हैं; और दोहराए गए मूल्यों के साथ यादृच्छिक संख्याओं का एक वैध सेट उत्पन्न कर सकता है।
विष्णु प्रसाद वि।

RandomStringUtilsपदावनत नहीं किया जाता है। यह सरल उपयोग के लिए अभिप्रेत है। क्या आप उस जानकारी का स्रोत प्रदान कर सकते हैं जो RandomStringUtilsपदावनत है? मैं RandomStringUtilsएक प्रमाण के रूप में नवीनतम संस्करण का प्रलेखन प्रदान कर सकता हूं कि यह पदावनत नहीं किया गया है: commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/……
krm

केवल पहले से ही उपयोग किए गए uuids के साथ एक नक्शा या हैशसेट की जाँच करके, टक्कर की संभावना बहुत बड़ी है।
एंटोन

18

पहला: यहां तक ​​कि जावा यूयूआईडी.randomUUID या .net GUID द्वारा उत्पन्न अद्वितीय आईडी 100% अद्वितीय नहीं हैं। विशिष्ट UUID.randomUUID "केवल" एक 128 बिट (सुरक्षित) यादृच्छिक मूल्य है। इसलिए यदि आप इसे 64 बिट, 32 बिट, 16 बिट (या यहां तक ​​कि 1 बिट) तक कम कर देते हैं तो यह बस कम अद्वितीय बन जाता है।

इसलिए यह कम से कम जोखिम आधारित निर्णय है, आपका यूआईडी कब तक होना चाहिए।

दूसरा: मेरा मानना ​​है कि जब आप "केवल 8 वर्णों" के बारे में बात करते हैं तो आपका मतलब है 8 सामान्य मुद्रण योग्य वर्णों का एक स्ट्रिंग।

यदि आप लंबाई 8 मुद्रण योग्य वर्णों के साथ एक अद्वितीय स्ट्रिंग चाहते हैं तो आप एक बेस 64 एन्कोडिंग का उपयोग कर सकते हैं। इसका मतलब है 6 बिट प्रति चार्ट, इसलिए आपको कुल 48bit मिलता है (संभव है कि बहुत अनूठा न हो - लेकिन शायद यह आपके लिए ठीक है)

तो रास्ता आसान है: एक 6 बाइट यादृच्छिक सरणी बनाएँ

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

और फिर इसे एक बेस 64 स्ट्रिंग में बदल दें, उदाहरण के लिए org.apache.commons.codec.binary.Base64

BTW: यह आपके आवेदन पर निर्भर करता है अगर "uuid" बनाने का एक बेहतर तरीका है तो यादृच्छिक। (यदि आप प्रति सेकंड केवल एक बार UUIDs बनाते हैं, तो टाइम स्टैंप को जोड़ना एक अच्छा विचार है) (वैसे: यदि आप दो यादृच्छिक मूल्यों को जोड़ते हैं (xor), तो परिणाम हमेशा कम से कम यादृच्छिक रूप से सबसे अधिक होता है दोनों का यादृच्छिक)।


7

जैसा कि @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()), '=');
}

2

यह एक ऐसा ही तरीका है जिसका उपयोग मैं यहां एक अनोखा त्रुटि कोड जनरेट करने के लिए कर रहा हूं, जो कि एंटोन पुरीन के उत्तर पर आधारित है, लेकिन org.apache.commons.text.RandomStringGenerator(एक बार, अब और नहीं) के बजाय अधिक उपयुक्त पर निर्भर करता है org.apache.commons.lang3.RandomStringUtils:

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

}

टक्कर के बारे में सभी सलाह अभी भी लागू होती हैं, कृपया उनके बारे में पता करें।


RandomStringUtilsपदावनत नहीं किया जाता है। यह सरल उपयोग के लिए अभिप्रेत है। क्या आप उस जानकारी का एक स्रोत प्रदान कर सकते हैं जो RandomStringUtilsपदावनत है? मैं RandomStringUtilsएक प्रमाण के रूप में नवीनतम संस्करण के प्रलेखन प्रदान कर सकता हूं कि यह पदावनत नहीं किया गया है: commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/……
krm

ठीक है, अगर आप थोड़ा और खोदते हैं, तो आप देखेंगे कि, इस उत्तर के लिखने के समय के रूप में, नवीनतम रिलीज़ ने वास्तव में इस वर्ग को हटा दिया था: github.com/apache/commons-lang/commits/master/src / main / java / org /… संभवतः कुछ प्रतिक्रिया ( user.commons.apache.narkive.com/GVBG2Ar0/… ) ने इसे वापस बनाया। आपको किसी भी चीज़ का उपयोग नहीं करना चाहिए जो commons.langकि वैसे भी भाषा से कड़ाई से संबंधित नहीं है, commons.textएक उद्देश्य के साथ बनाया गया था।
ब्रूनो जेसीएम

स्पष्टीकरण ब्रूनो जेसीएम के लिए धन्यवाद। वर्तमान समय RandomStringUtilsमें पदावनत नहीं किया जाता है और आपके द्वारा उपलब्ध कराए गए संदर्भों के अनुसार इसे हटाए नहीं रखने का एक अच्छा कारण है, क्योंकि यह RandomStringGeneratorसरल उपयोग के मामलों की तुलना में उपयोग करने के लिए बहुत सरल है । शायद आप अपना जवाब अपडेट कर सकते हैं? यदि / जब RandomStringUtilsया साधारण उपयोग के मामलों के लिए इसकी कार्यक्षमता को स्थानांतरित कर दिया जाएगा commons.text, तो आप अपने उत्तर को फिर से अपडेट कर सकते हैं, लेकिन वर्तमान में यह भ्रामक है।
क्रि।

एक नोट जोड़ा गया है, लेकिन फिर से, यह स्पष्ट है कि अपाचे कॉमन्स परियोजना पाठ के बर्तनों को आगे बढ़ा रही commons.langहै commons.text, किसी के लिए पूर्ववर्ती का उपयोग करने के बजाय किसी अन्य के लिए इसका उपयोग करने का कोई कारण नहीं है क्योंकि यह पहले से कहीं और उपयोग कर रहा है। यहाँ सादगी बल्कि व्यक्तिपरक है, मुझे अपना उत्तर अभी भी बहुत सरल लगता है, और मैं इसे कभी भी किसी ऐसी चीज के लिए नहीं बदलूंगा जिसके लिए कॉमन्स लैंग को आयात करना होगा।
ब्रूनो जेसीएम 15

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

4
आप जानते हैं कि getLong()केवल बफर के पहले 8 बाइट्स को पढ़ना है। यूयूआईडी में कम से कम 36 बाइट होंगी। क्या मुझे कुछ याद आ रहा है क्योंकि मेरे लिए यह कभी काम नहीं करेगा।
एडविन डेलोरजो

2
पहले 8 बाइट्स UUID के सबसे महत्वपूर्ण बिट्स हैं। इस उत्तर के अनुसार कम महत्वपूर्ण बिट अधिक यादृच्छिक है। तो Long.toString(uuid.getLessSignificantBits(), Character.MAX_RADIX)बेहतर है।
डीयू

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

अपडेट करें : यह कोड एकल JVM पर काम करेगा, लेकिन हमें वितरित JVM पर सोचना चाहिए, इसलिए मैं DB के साथ दो समाधान सोच रहा हूं और DB के बिना एक और।

डीबी के साथ

कंपनी का नाम (शोर्टनाम 3 चार्ट्स) ---- रैंडम_Number ---- प्रमुख विशिष्ट रेडीस कॉर्नर
(3 चार) -------------------------- ---------------------- (2 char) ---------------- (11 char)

बिना डी.बी.

IPADDRESS ---- THREAD_NUMBER ---- INCR_NUMBER ---- युगीन मिलीसेकंड
(5 वर्ण) ----------------- (2char) --------- -------------- (2 char) ----------------- (6 char)

कोडिंग हो जाने के बाद आपको अपडेट करेगा।



-11

मुझे नहीं लगता कि यह संभव है लेकिन आपके पास एक अच्छा समाधान है।

  1. () का उपयोग कर अपने UUID के अंत में कटौती
  2. उपयोग कोड new Random(System.currentTimeMillis()).nextInt(99999999); यह 8 अक्षर तक की यादृच्छिक आईडी उत्पन्न करेगा।
  3. अल्फ़ान्यूमेरिक आईडी बनाएँ:

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

14
दुर्भाग्य से, इन सभी दृष्टिकोणों से आप जितनी जल्दी चाहते हैं, आपको दोहराने की संभावना है (यानी गैर-अद्वितीय Ids)।
स्टीफन सी

1
खाली कंस्ट्रक्टर का उपयोग करने की तुलना में वर्तमान तिथि के साथ बीजारोपण कम यादृच्छिक नहीं है?
पैट्रिक फेवर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.