我一直在使用simhash算法。我根据我对爬虫的理解实现了它。但是,当我做一些测试时,对我来说似乎不太可靠。
我计算了200,000个不同文本数据的指纹,看到一些不同的内容有相同的指纹。所以碰撞有很大的可能性。
我的实施代码如下。
我的问题是:如果我的实现是正确的,那么这个算法就会发生很大的冲突。谷歌怎么用这个算法?否则,我的算法有什么问题?
public long CalculateSimHash(string input)
{
var vector = GenerateVector(input);
//5- Generate Fingerprint
long fingerprint = 0;
for (var i = 0; i < HashSize; i++)
{
if (vector[i] > 0)
{
var zz = Convert.ToInt64(1 << i);
fingerprint += Math.Abs(zz);
}
}
return fingerprint;
}
private int[] GenerateVector(string input)
{
//1- Tokenize input
ITokeniser tokeniser = new OverlappingStringTokeniser(2, 1);
var tokenizedValues = tokeniser.Tokenise(input);
//2- Hash values
var hashedValues = HashTokens(tokenizedValues);
//3- Prepare vector
var vector = new int[HashSize];
for (var i = 0; i < HashSize; i++)
{
vector[i] = 0;
}
//4- Fill vector according to bitsetof hash
foreach (var value in hashedValues)
{
for (var j = 0; j < HashSize; j++)
{
if (IsBitSet(value, j))
{
vector[j] += 1;
}
else
{
vector[j] -= 1;
}
}
}
return vector;
答案 0 :(得分:1)
我可以看到几个问题。首先,您只获得32位散列,而不是64位散列,因为您使用了错误的类型。见https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/left-shift-operator 这里最好不要使用有符号整数类型,以避免混淆。所以:
// Generate Fingerprint
ulong fingerprint = 0;
for (int i = 0; i < HashSize; i++)
{
if (vector[i] > 0)
{
fingerprint += 1UL << i;
}
}
第二个问题是:我不知道你的OverlappingStringTokenizer是如何工作的 - 所以我只是猜测 - 但如果你的带状疱疹(重叠的ngrams)只有2个字符长,那么很多这些带状疱疹会被发现在很多文件中。有可能两个文档将共享许多这些功能,即使文档的目的和含义完全不同。
因为单词在处理文本时是最小的简单意义单位,所以我通常用单词而不是字符来计算我的标记。当然,2个字符对于有效的功能来说太小了。我喜欢用5个单词生成带状疱疹,忽略标点符号和空格。