簡體   English   中英

Java object 的唯一 ID

[英]Unique id for Java object

我將 java 對象索引到 Elasticsearch 中。 以下是 class 的結構:

public Class Document{
    private String name;
    private double value;
    private Date date;
    private Map<String, String> attributes;
    //getters and setters
}

在我索引任何 object 之前,我想計算/導出 object 的唯一 ID,它應該基於這些成員的值。 如果我構造另一個 object 具有相同的名稱、日期、值和屬性值(即,如果鍵值對的數量和值相同),那么 ID 也應該相同。

目前,我正在使用Objects.hash(Object... objects)來計算 hashCode 並將該 hashCode 設置為 id。 它似乎工作正常。 對於這些屬性具有相同值的對象,它返回相同的 integer。 但是,考慮到 java 中 int 的文檔數量和范圍,哈希碼可能/可能不同(這將導致重復文檔)。

對此有任何替代解決方案嗎? 我們可以根據這些值創建一個字母數字字符串(或其他東西)嗎?

提前致謝。

除非您將對象本身用作鍵,否則您將無法完全避免沖突……如果您希望這樣做,則可以將值序列化為一個字節序列,即8個字節表示date double 8(因為內部表示很long ,根據您name的長度任意字節數...

最明智的做法是使用這些值來計算hashCode,然后在發生沖突時逐個比較每個成員以確保相等。 這就是Java Hashtable工作方式。

如果您想繼續創建“絕對唯一的標識符”,請...

byte[] defoUnique = new byte[24 + name.size()];
byte[] dateBytes = Long.toByteArray(date.getTime());
for (int i = 0 ; i < 8 ; i++) defoUnique[i] = dateBytes[i];
byte[] valueBytes = Long.toByteArray(Double.doubleToLongBits(value));
for (int i = 0 ; i < 8 ; i++) defoUnique[i+8] = valueBytes[i];
byte[] nameBytes = name.getBytes();
for (int i = 0 ; i < nameBytes.length ; i++) defoUnique[i+16] = nameBytes[i];

/* Make byte sequence into alphanumeric string */
String identifierString = Base64.getEncoder().encodeToString(defoUnique);

您應該重寫equals()和hashcode()。 (常見的錯誤是不同時覆蓋兩者)。

以下是一個示例。 想法是為每個對象創建一個哈希碼並測試是否相等(無論是否返回對象)

例:

    // from http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/builder/HashCodeBuilder.html
     public class Person {
       String name;
       int age;
       boolean smoker;
       int id;  // this is your bit

       public int hashCode() {
         // you pick a hard-coded, randomly chosen, non-zero, odd number
         // ideally different for each class
         return new HashCodeBuilder(17, 37).
           append(name).
           append(age).
           append(smoker).
           toHashCode();
       }
     }

  public boolean equals(Object obj) {
  // the next 3 ifs are a 'short' circuit'
       if (obj == null) { return false; }
       if (obj == this) { return true; }
       if (obj.getClass() != getClass()) {
         return false;
       }

       // the meat of it
       MyClass rhs = (MyClass) obj;

       boolean sameClass = new EqualsBuilder()
                     .appendSuper(super.equals(obj))
                     .append(field1, rhs.field1)
                     .append(field2, rhs.field2)
                     .append(field3, rhs.field3)
                     .isEquals();

       //  here set/update your id
           if (sameClass){
                 this.id = rhs.id
           }

           return sameClass 
          }

最終有這樣的事情:

/**
     * Sets the id of document by calculating hash for individual elements
     */
    public void calculateHash(){
        ByteBuffer byteBuffer = ByteBuffer.allocate(16);
        byteBuffer.putInt(Objects.hashCode(name));
        byteBuffer.putInt(Objects.hashCode(date));
        byteBuffer.putInt(Objects.hashCode(value));
        byteBuffer.putInt(Objects.hashCode(attributes));
        super.setId(DigestUtils.sha512Hex(byteBuffer.array())); 
        byteBuffer.clear();
    }

因此,基本上,我計算單個元素的哈希,將它們填充到字節數組中,然后計算該元素的SHA-1哈希。 因此,發生碰撞的機會非常少。 即使一個哈希發生沖突,其他哈希也不太可能也發生沖突(因為這是4個哈希的組合)。 我認為發生碰撞的可能性為(1/4億)^ 4,這對我來說是更好的方法:) 例如, int哈希可以具有40億個值,因此,一個值的概率為1 /(40億),並且在其他地方具有相同編號的數字是1 / 4b x 1 / 4b x 1 / 4b x 1 / 4b,即(1 / 4b)^ 4(如果我沒記錯的話)。

不知道這是否是最合適的方法。 但這似乎奏效了。

謝謝

hashCode() 給出 32 位,如果這將有沖突的風險,請使用不同的散列算法。

java.security.MessageDigest 在 Java 中提供選項

我會為此推薦“MD5”,它會為您提供 128 位數字

"MD5" = 128 bits
"SHA1" = 160 bits
"SHA-256" = 256 bits
"SHA-384" = 384 bits
"SHA-512" = 512 bits

您不必擔心 md5 或 sha-1 的加密問題

權衡 hash 的大小,有碰撞的機會。

總是有碰撞的危險,要完全避免它把貓元素串在一起。 以 16,32 或 64 為基數表示數字以節省一點空間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM