结果排序和再排序对于优化搜索结果的顺序至关重要。通常,初始候选文档集是使用基于向量相似度的近似最近邻 (ANN) 搜索检索的,但这种方法的原始输出往往需要进一步优化。尽管向量相似度为语义相关性提供了强烈的信号,但它通常无法完整呈现一个结果对用户查询的真正有用或恰当之处。这就是结果排序和再排序发挥作用的地方。来自ANN搜索的初始列表,通常按余弦相似度或欧氏距离等距离指标排序,作为输入,进入一个可能更复杂的流程,旨在产生最终的、优化过的顺序。为何再排序?纯向量相似度的局限性仅仅依赖向量数据库的原始相似度分数存在局限性:细节不足: 高维向量能有效捕捉语义,但单一的相似度分数可能过度简化相关性。两个文档可能与查询向量距离相等,但在对用户重要的其他方面(例如,新近度、权威性、来源类型)存在明显差异。忽视元数据: 向量数据库允许在向量旁边存储元数据(如时间戳、类别、用户评分)。初始的ANN搜索可能会基于元数据进行预过滤,但相似度分数本身并不固有地将这些元数据值纳入排序。再排序提供了明确使用此元数据来调整顺序的机会。可能出现冗余: 向量空间中的最近邻可能代表非常相似的信息,导致列表顶部出现重复结果。再排序可以引入多样性。业务目标: 搜索结果通常需要符合特定的业务目标,例如推广某些产品、遵守内容策略或优先显示特定内容类型。纯向量相似度不考虑这些要求。混合搜索需求: 正如后面讨论的,将语义相关性与传统关键词匹配结合通常会产生更好的整体结果。再排序是这些不同信号通常结合的阶段。再排序策略再排序接受来自ANN搜索的初始候选列表(通常是前K个结果,其中K可能是50、100或更多),并应用额外的逻辑或模型来重新排序它们。1. 基于元数据的提升和过滤这通常是最简单有效的首要步骤。在基于向量相似度检索到前K个候选文档后,您可以根据相关元数据调整它们的排名。提升: 提高符合某些标准的文档的分数或排名位置。例如,提升近期发布的文档、来自经过验证的来源的文档,或目前正在销售的商品。过滤: 虽然预过滤发生在ANN搜索之前,但后过滤可以在再排序期间进行,以移除不符合严格标准的结果,即使它们在语义上接近。衰减函数: 根据时效性施加惩罚,降低较旧内容的排名,除非其语义分数非常高。实施通常涉及检索前K个候选文档的元数据,并在生成最终列表之前应用简单的分数调整。2. 交叉编码器用于增强相关性评分虽然初始搜索通常使用双编码器(为查询和文档创建独立的嵌入),但交叉编码器提供更有效的方式来评估特定查询和特定文档之间的相关性。交叉编码器同时将查询和候选文档作为输入,并输出一个代表它们相关性的单一分数。这使得模型能够直接比较查询和文档文本,捕捉到比预计算嵌入和余弦相似度可能实现的更细致的交互。digraph G { rankdir=LR; node [shape=box, style=rounded, fontname="Arial", fontsize=10, color="#495057", fillcolor="#e9ecef", style="filled,rounded"]; edge [fontname="Arial", fontsize=9, color="#495057"]; subgraph cluster_bi { label="双编码器(初始检索)"; bgcolor="#f8f9fa"; color="#adb5bd"; fontsize=10; QueryBi [label="用户查询"]; DocBi [label="文档文本"]; EncoderBi1 [label="编码器\n(例如, SBERT)", fillcolor="#a5d8ff"]; EncoderBi2 [label="编码器\n(例如, SBERT)", fillcolor="#a5d8ff"]; EmbQuery [label="查询向量"]; EmbDoc [label="文档向量"]; Similarity [label="相似度\n(余弦, 等)", shape=diamond, fillcolor="#b2f2bb"]; QueryBi -> EncoderBi1 -> EmbQuery; DocBi -> EncoderBi2 -> EmbDoc; {EmbQuery, EmbDoc} -> Similarity; } subgraph cluster_cross { label="交叉编码器(再排序)"; bgcolor="#f8f9fa"; color="#adb5bd"; fontsize=10; QueryCross [label="用户查询"]; DocCross [label="候选文档"]; InputPair [label="[CLS] 查询 [SEP] 文档 [SEP]"]; EncoderCross [label="交叉编码器\n(例如, BERT)", fillcolor="#ffec99"]; RelevanceScore [label="相关性评分\n(单一值)", shape=diamond, fillcolor="#b2f2bb"]; {QueryCross, DocCross} -> InputPair; InputPair -> EncoderCross -> RelevanceScore; } }双编码器独立处理查询和文档以实现快速相似度搜索,而交叉编码器则同时处理查询-文档对,以在再排序期间获得可能更高的相关性评分准确度。权衡在于计算成本。运行交叉编码器比计算预计算向量之间的余弦相似度明显慢得多。因此,交叉编码器通常只用于由更快的ANN搜索检索到的前K个候选文档。您可能会从ANN获取前50个结果,然后使用交叉编码器重新评分,以获得最终的前10个结果。3. 排序学习 (LTR) 模型对于更复杂的排序,您可以训练专用的机器学习模型,称为排序学习 (LTR) 模型。这些模型学习一个函数来预测给定查询的最佳文档顺序。LTR模型将多个特征作为每个查询-文档对的输入,例如:初始向量相似度分数。来自关键词匹配算法(如BM25)的分数。元数据特征(新近度、受欢迎程度、类别匹配)。来自交叉编码器的分数(如果使用)。文档质量指标(长度、可读性)。用户交互信号(点击率、停留时间),如果可用。LTR模型结合这些特征以生成用于排序的最终相关性分数。常见的LTR方法包括:逐点法: 独立预测每个文档的相关性分数。成对法: 学习预测一对文档中哪个更相关。列表法: 直接优化整个文档列表的顺序,基于NDCG(归一化折损累计增益)等指标。训练LTR模型需要标注数据(带有文档相关性判断的查询),并增加了系统的复杂性,但可以在成熟的搜索应用中明显提高排序质量。4. 结合分数实现混合搜索再排序是实施混合搜索的自然位置,结合了语义搜索(理解含义)和关键词搜索(匹配特定术语)的优势。一种常用方法是为候选文档计算语义分数(来自向量数据库)和关键词分数(例如,使用来自Elasticsearch或OpenSearch等系统的BM25)。这些分数随后在再排序阶段结合起来。加权求和: 一种简单的方法是为每个分数分配权重并求和: $$Score_{hybrid} = (w_{semantic} \times Score_{semantic}) + (w_{keyword} \times Score_{keyword})$$ 权重 $w_{semantic}$ 和 $w_{keyword}$ 可以根据实验或业务需求进行调整。倒数排名融合(RRF): RRF是一种技术,可以在不直接调整权重或归一化分数的情况下,结合来自不同系统的排名。当不同系统的分数范围差异很大时,它尤其有效。对于结果列表中出现的每个文档,其RRF分数计算如下: $$Score_{RRF} = \sum_{i} \frac{1}{k + rank_i}$$ 其中 $rank_i$ 是文档在第 $i$ 个结果列表(例如,语义列表、关键词列表)中的排名,$k$ 是一个常数(例如 $k=60$),用于降低高排名的影响。然后根据其结合的RRF分数对文档进行排序。再排序的实际考虑延迟: 每个再排序步骤都会增加搜索请求的延迟。将交叉编码器或LTR等复杂模型应用于数百个候选文档可能会明显减慢响应时间。通常做法是只对初始结果的一个子集(例如,前50-200个)进行再排序。复杂度: 实现元数据提升相对简单。使用交叉编码器需要管理另一个模型,而LTR则需要训练数据和模型生命周期管理。选择平衡性能需求和实现复杂度的策略。评估: 任何再排序策略的有效性都必须衡量。NDCG、MAP和Recall@K等指标(将在评估部分讨论)对于比较不同方法和调整参数是必不可少的。通过认真实施排序和再排序策略,可以将向量相似度搜索的原始结果转化为高度相关、多样化且有用的结果集,从而更好地满足用户预期和应用要求。