Java对象的唯一id
我正在将java对象索引到Elasticsearch中。下面是一个类的结构:Java对象的唯一id,java,hash,
elasticsearch,hashcode,identifier,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 } 公共类文档{ 私有字符串名称; 私人双重价值; 私人日期; 私有地图属
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的文档数量和范围,hashcode可能/可能不相同(这将导致重复文档)
有其他解决办法吗?我们可以根据这些值创建字母数字字符串(或其他东西)吗
提前感谢。除非将对象本身用作键,否则无法完全避免碰撞。。。如果您想这样做,您可以将您的值序列化为一个字节序列,即8个字节的双字节8个字节的日期(因为内部表示是长的
,以及任意数量的字节,具体取决于名称的长度
最明智的做法是使用这些值计算hashCode,然后在发生冲突时逐个比较每个成员以确保相等。这就是javaHashtable
的工作原理
如果你想继续创建你的“绝对唯一的标识符”
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);
byte[]defoUnique=新字节[24+name.size()];
byte[]dateBytes=Long.toByteArray(date.getTime());
对于(inti=0;i<8;i++)defoUnique[i]=dateBytes[i];
byte[]valueBytes=Long.toByteArray(Double.doubleToLongBits(value));
对于(int i=0;i<8;i++)defoUnique[i+8]=valueBytes[i];
byte[]nameBytes=name.getBytes();
对于(int i=0;i
您应该重写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,如果我没有错的话
不知道这是不是最合适的方式。但这似乎奏效了
谢谢对象的任何元素都是独一无二的吗?这些对象中的每一个都需要某种类型的id。所有元素都不是唯一的。但是,所有元素的组合都应该是唯一的。你的意思是担心所有哈希代码的大小是否足以容纳大量对象吗?是的。正是我的意思!int:默认情况下,int数据类型是32位带符号2的补码整数,最小值为-2^31,最大值为2^31-1。(20亿美元)。我不知道如何将对象本身用作键。。我想要的是一个数字(或字母数字)id,它对于一个对象来说是“有意义的”唯一的。i、 e.如果存在具有相同值的另一个对象,则id将相同。但是,在插入对象时,我将无法访问存储在ES中的现有数据(对象)。因此,我将生成一个id。如果有另一个对象具有相同的值,我的id将与其id匹配,因此,我的对象将不会被插入。这就是我想要的。谢谢。好的,在这种情况下,您可以使用我提供给您的字节[]
数组,并使用base64对其进行编码:我不确定修改equals
中的对象是否是一个好主意。。。