如何提升搜索系统查询速度?

1 导语

为什么同样的查询我的代码要1s,别人的只要50ms?

为什么百度搜图可以处理上亿数据最近邻而我的机器几百万数据查询就很慢?

对于大部分互联网服务,网站相应时间和用户满意度是非常相关的。如果你是一家电商创业公司,用户输入一个Query后1~2s都没有结果显示,这时间就足够他放弃你们的产品转而去访问淘宝或者京东,开始新的一次查询。

在当今这个移动互联网时代,我们的日常生活每天都面临着海量数据地冲击,诸如像个人信息、视频 记录、图像采集、地理信息、日志文档等,面对如此庞大且日益增长的数据信息,如何对我们需要的海量信息有效的存储及索引,以便快速查询是目前国内外研究的热点。

2 最近邻搜索

日志、图像、视频等数据的查找的本质是最近邻搜索任务

最近邻检索就是根据数据的相似性,从数据库中寻找与目标数据最相似的项目,而这种相似性通常会被量化到空间上数据之间的距离,可以认为数据在空间中的距离越近,则数据之间的相似性越高。

最近邻搜索一般方法:线性查找

最简单的近邻搜索涉及数据集中所有成对点之间距离的暴力计算,也就是平常所说的穷举搜索。

在数据库中依次计算其中样本与所查询数据之间的距离,抽取出所计算出来的距离最小的样本即为所要查找的最近邻。

一般方法索面临的挑战:

对于小数据样本,高效的暴力近邻搜索是非常有竞争力的。然而,随着样本数N的增长,暴力方法失去了可行性。

搜索和推荐系统的计算量很大,我们面对和需要处理的数据往往是海量并且具有很高的维度(high dimensional spaces),同时数据中又普遍存在着近似相同的情况(例如相似的对话、相似的网页、相似的图片等),怎样快速地从海量的高维数据集合中找到与某个数据近似相似(approximate or exact Near Neighbor)的一个数据或多个数据,成为了一个难点和问题。

3 近似最邻近搜索

面对庞大的数据量以及数据库中高维的数据信息,现有的基于 最近邻搜索 的检索方法无法获得理想的检索效果与可接受的检索时间。进而有研究人员开始关注近似最近邻检索(Approximate Nearest Neighbor,ANN)

近似最近邻检索利用了数据之间形成簇状聚集分布的特性,通过对数据分析聚类的方法对数据库中的数据进行分类或编码,完成对全空间分割,将其分割成很多小的子空间,在搜索的时候,通过某种方式,快速锁定在某一子空间,然后在该子空间里做遍历。

近似最近邻检索的核心思想是搜索可能是近邻的数据项而不再只局限于返回最可能的项目,在牺牲可接受范围内的精度的情况下提高检索效率。

可以将ANN的方法分为三大类:基于树的方法、哈希方法、矢量量化方法。

3.1 基于树的近似最近邻算法

当待搜索数据维度为一的时候:只要采用传统的二分查找法或者各类平衡树就能找到最近邻,比如下图利用二分检索树总众多一维数据中快速找到符合要求的数据可以大幅缩小计算的次数。

二分检索树

当数据维度不太高(如d< 20),通常采用树型索引结构对数据进行分区以实现高效索引,如最经典的KD树算法 、R树、M树等等,它们的时间和空间复杂度都是以d为指数的指数级别的,在实际搜索时也取得了良好的效果。

其中,KD-Tree 是由 Finkel 和 Bentley 共同设计提出的对二叉搜索树的推广,利用KD-Tree 我们可以对一个由 K 维数据组成的数据集合进行划分,划分时在树的每一层上根据设定好的分辨器(discriminator)选取数据的某一维,比较待分配数据与节点数据在这一维度上数值的大小,根据结果将数据划分到左右子树中。

比如X= {(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)}这样的一个由6个点构成的二维点集,我们首先对它的第一维X进行划分,根据二分将(7,2)作为根节点,那么数据点的x轴小于7的划分到左子树,大于7的划分到右子树;再对第二维Y进行划分时,则根据数据点的y轴的大小进行左右划分。

如何提升搜索系统查询速度?_第1张图片

