在推荐和搜索场景下,召回recall是一个关键的步骤,这个步骤通常需要在海量的目标中,召回部分与用户特征相近的item,所以有一个快速,并且准去的算法是非常有必要的,HNSW(Hierarchical Navigable Small World)就是其中一种方法,当然HNSW也不止用于此。
对于召回的场景下,每个需要进行召回的item已经用户的特征都是多维的,在多个特征维度的空间中,找到与用户特征最相近的topK。所以召回的问题其实可以抽象化为在多维空间中,找到与某个点邻近的topK个点。
HNSW(Hierarchical Navigable Small World)
翻译成中文为分级导航小世界,是基于图数据结构的搜索算法,将复杂问题转化成ANN
,来解决此类问题。
ANN(Artificial Neural Network)人工神经网络。
NSW(Navigable Small World)
在HNSW
之前提出的NSW
是HNSW的基础,这个算法解决了邻近点搜索的基本问题。
比如我们现在将问题就从多维简化为二维,并且推荐item和用户都的当成一个点的话,那么我们的问题就可以简化为,二维平面中存在海量的点,我们收集到一个用户的特征,就相当于二维空间中给用户找到了他的坐标,那么我们现在要在这些海量的点中找出离用户坐标最近的topK,这就是问召回也就是NSW和HNSW要做的。
构建索引结构
首先,在插入用户特征点之前,我们要做的,就是将所有点与其向邻近的“友点”进行连接。这可以看做是所有item的索引,我们的召回匹配,需要在这个索引上进行。这个索引被称为是Delaunay graph
,这种结构的特征就是组成的基本模块都是三角形。
在NSW
中,实现Delaunay graph
的索引的构建:
- 1.插入一个新点时,会先随机挑选一个节点,然后计算这个节点A和他“友点”到这个新节点的距离,并记录
- 2.如果距离最短的节点是节点A,那么就可以根据
m
的数量(可以认为规定的topK)去连接相应的节点,如果友点数量不够,那么先连接节点A,然后将第二近的节点作为下一个节点,去计算距离,重复上面的过程,直到找到m的节点与新节点相连
高速公路
这样的连接其实是有一点小问题的,比如我们两个相距很远的节点A和E,因为插入的比较早,所以就算不是最近的,两点之间也有连线。
我们后面插入了新的节点在AE中间,P和Q,我们可以连接成A-P-C-E,如果没有A-E的话,我们随机点挑选在E,但是我们需要查找的点在A附近的话,我们需要从E-C-P-A要经过三次友点才能到达A,但是因为有AE的连线,我们可以直接从E到A,快速的找到A点附近,接近结果。
所以这个是构建必然会出现的一个情况,也是后续的一个缩短时间的一个工具。
构建索引的优化
- 最简单的就是每次遍历的时候,计算了两点间的距离,可以将两点的距离存起来,这样再遍历到这两点的时候就不用重复计算了。
- 可以并行的计算多个“友点”对目标点的距离,多线程优化
HNSW(Hierarchical Navigable Small World)
HNSW比NSW多了一个Hierarchical,也就是分级,这个分级我们看HNSW和跳表的结构就知道是个什么分级了
这个是HNSW的结构:
这个是跳表 的结构
其实HNSW的优化就是分多层,每层都是下一层的索引层。而越往上层的节点数越少,所以接近目标节点的速度就越快。
所以在召回的时候,我们将一个用户特征的新点加入HNSW的随机一层Li,然后还是从最高层开始搜索每一层与新点的邻近点,然后逐层下降,直到Li层,然后分别连接各层的邻近点。