E2LSH的原理与实现

E2LSH

E2LSH一个是用来解决高维空间近邻搜索问题的工具包。E2LSH实现了R-NN问题的随机化解决方案,即(R, 1 −δ )-near neighbor:每个满足||q-p|| 2 ≤ R的点p被报告的概率至少为1 −δ。E2LSH的实现基于基本的LSH模式。

Hash函数族

E2LSH使用基于p-stable分布的哈希函数族: ha,b=[a⃗ v⃗ +bw] 其中a是一个d维向量,a的每一项是从p-stable分布中随机独立选取的;b是从[0, w]中均匀选取的一个实数。有了一组确定的a和b,也就产生了一个相应的 ha,b(v)RdZ ,将一个d维的点向量v映射到一个整数。

LSH基本过程

定义g函数: gi(v)=(h1(v),h2(v),...,hk(v))1iL ,对应L个哈希表,每个g函数随机独立产生。每个g函数由在哈希函数族 ha,b 中随机独立选取的k个h函数组成。g函数的值对应具体的哈希桶。

使用LSH进行R-NN或k-NN搜索的过程主要分为建立索引和查询两步。建立索引时,对数据集中的每个点v∈P,计算其L个g函数值,并将其存入L个表中对应的哈希桶内。查询时,同样计算查询点q的L个g函数值,则找到q所在的L个哈希桶,计算这些哈希桶中的点与q的距离,找到规定距离R之内的点(R-NN),或k个距离最近的点(k-NN)。

参数的确定

L的确定

参数L的确定需要根据前面提到的(R, 1 −δ )-near neighbor的定义来解决,即一个近邻点被报告的概率至少为1 −δ。给定一个查询点q,近邻点v ∈ B(q,R),设p 1= p(R),两点在某个桶中发生碰撞,即在一个g函数中两点的值相等,应满足: PrgG[g(q)=g(v)]pk1 那么q和v在L个g函数中的值都不相等概率至多为 (1pk1)L 则q在至少一个g函数中与v的值相等的概率满足: 1(1pk1)L1δ 则L满足: Llogδlog(1pk1) 。 因为建立哈希表的时间与L的值正相关,因此为了减少建立索引的时间,L取下界。

k的确定

为了确定参数k的取值,首先需要知道使用E2LSH进行R-NN查询的查询时间分为两部分: - Tg=O(dkL) :为查询点q计算L个 gi1iL ,函数并在各表中检索gi(p)桶的时间 - Tc=O(d#collisions) :计算发生碰撞的桶中的点与查询点q之间的距离的时间 其中#collisions是碰撞的桶的数目,\#collisions的期望为: E(#collisions)=L×vPpk(||qv||2)

根据Tg与Tc的计算方式可知,Tg随k的增大而增大,Tc随k的增大而减小,因此存在一个k的最优值使Tg+Tc最小。对不同的查询点q来说Tc是不同的,因此需要计算Tc的平均值,根据其平均值来估计k的最优值。 E2LSH的实现是从查询集中随机选取一组样本点组成集合S,构造一个样本数据结构,并在这个数据结构上执行多次查询,测得一组真实的Tg与Tc的值,计算出Tc的平均值 Tc Tc=qSTc(q)|S| ,则k取 Tg+Tc 最小时对应的值。

gi 的快速计算

在基本的LSH方法中,g函数的确定过程是在哈希函数族中均匀随机独立选取L个函数gi = (h(i)1 , … , h(i)k ),则需要O(d)时间计算h j (i)(q),O(dkL)时间计算g1(q), … , gL(q)。为了减少计算函数gi函数的时间,需重用一部分h j (i)函数,过程如下:
    - 设k为偶数,m是一个常数,定义函数 ui=(h(i)1,...,h(i)k/2)
    - 重新定义 gi=(ua,ub)1a<bm ,即先产生k/2个h函数,再产生k/2个h函数(不再相互独立地选取,而是可重用,且已计算过的不需要重复计算),然后进行组合产生g函数
    - 总共的哈希表个数为 L=C1m+C2m1+...+C11=m(m1)2
因为每个g函数需要两个u函数,因此需要在至少两个u函数内q和v的值相等时,才会产生一个相应的g函数使q和v的相应值相等,即在对应桶中发生碰撞。根据u函数的定义,有:

m个u函数中q和v的值都不相等的概率为 : (1pk/21)m

只有一个u函数中q和v的值相等的概率为: m×pk/21×(1pk/21)m1

根据前面内容,则新的gi下q在至少一个g函数中的值与v相等的概率满足: 1(1pk/21)mm×pk/21×(1pk/21)m11δ

该式计算出来的L会比gi相互独立时计算的L值略大一点,但依然是 O(log1/δpk1) 的,新的时间复杂度降低为O(dkm)=O(dk√L)

实现细节

桶哈希

对数据集中的点使用哈希函数哈希之后得到g(v)=(h1(v),…,hk(v)),但将(h1(v),…,hk(v))直接存入哈希表,即占用内存,又不便于查找,为解决此问题,E2LSH使用了另外两个哈希函数:

    - h1Zk{0,...,tableSize1}
    - h2:Zk{0,...,C} ,C是一个大素数
h1的值作为哈希表的索引;h2作为链表中桶的索引。h1、h2的具体形式如下:

    - h1(a1,a2,...,ak)=((ki=1r'i×ai)mod prime)mod tableSize
    - h2(a1,a2,...,ak)=((ki=1r'i×ai)mod prime)
其中r’和r”是两个随机整数,C取值为2 32-5

由于每一个哈希桶(Hash Buckets)gi被映射成Zk,函数h1是普通哈希策略的哈希函数,函数h2用来确定链表中的哈希桶。 (1)要在一个链表中存储一个哈希桶gi(v)=(x1,…,xk)时,使用指纹h2(x1,…,xk)构造的指纹代替向量(x1,…,xk),因此一个哈希桶gi(v)=(x1,…,xk)在链表中的存储的相关信息仅包括标识(identifier)指纹h2(x1,…,xk)和相应的原始数据点。 (2)存储指纹值h2,而不是存储gi(v)=(x1,…,xk)的值有两个原因:首先,用h2(x1,…,xk)构造的指纹将单个哈希桶的存储空间从O(k)降到了O(1);其次,使用指纹值可以更快的检索哈希表中哈希桶。通过选取一个足够大的h2的值域来保证任意两个不同的哈希桶在链表中有不同的h2指纹值。 具体过程如下图所示

E2LSH的原理与实现_第1张图片

你可能感兴趣的:(相似性搜索,LSH)