Java对象的唯一ID

时间:2015-02-05 23:10:22

标签: java hash elasticsearch hashcode identifier

我正在将java对象索引到Elasticsearch中。以下是一个类的结构:

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

在索引任何对象之前,我想计算/派生一个对象的唯一ID,该ID应该基于这些成员的值。如果我构造另一个具有相同名称,日期,值和属性值的对象(即,如果键值对的数量和值相同),那么id应该也是相同的。

目前,我正在使用Objects.hash(Object... objects)来计算hashCode并将该hashCode设置为id。它似乎工作正常。它为具有相同值的对象返回相同的整数。但是,考虑到java中文档的数量和int的范围,哈希码可能/可能不相同(这将导致重复的文档)。

对此有任何替代解决方案吗?我们可以根据这些值创建一个字母数字字符串(或其他东西)吗?

提前致谢。

3 个答案:

答案 0 :(得分:0)

你不会完全能够避免冲突,除非你将对象本身用作一个键......如果你想这样做,你可以将你的值序列化为一个序列对于doubledate 8的字节数为8个字节(因为内部表示为long,并且取决于name ...的长度,任意数量的字节/ p>

最明智的做法是使用这些值来计算hashCode,然后在发生碰撞时逐个比较每个成员以确保相等。这就是java Hashtable的工作原理。

如果您想继续创建&#34;绝对唯一的标识符&#34;虽然...

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

答案 1 :(得分:0)

你应该重写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 
          }

答案 2 :(得分:0)

结束了这样的事情:

/**
     * 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 hash可以有40亿个值,因此,一个值的概率是1 /(40亿),并且其他地方具有相同数字的概率是1 / 4b x 1 / 4b x 1 / 4b x 1 / 4b即(1 / 4b)^ 4如果我没有错。

不知道它是否是最合适的(或适当的)方式。但它似乎有效。

感谢