搜索领域重排序:优化搜索结果展示的关键因素
关键词:搜索重排序、信息检索、机器学习排序、相关性优化、用户体验、搜索算法、个性化推荐
摘要:本文深入探讨搜索领域中的重排序技术,这是优化搜索结果展示的核心环节。我们将从基础概念出发,分析重排序的关键因素,详细介绍主流算法原理和实现方法,并通过实际案例展示如何应用这些技术。文章还将探讨重排序面临的挑战和未来发展趋势,为搜索相关领域的从业者提供全面的技术参考。
1. 背景介绍
1.1 目的和范围
搜索重排序是信息检索系统中至关重要的环节,它决定了用户最终看到的搜索结果排序。本文旨在全面解析搜索重排序的技术原理、实现方法和优化策略,帮助读者深入理解这一关键技术。
本文将覆盖以下内容:
- 搜索重排序的基本概念和重要性
- 主流重排序算法和技术
- 重排序中的关键因素和优化方法
- 实际应用案例和代码实现
- 未来发展趋势和挑战
1.2 预期读者
本文适合以下读者:
- 搜索算法工程师和研究人员
- 信息检索系统开发者
- 数据科学家和机器学习工程师
- 对搜索技术感兴趣的产品经理和技术决策者
- 计算机科学相关专业的学生和研究人员
1.3 文档结构概述
本文采用循序渐进的结构:
- 首先介绍搜索重排序的背景和基本概念
- 然后深入分析核心算法和技术原理
- 接着通过实际案例展示具体实现
- 最后探讨应用场景和未来趋势
1.4 术语表
1.4.1 核心术语定义
- 搜索重排序(Reranking):在初步检索结果基础上,应用更复杂的算法对结果进行重新排序的过程。
- 信息检索(Information Retrieval, IR):从大规模非结构化数据中获取相关信息的过程和技术。
- 相关性(Relevance):搜索结果与用户查询意图匹配程度的度量。
- 排序学习(Learning to Rank, LTR):使用机器学习方法训练排序模型的算法集合。
- 点击率(Click-Through Rate, CTR):用户点击搜索结果的比例,常用作相关性评估指标。
1.4.2 相关概念解释
- 第一轮检索(First-stage Retrieval):使用高效但相对简单的算法快速筛选候选结果集。
- 精排(Fine Ranking):在重排序阶段应用的更复杂、计算成本更高的排序算法。
- 个性化排序(Personalized Ranking):考虑用户个人偏好和历史行为的排序方法。
- 多样性(Diversity):确保搜索结果覆盖查询的不同方面或含义。
1.4.3 缩略词列表
- IR: Information Retrieval 信息检索
- LTR: Learning to Rank 排序学习
- CTR: Click-Through Rate 点击率
- NDCG: Normalized Discounted Cumulative Gain 归一化折损累积增益
- MAP: Mean Average Precision 平均精度均值
- MRR: Mean Reciprocal Rank 平均倒数排名
- BERT: Bidirectional Encoder Representations from Transformers
2. 核心概念与联系
搜索重排序是搜索系统中的关键环节,位于初始检索和最终结果展示之间。让我们通过架构图来理解其在整个搜索系统中的位置:
2.1 搜索重排序的核心目标
搜索重排序主要解决以下几个关键问题:
- 相关性优化:确保最相关的结果排在前面
- 用户体验提升:考虑结果的可读性、时效性和权威性
- 个性化适配:根据用户画像和历史行为调整排序
- 多样性平衡:避免结果过于同质化
- 商业目标达成:在保证用户体验的前提下实现商业价值
2.2 重排序与传统排序的区别
传统排序主要基于静态的、预定义的特征(如TF-IDF、BM25等),而重排序则:
- 使用更复杂的特征和模型
- 可以动态适应用户和上下文
- 计算成本更高,但效果更好
- 通常处理较小规模的候选集(100-1000个结果)
2.3 重排序的关键因素
3. 核心算法原理 & 具体操作步骤
搜索重排序算法主要分为三类:基于传统机器学习的方法、基于深度学习的方法和混合方法。我们将重点介绍几种代表性算法。
3.1 排序学习(Learning to Rank)基础
排序学习是搜索重排序的核心技术,主要分为三种方法:
- Pointwise方法:将排序问题转化为回归或分类问题
- Pairwise方法:学习文档对的相对顺序
- Listwise方法:直接优化整个排序列表的评价指标
3.1.1 LambdaMART算法
LambdaMART是目前最成功的排序学习算法之一,它结合了MART(Multiple Additive Regression Trees)和LambdaRank的思想。
from lightgbm import LGBMRanker
# 示例:使用LightGBM实现LambdaMART
def train_lambdamart(X_train, y_train, qid_train):
# 初始化模型
model = LGBMRanker(
objective="lambdarank",
metric="ndcg",
boosting_type="gbdt",
n_estimators=100,
importance_type="gain",
verbose=10
)
# 训练模型
model.fit(
X_train,
y_train,
group=qid_train,
eval_set=[(X_valid, y_valid)],
eval_group=[qid_valid],
eval_at=5,
early_stopping_rounds=50,
verbose=True
)
return model
3.1.2 特征工程
有效的特征工程是排序学习成功的关键:
def extract_features(query, document):
# 1. 文本匹配特征
features = {}
# BM25特征
features["bm25"] = calculate_bm25(query, document)
# 词重叠特征
features["jaccard"] = jaccard_sim(query_terms, doc_terms)
features["cosine"] = cosine_sim(query_vec, doc_vec)
# 2. 文档质量特征
features["doc_len"] = len(document.text)
features["pagerank"] = document.pagerank
features["spam_score"] = document.spam_score
# 3. 用户行为特征
features["avg_ctr"] = document.avg_ctr
features["dwell_time"] = document.avg_dwell_time
# 4. 个性化特征
features["user_interest"] = calculate_interest(user, document)
return features
3.2 基于深度学习的重排序方法
3.2.1 BERT重排序模型
预训练语言模型如BERT在重排序中表现出色:
from transformers import BertTokenizer, BertModel
import torch
class BERTRanker(torch.nn.Module):
def __init__(self, pretrained_model='bert-base-uncased'):
super().__init__()
self.bert = BertModel.from_pretrained(pretrained_model)
self.classifier = torch.nn.Linear(self.bert.config.hidden_size, 1)
def forward(self, input_ids, attention_mask):
outputs = self.bert(input_ids, attention_mask=attention_mask)
pooled_output = outputs.pooler_output
logits = self.classifier(pooled_output)
return logits.squeeze(-1)
# 使用示例
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BERTRanker()
# 准备输入
query = "best Italian restaurant"
document = "Mario's Trattoria offers authentic Italian cuisine..."
inputs = tokenizer(query, document, return_tensors='pt', truncation=True, max_length=512)
# 计算相关性分数
with torch.no_grad():
score = model(**inputs).item()
3.2.2 深度个性化排序模型
结合用户嵌入和文档嵌入的深度模型:
import tensorflow as tf
from tensorflow.keras.layers import Input, Embedding, Dense, Concatenate
def build_personalized_ranker(user_vocab_size, doc_vocab_size, embedding_dim=128):
# 用户侧输入
user_input = Input(shape=(1,))
user_embedding = Embedding(user_vocab_size, embedding_dim)(user_input)
user_vec = tf.squeeze(user_embedding, axis=1)
# 文档侧输入
doc_input = Input(shape=(None,)) # 文档ID序列
doc_embedding = Embedding(doc_vocab_size, embedding_dim)(doc_input)
doc_vec = tf.reduce_mean(doc_embedding, axis=1)
# 合并特征
merged = Concatenate()([user_vec, doc_vec])
# 深度神经网络
x = Dense(256, activation='relu')(merged)
x = Dense(128, activation='relu')(x)
output = Dense(1, activation='sigmoid')(x)
model = tf.keras.Model(inputs=[user_input, doc_input], outputs=output)
model.compile(optimizer='adam', loss='binary_crossentropy')
return model
3.3 重排序操作流程
典型的搜索重排序流程如下:
4. 数学模型和公式 & 详细讲解 & 举例说明
4.1 排序学习的数学基础
4.1.1 排序问题的形式化定义
给定查询 q q q 和文档集 D = { d 1 , d 2 , . . . , d n } D = \{d_1, d_2, ..., d_n\} D={d1,d2,...,dn},目标是找到一个排序函数 f ( q , d ) f(q, d) f(q,d),使得对于相关文档 d + d^+ d+ 和不相关文档 d − d^- d−:
f ( q , d + ) > f ( q , d − ) f(q, d^+) > f(q, d^-) f(q,d+)>f(q,d−)
4.1.2 损失函数
- Pointwise损失(回归形式):
L ( f ; q , d , y ) = ( f ( q , d ) − y ) 2 \mathcal{L}(f; q, d, y) = (f(q, d) - y)^2 L(f;q,d,y)=(f(q,d)−y)2
其中 y y y 是文档 d d d 对于查询 q q q 的相关性标签。
- Pairwise损失(如RankNet):
L ( f ; q , d i , d j ) = log ( 1 + exp ( − ( f ( q , d i ) − f ( q , d j ) ) ⋅ s i j ) ) \mathcal{L}(f; q, d_i, d_j) = \log(1 + \exp(-(f(q, d_i) - f(q, d_j)) \cdot s_{ij})) L(f;q,di,dj)=log(1+exp(−(f(q,di)−f(q,dj))⋅sij))
其中 s i j = 1 s_{ij} = 1 sij=1 如果 d i d_i di 应该排在 d j d_j dj 前面,否则 s i j = − 1 s_{ij} = -1 sij=−1。
- Listwise损失(如LambdaLoss):
L = − ∑ π ∈ Ω P ( π ∣ s ) ⋅ NDCG ( π ) \mathcal{L} = -\sum_{\pi \in \Omega} P(\pi|s) \cdot \text{NDCG}(\pi) L=−π∈Ω∑P(π∣s)⋅NDCG(π)
其中 π \pi π 是排列, P ( π ∣ s ) P(\pi|s) P(π∣s) 是基于分数的排列概率。
4.2 评价指标
4.2.1 NDCG (Normalized Discounted Cumulative Gain)
DCG @ k = ∑ i = 1 k 2 r e l i − 1 log 2 ( i + 1 ) \text{DCG}@k = \sum_{i=1}^k \frac{2^{rel_i} - 1}{\log_2(i+1)} DCG@k=i=1∑klog2(i+1)2reli−1
NDCG @ k = DCG @ k IDCG @ k \text{NDCG}@k = \frac{\text{DCG}@k}{\text{IDCG}@k} NDCG@k=IDCG@kDCG@k
其中 r e l i rel_i reli 是第 i i i 个结果的相关性程度,IDCG 是理想 DCG。
4.2.2 MAP (Mean Average Precision)
对于单个查询:
AP = ∑ k = 1 n P ( k ) ⋅ r e l ( k ) number of relevant documents \text{AP} = \frac{\sum_{k=1}^n P(k) \cdot rel(k)}{\text{number of relevant documents}} AP=number of relevant documents∑k=1nP(k)⋅rel(k)
其中 P ( k ) P(k) P(k) 是前 k k k 个结果的精度, r e l ( k ) rel(k) rel(k) 表示第 k k k 个结果是否相关。
MAP 是所有查询 AP 的平均值。
4.3 概率排序原则(Probability Ranking Principle, PRP)
PRP 是信息检索的基础理论,它指出:
“如果一个检索系统的响应按照文档相关概率的降序排列,那么系统的整体效果是最优的。”
数学表达:
p ( R ∣ d i , q ) p ( R ˉ ∣ d i , q ) > p ( R ∣ d j , q ) p ( R ˉ ∣ d j , q ) ⇒ d i 应该排在 d j 前面 \frac{p(R|d_i, q)}{p(\bar{R}|d_i, q)} > \frac{p(R|d_j, q)}{p(\bar{R}|d_j, q)} \Rightarrow d_i \text{ 应该排在 } d_j \text{ 前面} p(Rˉ∣di,q)p(R∣di,q)>p(Rˉ∣dj,q)p(R∣dj,q)⇒di 应该排在 dj 前面
其中 R R R 表示相关, R ˉ \bar{R} Rˉ 表示不相关。
5. 项目实战:代码实际案例和详细解释说明
5.1 开发环境搭建
5.1.1 基础环境
# 创建Python虚拟环境
python -m venv reranking_env
source reranking_env/bin/activate # Linux/Mac
reranking_env\Scripts\activate # Windows
# 安装基础包
pip install numpy pandas scikit-learn lightgbm torch transformers
5.1.2 数据集准备
我们使用MS MARCO Passage Ranking数据集作为示例:
import pandas as pd
from sklearn.model_selection import train_test_split
# 加载数据
data = pd.read_csv('msmarco/passage_ranking.csv')
queries = pd.read_csv('msmarco/queries.csv')
passages = pd.read_csv('msmarco/passages.csv')
# 合并数据
merged = data.merge(queries, on='query_id').merge(passages, on='passage_id')
# 划分训练集和测试集
train, test = train_test_split(merged, test_size=0.2, random_state=42)
5.2 源代码详细实现和代码解读
5.2.1 基于LightGBM的排序模型
import lightgbm as lgb
import numpy as np
def prepare_lgb_data(df):
# 假设我们已经提取了特征
features = ['bm25', 'jaccard', 'cosine', 'doc_len', 'pagerank', 'avg_ctr']
X = df[features].values
y = df['relevance'].values
qid = df['query_id'].values
return X, y, qid
# 准备数据
X_train, y_train, qid_train = prepare_lgb_data(train)
X_test, y_test, qid_test = prepare_lgb_data(test)
# 创建数据集
train_data = lgb.Dataset(X_train, label=y_train, group=np.bincount(qid_train))
valid_data = lgb.Dataset(X_test, label=y_test, group=np.bincount(qid_test))
# 设置参数
params = {
'objective': 'lambdarank',
'metric': 'ndcg',
'ndcg_eval_at': [5, 10],
'learning_rate': 0.05,
'num_leaves': 31,
'min_data_in_leaf': 20,
'lambda_l1': 0.1,
'lambda_l2': 0.1,
'max_depth': -1,
'verbosity': 1
}
# 训练模型
model = lgb.train(
params,
train_data,
num_boost_round=1000,
valid_sets=[valid_data],
early_stopping_rounds=50,
verbose_eval=10
)
# 保存模型
model.save_model('lambdamart_model.txt')
5.2.2 基于BERT的神经排序模型
import torch
from transformers import BertTokenizer, BertForSequenceClassification
from torch.utils.data import Dataset, DataLoader
class RankingDataset(Dataset):
def __init__(self, queries, passages, labels, tokenizer, max_len=512):
self.queries = queries
self.passages = passages
self.labels = labels
self.tokenizer = tokenizer
self.max_len = max_len
def __len__(self):
return len(self.queries)
def __getitem__(self, idx):
query = str(self.queries[idx])
passage = str(self.passages[idx])
label = self.labels[idx]
encoding = self.tokenizer(
query,
passage,
max_length=self.max_len,
padding='max_length',
truncation=True,
return_tensors='pt'
)
return {
'input_ids': encoding['input_ids'].flatten(),
'attention_mask': encoding['attention_mask'].flatten(),
'labels': torch.tensor(label, dtype=torch.float)
}
# 初始化模型和tokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=1)
# 准备数据
train_dataset = RankingDataset(
train['query_text'].values,
train['passage_text'].values,
train['relevance'].values,
tokenizer
)
train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
# 训练设置
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=2e-5)
loss_fn = torch.nn.MSELoss()
# 训练循环
for epoch in range(3):
model.train()
total_loss = 0
for batch in train_loader:
input_ids = batch['input_ids'].to(device)
attention_mask = batch['attention_mask'].to(device)
labels = batch['labels'].to(device)
optimizer.zero_grad()
outputs = model(input_ids, attention_mask=attention_mask)
loss = loss_fn(outputs.logits.squeeze(), labels)
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f'Epoch {epoch+1}, Loss: {total_loss/len(train_loader)}')
# 保存模型
torch.save(model.state_dict(), 'bert_ranker.pth')
5.3 代码解读与分析
5.3.1 LightGBM模型分析
-
数据准备:
- 我们提取了文本匹配特征(BM25、Jaccard、Cosine)和文档质量特征(长度、PageRank等)
- 查询ID用于分组,确保同一查询的文档被一起评估
-
模型训练:
- 使用LambdaRank目标函数,直接优化NDCG指标
- 早停机制防止过拟合
- 正则化参数(lambda_l1, lambda_l2)控制模型复杂度
-
优势:
- 训练速度快,适合大规模数据
- 特征重要性可解释
- 对数值型特征处理效果好
5.3.2 BERT模型分析
-
数据处理:
- 将查询和文档拼接作为BERT输入
- 使用动态padding和truncation处理不同长度文本
- 将相关性分数作为回归目标
-
模型架构:
- 基于预训练BERT模型,添加回归头
- 使用MSE损失函数优化相关性预测
-
优势:
- 捕捉深层次语义关系
- 不需要复杂的特征工程
- 对短文本匹配效果尤其好
-
挑战:
- 计算资源需求高
- 训练时间较长
- 可解释性较差
6. 实际应用场景
6.1 电商搜索
电商平台需要综合考虑多种因素进行重排序:
- 商品相关性:标题、描述与搜索词匹配度
- 商品质量:评价分数、退货率、图片质量
- 商业因素:利润率、促销活动、广告
- 个性化:用户历史行为、偏好、购买力
graph TD
A[用户搜索"智能手机"] --> B[初始召回]
B --> C[重排序因素]
C --> C1[相关性: 标题匹配]
C --> C2[质量: 评价4.8星]
C --> C3[商业: 促销中]
C --> C4[个性化: 用户常看高端机]
C --> D[最终排序]
6.2 企业文档搜索
企业内文档搜索的重排序考虑:
- 内容相关性:文档内容与查询的匹配度
- 权威性:官方文档优先
- 时效性:新版本文档优先
- 访问频率:常用文档排名靠前
- 部门相关性:同部门文档优先
6.3 新闻搜索
新闻搜索的特殊重排序需求:
- 时效性:新鲜度权重高
- 权威性:主流媒体优先
- 多样性:避免重复报道
- 地域性:本地新闻优先
- 用户兴趣:基于阅读历史的个性化
6.4 视频平台搜索
视频搜索的重排序特点:
- 内容匹配:标题、字幕、标签匹配
- 视频质量:分辨率、制作质量
- 互动指标:观看量、点赞率、完播率
- 创作者权重:知名创作者优先
- 个性化推荐:基于观看历史
7. 工具和资源推荐
7.1 学习资源推荐
7.1.1 书籍推荐
- 《Search Engines: Information Retrieval in Practice》 - W. Bruce Croft
- 《Learning to Rank for Information Retrieval》 - Tie-Yan Liu
- 《Neural Information Retrieval》 - Bhaskar Mitra, Nick Craswell
- 《Deep Learning for Search》 - Tommaso Teofili
7.1.2 在线课程
- 斯坦福大学CS276: Information Retrieval and Web Search
- Coursera: Text Retrieval and Search Engines (UIUC)
- Udemy: Learning to Rank with Apache Solr and Elasticsearch
- DeepLearning.AI: Natural Language Processing with Attention Models
7.1.3 技术博客和网站
- Google Research Blog - 搜索技术最新进展
- Microsoft Research - Information Retrieval
- Elasticsearch官方博客
- Towards Data Science - 搜索和推荐系统专栏
7.2 开发工具框架推荐
7.2.1 IDE和编辑器
- Jupyter Notebook - 快速原型开发
- PyCharm Professional - Python开发
- VS Code - 轻量级代码编辑
- Colab - 云端GPU实验环境
7.2.2 调试和性能分析工具
- TensorBoard - 深度学习模型监控
- Weights & Biases - 实验跟踪
- PyTorch Profiler - 性能分析
- cProfile - Python代码性能分析
7.2.3 相关框架和库
-
排序学习:
- LightGBM (LambdaMART实现)
- XGBoost
- RankLib (Java实现)
-
深度学习:
- Transformers (Hugging Face)
- PyTorch
- TensorFlow Ranking
-
全文搜索:
- Elasticsearch
- Apache Solr
- Vespa
7.3 相关论文著作推荐
7.3.1 经典论文
- “Learning to Rank Using Gradient Descent” (RankNet) - Burges et al.
- “From RankNet to LambdaRank to LambdaMART” - Burges
- “The Probabilistic Relevance Framework: BM25 and Beyond” - Robertson, Zaragoza
- “BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding” - Devlin et al.
7.3.2 最新研究成果
- “Pre-trained Language Model for Ranking: BERT is an Effective Ranking Model” - Nogueira et al.
- “Document Ranking with a Pretrained Sequence-to-Sequence Model” - Sachan et al.
- “Multi-stage Document Ranking with BERT” - Pradeep et al.
- “Cross-Architecture Knowledge Distillation for Search Ranking” - Hofstätter et al.
7.3.3 应用案例分析
- “Amazon Search: The Joy of Ranking Products” - Amazon Science
- “Learning to Rank at Airbnb” - Airbnb Engineering
- “Google’s Neural Machine Translation System” - Wu et al. (相关技术)
- “Microsoft Bing: The Deep Learning Transformation” - Microsoft Research
8. 总结:未来发展趋势与挑战
8.1 未来发展趋势
-
大规模预训练模型的应用:
- 更大规模的预训练语言模型将进一步提升重排序效果
- 多模态模型处理文本、图像、视频混合搜索
-
个性化与上下文感知:
- 更精细的用户建模
- 实时上下文捕捉(位置、时间、设备等)
-
端到端学习:
- 从检索到排序的端到端联合训练
- 减少人工特征工程依赖
-
可解释性与可控性:
- 开发可解释的深度学习模型
- 提供更灵活的业务规则接口
-
跨领域迁移学习:
- 在一个领域训练的模型迁移到其他领域
- 小样本学习技术
8.2 主要挑战
-
计算成本:
- 复杂模型的高计算成本
- 实时性要求与模型复杂度的平衡
-
数据偏差:
- 点击数据中的位置偏差
- 长尾查询处理
-
评价指标:
- 在线指标与离线指标的不一致
- 用户体验的全面评估
-
隐私保护:
- 个性化与用户隐私的平衡
- 联邦学习等隐私保护技术的应用
-
多目标优化:
- 相关性、多样性、商业目标的多目标平衡
- 动态权重的自适应调整
9. 附录:常见问题与解答
Q1: 重排序和第一轮检索有什么区别?
A1: 第一轮检索关注快速从海量数据中筛选出可能相关的候选集(通常使用倒排索引等高效算法),而重排序则是在较小候选集上(通常几百到几千个结果)应用更复杂的算法进行精细排序。第一轮检索强调效率,重排序强调效果。
Q2: 如何选择Pointwise、Pairwise和Listwise方法?
A2: 选择取决于数据和需求:
- Pointwise适合有明确相关性标签的数据
- Pairwise适合相对偏好数据(如点击日志)
- Listwise直接优化排序指标但实现复杂
实践中,LambdaMART(Listwise)通常效果最好但计算成本高,Pairwise方法如RankNet是良好折中。
Q3: 深度学习模型是否总是优于传统方法?
A3: 不一定。虽然深度学习在语义匹配方面表现优异,但传统方法(如LambdaMART)在以下情况可能更好:
- 训练数据较少
- 需要模型可解释性
- 计算资源有限
- 查询和文档有丰富的结构化特征
Q4: 如何处理冷启动问题?
A4: 冷启动问题可以通过以下方法缓解:
- 使用内容基础特征(如BM25)作为初始排序
- 利用迁移学习从其他领域迁移知识
- 基于用户注册信息构建初始画像
- 设计探索-利用机制(如bandit算法)
Q5: 如何平衡相关性和多样性?
A5: 常用方法包括:
- MMR (Maximal Marginal Relevance)算法
- 在损失函数中加入多样性惩罚项
- 后处理重排(如多样性重排)
- 多目标优化框架
10. 扩展阅读 & 参考资料
-
Liu, T. Y. (2009). Learning to rank for information retrieval. Foundations and Trends in Information Retrieval, 3(3), 225-331.
-
Mitra, B., & Craswell, N. (2018). An introduction to neural information retrieval. Foundations and Trends in Information Retrieval, 13(1), 1-126.
-
Onal, K. D., et al. (2018). Neural information retrieval: At the end of the early years. Information Retrieval Journal, 21(2-3), 111-182.
-
Nogueira, R., & Cho, K. (2019). Passage re-ranking with BERT. arXiv preprint arXiv:1901.04085.
-
Google Research publications on search and information retrieval: https://research.google/
-
Microsoft Bing Search technologies: https://www.microsoft.com/en-us/research/group/bing-advanced-technology-group/
-
Elasticsearch Learning to Rank plugin: https://github.com/o19s/elasticsearch-learning-to-rank
-
Hugging Face Transformers documentation: https://huggingface.co/docs/transformers/index