那么对于k维的点集,我们只需要依照上面的方法进行k层这样的划分就可以构成一棵KD-Tree 。在做最近邻检索时,只需要从根节点到叶子节点自上而下的检索较线性查找节省了大量时间。

如何提升搜索系统查询速度?_第2张图片

3.2 基于哈希的近似最近邻算法

局部敏感哈希(Locality-Sensitive Hashing, LSH)是用来解决高维检索问题的经典基于哈希法的近似最近邻算法。

由于线性搜索,时间复杂度极高,效率地下。LSH作者从以下几个方面进行了思考:

  • 既然原空间计算难度大,能否找到另外一个空间,而在这个空间中计算更加简便?
  • 在进行检索的时候是不是一定要线性的计算所有数据集的距离?

针对第一个问题,作者想到的是进行空间转换,但这个空间转换得保证在原空间相近的点,在转换后依然相近;同样,之前距离较远的点,转换后依然较远。同时考虑到用Hamming距离代替欧式距离的计算。Hamming距离的计算公式是:

H ( p 1 , p 2 ) = ∑ i = 0 n ∣ p 1 i − p 2 i ∣ H(p_1,p_2)=\sum_{i=0}^{n}|p_1^{i}-p_2^{i}| H(p1,p2)=i=0np1ip2i

针对第二个问题,作者提出了“局部敏感哈希”的概念:在高维空间相邻的数据经过哈希函数的映射投影转化到低维空间后,他们落入同一个桶的概率很大而不相邻的数据映射到同一个吊桶的概率则很小。下图就是普通哈希算法与局部敏感哈希的不同示意图:

如何提升搜索系统查询速度?_第3张图片

左图是传统Hash算法,右图是LSH。红色点和绿色点距离相近,橙色点和蓝色点距离相近。

传统Hash算法计算得到的value值完全不一样;LSH算法,红色点和绿色点的value值相等,橙色点和蓝色点的value值相近。

在检索时,局部敏感哈希就是这样将全局检索转化为对映射到同一个吊桶中的数据进行检索,从而提高了检索速度。

此外,我们应该意识到局部敏感哈希是相对的,而且我们所说的保持数据的相似度不是说保持100%的相似度,而是保持最大可能的相似度。因此这种方法的主要难点在于如何寻找适合的哈希函数。下面是几种改进的哈希最近邻算法:

  • 多表LSH:对于单表哈希,当我们的哈希函数数目K取得太大,查询样本与其对应的最近邻落入同一个桶中的可能性会变得很微弱,针对这个问题,我们可以重复构建L个哈希表,从而增加最近邻的召回率。
  • Multiprobe LSH:不止在查询样本所在的哈希桶中遍历,还会找到跟查询样本所在的哈希桶邻近的哈希桶,然后这些找到的T个哈希桶中进行遍历。其中“邻近”指的是汉明距离度量下的邻近。
  • SimHash:前面介绍的LSH算法,都需要首先将样本特征映射为特征向量的形式,使得我们需要额外存储一个映射字典。为此,Charikar提出了大名鼎鼎的SimHash算法,在满足随机超平面投影LSH特性的同时避免了额外的映射开销,非常适合于token形式的特征。

3.3 基于矢量量化的近似最近邻算法

矢量量化方法,即vector quantization,其具体定义为:将一个向量空间中的点用其中的一个有限子集来进行编码的过程。在矢量量化编码中,关键是码本的建立和码字搜索算法。比如常见的聚类算法,就是一种矢量量化方法。

而在ANN近似最近邻搜索中,向量量化方法又以乘积量化(PQ, Product Quantization)最为典型。PQ的主要思想是将特征向量进行正交分解,在分解后的低维正交子空间上进行量化,由于低维空间可以采用较小的码本进行编码,因此可以降低数据存储空间 。

如何提升搜索系统查询速度?_第4张图片

在训练阶段,针对N个训练样本,假设样本维度为128维,我们将其切分为4个子空间,则每一个子空间的维度为32维;

然后我们在每一个子空间中,对子向量采用K-Means对其进行聚类(图中示意聚成256类),这样每一个子空间都能得到一个码本。

