1

我想从一个文本(在我的例子中是html)中制作一种哈希键,它可以匹配/比较其他类似文本的哈希

匹配文本的前:

  • “2012/10/01 这是我的网页 #1”+ 100k_of_same_text + random_words_1 + ..
  • “2012/10/02 这是我的网页 #2”+ 100k_of_same_text + random_words_2 + ..
  • ...
  • “2012/10/02 这是我的网页 #2”+ 100k_of_same_text + random_words_3 + ..

到目前为止,我已经考虑过删除数字和标签,但这仍然会留下随机单词。

有什么东西可以剂量吗?

我对服务器具有 root 访问权限,因此我可以添加任何必要的 UDF,如果需要,我可以用 c 或其他语言进行处理。

理想的情况是一个类似的函数generateSimilarHash(text)和一个compareSimilarHashes(hash1,hash2)返回匹配文本的概率的函数。

像 compare(text1,text2) 这样的任何函数都不会像我的情况那样工作,因为我有很多页面要比较(目前约 2000 万)

欢迎任何建议!

4

3 回答 3

2

我从来没有做过这样的事情,所以只是根据一般的散列知识扔掉一些东西。

首先,一般来说,我怀疑您是否可以将要比较的整个字符串表示为从中散列的一个值,然后仅使用该值有意义地找到近似匹配。散列函数通常被设计成从输入值的最小变化中产生巨大的伪随机输出值差异 - 所以天真地使用它们并不适合解决这个问题,但是......

可能有用的是使用一些约定将长文本分成小节,例如寻找至少 N 个字符的终止标点符号(句号、感叹号、问号),然后您可以散列这些单独的子字符串并使用匹配散列的计数来近似匹配文本的数量。

您必须计算出合适的粒度级别,以将文本划分为合理数量的不同散列 - 平衡散列的大小和散列比较的速度与匹配的准确性。您可能还需要进行一些先前的转换,例如将字符转换为单个大小写或将一个或多个空白字符的每个区域替换为单个空格,也许将标点符号替换为空格:这样微不足道的差异不会导致散列不匹配 - 调整口味。

在您的示例中:

“2012/10/01 这是我的网页 #1”+ 100k_of_same_text + random_words_1 + ..

假设你在句号上打断,或者没有句号,我们发现局部最小值按排序的词序排列,这样一个部分中最多出现 5-20 个词......你最终可能会得到如下子字符串:

  • “2012/10/01 这是我的网页#1。”
  • “这是 100k 文本中的第一位。”
  • “这是 100k 文本中的第二位。”
  • “还有 100k 的一点。”
  • 《鸡书狗蜡笔抱抱》
    • 由于“苹果”是本地最小值而中断
  • “苹果树枝纸手套书挡 ibm”
    • 由于“激活”是本地最小值而中断
  • “激活篡位黑社会活动扳手。”
    • 打断 ”。”
  • 《斑马意大利夸克炖世纪恐龙夹克彩蛋把戏》
    • 由于“鸡”是本地最小值而中断;“世纪”是 < 5 个单词
  • “鸡笑话路坏”

然后你在上面的每一个上使用一个普通的字符串散列函数。要将其与其他类似散列的文本进行比较,您需要查找匹配散列值的数量(如果您不重视匹配的文本小节的顺序或连续性,则迭代预先排序的列表非常有效两组哈希,或用哈希值预先填充哈希表,然后依次查找每个哈希表)。

于 2013-02-07T09:26:40.600 回答
1

我想我会回答这个问题,因为我正在研究一个类似的问题。这种具有高冲突可能性的相似对象散列的想法的名称是“局部敏感散列”。关于这个主题有很多文献,但这里有一个简单的例子:

假设我们有一个固定长度的二进制向量 {1,0}。我们可以使用内置的 stl 和 boost 算法选择一个随机的索引子集来计算哈希:

#include <unordered_map>
#include <unordered_set>
#include <random>
#include <algorithm>
#include <boost/iterator/filter_iterator.hpp>
#include <boost/functional/hash.hpp>


template<class It, class pred>
std::size_t hash_filtered_range(It first, It last, pred f){

    return boost::hash_range(boost::make_filter_iterator(f, first, last),
                             boost::make_filter_iterator(f, last, last));


}

template<class iter>
struct IterableHash{
    IterableHash(const iter indices_begin, const iter indices_end): _inc_indices(indices_begin, indices_end){
    }

    template <class obj_type>
    std::size_t operator()(const obj_type& type)const{
        int _ix = 0;
        return hash_filtered_range(std::begin(type), std::end(type), [this, &_ix](const auto& t){
           return (this->_inc_indices.find(_ix++) != this->_inc_indices.end());
        });
    }

private:
    std::unordered_set<int> _inc_indices;

};


template<class hasher>
struct ApproxEqual{
    ApproxEqual(const hasher& hash):hash(hash) {}

    template<class obj_type>
    bool operator() (const obj_type& o1, const obj_type& o2)const{
        return hash(o1) == hash(o2);

    }
private:
    hasher hash;

};

然后,如果可迭代对象仅在以下索引处相等,则它们具有相同的哈希值和相等值:

即在我的电脑上

std::vector<int> hash_vec{0,2,3};

    using it = std::vector<int>::iterator;
    IterableHash<it> hasher(hash_vec.begin(),
                     hash_vec.end());

    ApproxEqual<IterableHash<it>> cmp(hasher);
    std::unordered_map<std::vector<char>, int, IterableHash<it>, ApproxEqual<IterableHash<it>> > map( 0, hasher,
                                                                                            cmp);
    std::vector<char> vec {1,0,1,0,1};
    map[vec] = 33;

    std::cout << hasher(vec)<< "\n";


    std::vector<char> fuzzy_vec {1,0,1,0,0};

    std::cout << hasher(fuzzy_vec)<< "\n";
    std::cout << (map.find(fuzzy_vec)->second);

生产

11093822460655

11093822460655

33

即,当我们使用fuzzy_res 查询时,我们恢复了不同向量res 的值;

于 2016-09-26T16:22:09.703 回答
0

您可以尝试对随机词使用 DJB 哈希算法。然后比较哈希键。确实,两个不同的文本给出相同结果的可能性总是很小...但是如果 32 位的哈希值不够,您可以将其扩展为 64 位和/或保留对文本的引用以比较它们何时哈希是相同的。

更多细节在这里:DJB Hash

于 2013-02-07T09:11:30.737 回答