我正在将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的范围,哈希码可能/可能不相同(这将导致重复的文档)。
对此有任何替代解决方案吗?我们可以根据这些值创建一个字母数字字符串(或其他东西)吗?
提前致谢。
答案 0 :(得分:0)
你不会完全能够避免冲突,除非你将对象本身用作一个键......如果你想这样做,你可以将你的值序列化为一个序列对于 最明智的做法是使用这些值来计算hashCode,然后在发生碰撞时逐个比较每个成员以确保相等。这就是java 如果您想继续创建&#34;绝对唯一的标识符&#34;虽然... double
,date
8的字节数为8个字节(因为内部表示为long
,并且取决于name
...的长度,任意数量的字节/ p>
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);
答案 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如果我没有错。
不知道它是否是最合适的(或适当的)方式。但它似乎有效。
感谢