当前位置: 首页 > news >正文

用 Eland 在 Elasticsearch Serverless 部署 Learning-to-Rank 排序模型

1 LTR 流程总览

阶段关键产物工具
离线Judgment List → 特征 → 训练集 → model.jsonPandas / scikit-learn / XGBoost
导入MLModel.import_ltr_model()Eland
在线retriever 召回 + text_similarity_reranker 重排Search API

2 准备数据

2.1 Judgment List

qid  doc_id   relevance
1001  a12      4
1001  b77      3
1001  c02      0
...
  • 来源:点击/下单日志 + 人工标注
  • 平衡性:不同查询类型、正负样本比例要均衡

2.2 在 Python 里声明特征抽取器

from eland.ml.ltr import QueryFeatureExtractorfeature_extractors = [# title BM25 分数QueryFeatureExtractor(feature_name="title_bm25",query={"match": {"title": "{{query}}"}}),# title 命中词个数QueryFeatureExtractor(feature_name="title_matched_terms",query={"script_score": {"query": {"match": {"title": "{{query}}"}},"script": {"source": "return _termStats.matchedTermsCount();"}}},),# 文档属性:popularityQueryFeatureExtractor(feature_name="popularity",query={"script_score": {"query": {"exists": {"field":"popularity"}},"script": {"source": "return doc['popularity'].value;"}}},),
]

打包成配置对象:

from eland.ml.ltr import LTRModelConfig
ltr_config = LTRModelConfig(feature_extractors)

2.3 批量抽特征

from eland import Elasticsearch
from eland.ml.ltr import FeatureLoggeres = Elasticsearch("https://<endpoint>", api_key="...")
logger = FeatureLogger(es, index="products", ltr_config=ltr_config)# 针对单个 query 抽取部分文档的特征
df = logger.extract_features(query_params={"query": "wireless headset"},doc_ids=["doc-1","doc-9","doc-42"])

最佳实践:在 影子集群 做 feature logging,防止大批量请求影响线上搜索。

3 训练 XGBRanker

import xgboost as xgb
# 读取 DF => numpy
X = df[["title_bm25", "title_matched_terms", "popularity"]].values
y = df["relevance"].values
group = df.groupby("qid").size().to_list()  # 每个 query 的样本数dtrain = xgb.DMatrix(X, label=y)
dtrain.set_group(group)params = {"objective": "rank:ndcg","eval_metric": "ndcg@10","eta": 0.1,"max_depth": 6,"n_estimators": 200,
}
ranker = xgb.train(params, dtrain)
ranker.save_model("ltr_model.json")

4 Eland 导入模型

from eland.ml import MLModelMLModel.import_ltr_model(es_client=es,model=ranker,model_id="ltr-wireless-v1",ltr_model_config=ltr_config,es_if_exists="replace"          # 已存在则覆盖
)

导入过程做了两件事:

  1. ltr_config(特征模板)与 XGBoost 模型打包。
  2. 调用 Create Trained Model API 把模型存入 .ml-inference-* 索引,并自动创建推理端点。

上线后可在 DevTools 验证:

GET _inference/_deployments/ltr-wireless-v1/_stats

5 在线检索 + LTR 重排

POST /products/_search
{"size": 10,"retriever": {                      # Stage-1 召回"rrf": {"retrievers": [{ "standard": {               # BM25"query": { "match": { "title": "wireless headset" } },"k": 200 }},{ "standard": {               # 语义稀疏向量"query": { "semantic": {"field": "semantic_text","query": "wireless headset" } },"k": 200 }}]}},"reranker": {                       # Stage-2 LTR"text_similarity_reranker": {"model_id": "ltr-wireless-v1","field": "{{{features}}}",      # Eland 自动注入多特征模板"max_passages": 10}}
}
  • k=200:先召回 200 条,提供给重排;
  • 模板 {{{features}}}:Eland 生成的隐藏字段,服务端展开为多段 DSL,提取特征并送给模型。

6 模型管理与灰度

操作API or 工具
查看已部署版本GET _inference/_deployments/*
升级 v2 并灰度MLModel.import_ltr_model(..., model_id="ltr-wireless-v2")
给部分流量切换到 v2 端点
回滚DELETE _inference/_deployments/ltr-wireless-v2

可以通过 Search Template 参数化 model_id,由 AB proxy 控制分流,完成无损灰度。

7 常见坑与调优

问题解决方案
线上返回 "Failed to load model"端点未 startPOST /_inference/_deployments/<id>/_start
特征数量对不上保证离线 ltr_config 与线上一致;import_ltr_model 会自动校验
QPS 降低适当降低 k;或在 Elastic Cloud 升级 ML Node 规格
模型大小 > 20 MB调大 num_parallel_tree / max_depth 会指数增加模型体积,线上推理内存需同步加大

结语

  • Eland = 特征模板 + 数据提取 + 导入模型 的官方胶水层,让 LTR 在 Elastic 全家桶里“无缝衔接”。
  • 借助 XGBoost LambdaMART,精排 100 条只需数毫秒,能轻松嵌入任何检索流程作为二阶段 Re-rank。
  • 当业务迭代、特征新增时,重复 3 行 Python 即可快速上线新模型,保持搜索体验常新。

赶紧把你的点击日志喂给 Notebook,五分钟后就能在结果页看到“AI 调味”的 Top 10!

http://www.dtcms.com/a/313116.html

相关文章:

  • 数据,正在成为AI大模型最后的护城河
  • leetcode 2106. 摘水果 困难
  • Rust 同步方式访问 REST API 的完整指南
  • 道格拉斯-普克算法 - 把一堆复杂的线条变得简单,同时尽量保持原来的样子
  • python---赋值、浅拷贝、深拷贝
  • 【C 学习】03-你的第一个C程序
  • 上位机知识篇---脚本文件
  • Linux环境下使用Docker搭建多服务环境
  • Corrosion2靶场
  • xxljob总结
  • Obsidian结合CI/CD实现自动发布
  • 1、docker容器命令 | 生命周期管理
  • NX969NX972美光固态闪存NX975NX977
  • python 12 install jupyter时zmq.h或libzmq报错处理
  • MVCC:数据库事务隔离的 “时空魔法”
  • nvm切换本地nodejs环境
  • node中shapefile字符集判断
  • Sklearn 机器学习 数据聚类 KMeans实现聚类
  • wav音频格式中,ACM波形、A/mu-Law Wave、Windows PCM、Microsoft ADPCM的区别
  • 《使用Qt Quick从零构建AI螺丝瑕疵检测系统》——9. 接入真实硬件:驱动USB摄像头
  • LeetCode 分类刷题:2824. 统计和小于目标的下标对数目
  • Go语言--语法基础7--函数定义与调用--自定义函数
  • Go语言实战案例:TCP服务器与客户端通信
  • HoloLens+vuforia打包后遇到的问题
  • 图像、视频、音频多模态大模型中长上下文token压缩方法综述
  • Connection refused: no further information: localhost/127.0.0.1:2375
  • Git的安装和配置
  • JavaWeb开发
  • XSS-DOM 2
  • [硬件电路-150]:数字电路 - 数字电路与模拟电路的异同