这样训练样本的每个子段,都可以用子空间的聚类中心来近似,对应的编码即为类中心的ID。如图所示,通过这样一种编码方式,训练样本仅使用4维的一个编码得以表示,从而达到量化的目的。对于待编码的样本,将它进行相同的切分,然后在各个子空间里逐一找到距离它们最近的类中心,然后用类中心的id来表示它们,即完成了待编码样本的编码。

在查询阶段,PQ同样在计算查询样本与dataset中各个样本的距离:

如何提升搜索系统查询速度?_第5张图片

具体地,查询向量来到时,按训练样本生成码本的过程,将其同样分成相同的子段,然后在每个子空间中,计算子段到该子空间中所有聚类中心得距离,如图中所示,可以得到4*256个距离组成的距离矩阵;

在计算库中某个样本到查询向量的距离时,比如编码为(124, 56, 132, 222)这个样本到查询向量的距离时,我们分别到距离矩阵中取各个子段对应的距离即可;

所有子段对应的距离取出来后,将这些子段的距离求和相加,即得到该样本到查询样本间的非对称距离。所有距离算好后,排序后即得到我们最终想要的结果。

从上面这个过程可以很清楚地看出PQ乘积量化能够加速索引的原理:即将全样本的距离计算,转化为到子空间类中心的距离计算;另外,从上图也可以看出,对特征进行编码后,可以用一个相对比较短的编码来表示样本,自然对于内存的消耗要大大小于brute-force search的方式。

乘积量化的进阶版 -> 倒排乘积量化

倒排PQ乘积量化(IVFPQ)是PQ乘积量化的更进一步加速版。

PQ乘积量化计算距离的时候,距离虽然已经预先算好了,但是对于每个样本到查询样本的距离,还是得老老实实挨个去求和相加计算距离。

但是,实际上我们感兴趣的是那些跟查询样本相近的样本,也就是说PQ其实做了很多的无用功,如果能够通过某种手段快速将全局遍历锁定为感兴趣区域,则可以舍去不必要的全局计算以及排序。

倒排PQ乘积量化的”倒排“,正是这样一种思想的体现,在具体实施手段上,采用的是通过聚类的方式实现感兴趣区域的快速定位,在倒排PQ乘积量化中,聚类可以说应用得淋漓尽致。

倒排PQ乘积量化整个过程如下图所示:

如何提升搜索系统查询速度?_第6张图片

在PQ乘积量化之前,增加了一个粗量化过程。具体地,先对N个训练样本采用K-Means进行聚类,这里聚类的数目一般设置得不应过大,一般设置为1024差不多,这种可以以比较快的速度完成聚类过程。得到了聚类中心后,针对每一个样本 x i x_i xi,找到其距离最近的类中心 c i c_i ci后,两者相减得到样本 x i x_i xi的残差向量 ( x i − c i ) (x_i-c_i) (xici),后面剩下的过程,就是针对 ( x i − c i ) (x_i-c_i) (xici)的PQ乘积量化过程。

4 总结

最近邻检索起初作为具有查找相似性文档信息的方法被应用于文档检索系统,随后也被广泛应用于在图像检索、数据压缩、模式识别以及机器学习等领域。

在图像处理与检索的研究中,基于内容的图像检索方法(CBIR)是目前的主流,这里的“内容”指的是图像中包含的主要对象的几何形状、颜色强度、表面纹理等外在特性,以及前景与后景的对比程度等整体特征。

为了获得图像中这些特定的信息或方便后续处理,我们通常会利用多种不同的描述方式来表示图像,包括局部特征描述子(SIFT、SURF、BRIEF) ,全局特征描述子(GIST),特征频率直方图,纹理信息,显著性区域等。

而最近邻检索的引入将图像检索转化到特征向量空间,通过查找与目标特征向量距离最近的向量来获得相应图像之间的关系。这种特征向量之间的距离通常被定义为欧几里得距离(Euclidean distance),即是空间中两点之间的直线距离。

未来,我们将分享如何用近似最近邻算法提升图片检索查询效率,敬请期待。
如何提升搜索系统查询速度?_第7张图片

你可能感兴趣的:(深度学习)