基于火山引擎云搜索服务的排序学习实战

排序学习(LTR: Learning to Rank)作为一种机器学习技术,其应用场景非常广泛。例如,在电商推荐 领域,可以帮助电商平台对用户的购买历史、搜索记录、浏览行为等数据进行分析和建模;可以帮助搜索引擎 对用户的搜索关键词进行分析建模;可以为广告主提供最精准和最有效的广告投放 方案;在金融风控领域,排序学习可以帮助金融机构分析客户的信用评级和欺诈风险,提高风控能力和业务效率。

原理介绍

一般的搜索引擎服务,其搜索过程包含了两个阶段,即召回+排序。 如火山引擎云搜索服务,通过用户输入的文本段作为关键词,使用 BM25 打分算法,遍历数据库并挑选出分数最高的文档排好序后再返回展示给用户。由于 BM25 算法模型考虑的因素主要是文本的词频、逆文档频率等。因此搜索结果的排序仅仅取决于它所检索的文本的相关性,这在大部分场景下都是够用的,但是有些应用场景用户则想要实现相关性更优的个性化推荐效果。

为了达到这个目的,需要在已有召回+排序 的基础上,额外引入重排阶段。相比较于前两个阶段,第三阶段考虑的因素则偏向于用户行为,通过用户点击、收藏、购买等反馈特征,引入机器学习算法,针对特征与反馈自动学习并调整参数,预估用户对于返回结果的偏好,最终实现个性化搜推结合的效果。整个训练排序过程,也被称为排序学习(LTR: Learning to Rank)。

以火山引擎云搜索服务为例,为了实现完整的三阶段流程,存在内置和外挂两种方式:

  • 内置方式 ,是将重排阶段以插件的形式安装到火山引擎云搜索服务中,用户输入查询,得到搜推结果。整个流程对业务保持透明,业务只需与搜索引擎完成交互。相关实现为:elasticsearch-learning-to-rank插件等。
  • 外挂方式 ,是指在业务侧,先通过火山引擎云搜索服务查询得到召回+排序前两阶段结果,然后将中间结果作为输入,再与 LTR 模型工具进行交互,最后返回搜推结果。整个流程需要业务侧自行处理中间结果,完成与搜索服务和 LTR 模型工具的交互,灵活性更高,对应的开源工具有:metarank等。

本文的后续内容将利用火山引擎云搜索服务结合 Metarank 项目来演示如何实现用户的个性化搜推实践方案。


环境准备

  1. 登录火山引擎云搜索服务,创建实例集群,集群版本选择 7.10。
  1. Python Client 关键依赖准备
ini 复制代码
pip install -U elasticsearch7==7.10.1 # ES数据库相关
pip install -U pandas #分析splash的csv

数据集准备

选择 Metarank 文档中推荐的RankLens数据集,其中原始的数据集在dataset路径下,将其解压后即可得到约 2500 条数据,每条数据包含电影海报、演员、评分等信息。

json 复制代码
{
    ...
    "description": "When a rare phenomenon gives police officer John Sullivan the chance to speak to his father, 30 years in the past, he takes the opportunity to prevent his dad's tragic death.  After his actions inadvertently give rise to a series of brutal murders he and his father must find a way to fix the consequences of altering time.",
    "director": {
        "gender": 2,
        "id": 17812,
        "name": "Gregory Hoblit",
        "popularity": 1.62
    },
    "id": 3510,
    "overview": "When a rare phenomenon gives police officer John Sullivan the chance to speak to his father, 30 years in the past, he takes the opportunity to prevent his dad's tragic death.  After his actions inadvertently give rise to a series of brutal murders he and his father must find a way to fix the consequences of altering time.",
    "poster": "https://image.tmdb.org/t/p/original/eu3Hrjj271dnBdNAF0HqfmwWASt.jpg",
    "releaseDate": "2000-04-28",
    "tags": [
        "time travel",
        "father-son relationship",
        "alternate reality",
        "father son relationship",
        "supernatural"
    ],
    "title": "Frequency",
    "tmdbId": 10559,
    "tmdbPopularity": 10.95,
    "tmdbVoteAverage": 7.2,
    "tmdbVoteCount": 1254,
    "topActors": [
        {
            "gender": 1,
            "id": 31167,
            "name": "Elizabeth Mitchell",
            "popularity": 8.646
        },
        ...
    ]
}

搜推结合实践操作

连接

  • 火山引擎云搜索服务

登录火山引擎云搜索服务,选择刚刚创建好的实例,选择复制公网访问地址(由于Metarank运行在本地机器上,为了连接云搜索服务,需要打开公网访问,如果Metarank运行在用户VPC里则不需要):

ini 复制代码
# 连接火山引擎云搜索服务实例
cloudSearch = CloudSearch("https://{user}:{password}@{ES_URL}", 
                    verify_certs=False, 
                    ssl_show_warn=False)
  • Metarank 服务

本地启动 Metarank 服务,数据集参数(--data)指定转化后的数据集,包括数据的元信息及用户点击率信息;配置文件参数(--config)指定模型配置等,参数及文件下载可参考 docs.metarank.ai/introductio...

arduino 复制代码
java -jar metarank-0.7.1.jar standalone --data events.jsonl.gz  --config events-config.yml

写入

将 RankLens 数据集写入火山引擎云搜索服务

ini 复制代码
import json

path = '${下载的数据集所在路径}'
with open(path, 'r') as f:
  bulk_docs = []
  n = 0
  for line in f.readlines():
    doc = json.loads(line.rstrip())
    if 'title' in doc:
        n += 1
        bulk_docs.append({"index": {"_id": doc['id']}})
        bulk_docs.append(doc)
        
        ## 每次批量写入50条数据
        if n % 50 == 0:        
          resp = cloudSearch.bulk(bulk_docs, index='events2')
          bulk_docs = []  

查询

  1. 文本查询 + Metarank 重排
ini 复制代码
@app.route('/search', methods=['GET'])
def search():
    return innerSearch()

def innerSearch():
    # 获取参数
    query = request.args.get('query')
    method = request.args.get('retrieval')
    n = int(request.args.get('size'))
    rank = request.args.get('rank')
    start = time.time()
    
    # 文本查询
    docs = retrieve(method, query, n) 
    done1 = time.time()
    if len(docs['hits']['hits']) == 0:
        return render_template('search.html', help=False, query=query, method=method, rank=rank, size=n, took={"search": 1000*(done1-start), "rank": 0, "total": 1000*(done1-start)})

    # Metarank重排
    sorted = rerank(rank, query, docs['hits']['hits'])
    done2 = time.time()
    return render_template('search.html', help=False, query=query, docs=sorted, method=method, rank=rank, size=n, took={"search": 1000*(done1-start), "rank": 1000*(done2-done1), "total": 1000*(done2-start)})
  1. 点击反馈

将用户的偏好反馈写入 metarank

ini 复制代码
@app.route('/feedback', methods=['GET'])
def feedback():
    item = request.args.get('item')
    
    # 点击反馈
    interaction = metarank.feedbackInteraction(item)

    return innerSearch()

查询展示

相关推荐
龙亘川7 分钟前
科技决策分析报表平台:科技服务・项目・成果转化・政策四维报表全链路业务建模
大数据·科技·ai·信息可视化·智慧城市
分布式存储与RustFS8 分钟前
RustFS 多协议接入全景:S3 之外,Swift/Keystone 与 SFTP/FTPS 怎么选
云原生·开源·对象存储·分布式存储·s3·rustfs·性能基准
四季豆332 小时前
工业大数据不只是“大”,更是制造业突围的“导航仪”
大数据
newsxun2 小时前
光智融合,空间新生|Jupiter SR 亮相光博会CIOE 2026
大数据·人工智能
大树883 小时前
液冷系统的真正瓶颈,藏在那层不到1毫米的材料里
大数据·运维·服务器·人工智能·ai
Vicky_time3 小时前
2026美国海外仓TOP5技术评测:FBA中转海外仓系统对接与操作方案
大数据·系统架构
北京晶数信息科技3 小时前
加油机数据采集设备加油机数据采集器加油机智能采集器液位仪数据采集设备原厂成品油流通数智化综合监管平台技术原理与落地应用解决方案
大数据·人工智能·物联网·需求分析
凌风的跨境分享3 小时前
Temu店群运维提效:定时策略自动化任务全场景实操指南
大数据·运维·前端·人工智能·架构·自动化
Elastic 中国社区官方博客4 小时前
Elasticsearch 向量数据库:几分钟内完成部署,以经济高效的方式扩展至数千亿规模
大数据·运维·数据库·elasticsearch·搜索引擎·ai·全文检索
A hao4 小时前
LED视频处理器中帧率与刷新率的区别
大数据·图像处理·人工智能·音视频