学习排序

edit

此功能在8.12.0版本中引入,仅适用于某些订阅级别。 更多信息,请参阅https://www.elastic.co/subscriptions

学习排序 (LTR) 使用经过训练的机器学习 (ML) 模型来构建搜索引擎的排序函数。通常,该模型作为第二阶段的重新排序器,用于提高由更简单的第一阶段检索算法返回的搜索结果的相关性。LTR 函数接收一组文档和搜索上下文,并输出排序后的文档:

Learning To Rank overview
Figure 8. Learning To Rank overview

搜索上下文

edit

除了排序的文档列表外,LTR 函数还需要一个搜索上下文。通常,这个搜索上下文至少包括用户提供的搜索词(如上例中的 text_query)。搜索上下文还可以提供在排名模式中使用的附加信息。这可能是关于进行搜索的用户的信息(如人口统计数据、地理位置或年龄);关于查询的信息(如查询长度);或在查询上下文中的文档信息(如标题字段的分数)。

判断列表

edit

LTR 模型通常在判断列表上进行训练,该列表是一组带有相关性等级的查询和文档。判断列表可以由人类或机器生成:它们通常从行为分析中填充,通常有人工审核。判断列表决定了给定搜索查询的结果的理想排序。LTR 的目标是使模型尽可能接近判断列表的排序,以适应新的查询和文档。

判断列表是用于训练模型的主要输入。它由包含查询和文档对及其相应相关性标签的数据集组成。 相关性判断通常是二元的(相关/不相关)或更细粒度的标签,例如从0(完全不相关)到4(高度相关)的等级。下面的示例使用分级相关性判断。

Judgment list example
Figure 9. Judgment list example

判断列表的注意事项

edit

虽然判断列表可以由人工手动创建,但有一些技术可以利用用户参与数据(如点击或转化)来自动构建判断列表。

判断列表的数量和质量将极大地影响LTR模型的整体性能。在构建判断列表时,应非常仔细地考虑以下方面:

  • 大多数搜索引擎可以使用不同的查询类型进行搜索。例如,在电影搜索引擎中,用户通过标题搜索,但也通过演员或导演搜索。在您的判断列表中,为每种查询类型保持平衡的示例数量至关重要。这可以防止过拟合,并使模型能够有效地跨所有查询类型进行泛化。
  • 用户通常提供比负面示例更多的正面示例。通过平衡正面和负面示例的数量,您可以帮助模型更准确地区分相关和无关内容。

特征提取

edit

查询和文档对本身并不提供足够的信息来训练用于学习排序(LTR)的机器学习模型。判断列表中的相关性评分依赖于多个属性或特征。这些特征必须被提取出来,以确定各个组件如何组合来决定文档的相关性。判断列表加上提取的特征构成了LTR模型的训练数据集。

这些功能属于以下三个主要类别之一:

  • 文档特征: 这些特征直接从文档属性中派生。 示例:电子商务商店中的产品价格。
  • 查询特征: 这些特征直接从用户提交的查询中计算得出。 示例:查询中的单词数量。
  • 查询-文档特征: 用于在查询上下文中提供文档信息的特征。 示例:title 字段的 BM25 分数。

为了准备用于训练的数据集,特征被添加到判断列表中:

Judgment list with features
Figure 10. Judgment list with features

要在 Elasticsearch 中实现这一点,请在构建训练数据集和在查询时进行推理时使用模板化查询来提取特征。以下是一个模板化查询的示例:

[
  {
    "query_extractor": {
      "feature_name": "title_bm25",
      "query": { "match": { "title": "{{query}}" } }
    }
  }
]

模型

edit

LTR的核心当然是一个ML模型。该模型使用上述训练数据与一个目标相结合进行训练。在LTR的情况下,目标是根据某种排名指标(如nDCGMAP),以最优方式对结果文档进行排序,相对于一个判断列表。该模型仅依赖于训练数据中的特征和相关性标签。

LTR 空间正在迅速发展,许多方法和模型类型正在被实验。实际上,Elasticsearch 特别依赖梯度提升决策树(GBDT)模型进行 LTR 推理。

请注意,Elasticsearch 支持模型推理,但训练过程本身必须在 Elasticsearch 之外进行,使用 GBDT 模型。在当今最流行的 LTR 模型中,LambdaMART 提供了强大的排序性能和低推理延迟。它依赖于 GBDT 模型,因此非常适合在 Elasticsearch 中进行 LTR。

XGBoost 是一个著名的库,它提供了一个 实现 LambdaMART,使其成为LTR的热门选择。我们在 eland 中提供了帮助程序,以促进训练好的 XBGRanker 模型作为您的LTR模型集成到Elasticsearch中。

了解更多关于训练和部署LTR模型的信息,或者查看我们在elasticsearch-labs仓库中提供的交互式LTR笔记本

Elastic 堆栈中的 LTR

edit

在本指南的下一页中,您将学习如何:

部署和管理排序学习模型

edit

此功能在8.12.0版本中引入,仅适用于某些订阅级别。 更多信息,请参阅https://www.elastic.co/subscriptions

使用Eland训练和部署模型

edit

通常,XGBoost 模型训练过程使用标准的 Python 数据科学工具,如 Pandas 和 scikit-learn。

我们开发了一个 示例 notebook,可在 elasticsearch-labs 仓库中找到。这个交互式 Python notebook 详细介绍了一个端到端的模型训练和部署工作流程。

我们强烈推荐在您的工作流程中使用 eland,因为它为在 Elasticsearch 中使用 LTR 提供了重要的功能。使用 eland 来:

  • 配置特征提取
  • 提取用于训练的特征
  • 在Elasticsearch中部署模型
在Eland中配置特征提取
edit

特征提取器是使用模板查询定义的。Eland 提供了 eland.ml.ltr.QueryFeatureExtractor 来直接在 Python 中定义这些特征提取器:

from eland.ml.ltr import QueryFeatureExtractor

feature_extractors=[
    # We want to use the score of the match query for the title field as a feature:
    QueryFeatureExtractor(
        feature_name="title_bm25",
        query={"match": {"title": "{{query}}"}}
    ),
    # We can use a script_score query to get the value
    # of the field rating directly as a feature:
    QueryFeatureExtractor(
        feature_name="popularity",
        query={
            "script_score": {
                "query": {"exists": {"field": "popularity"}},
                "script": {"source": "return doc['popularity'].value;"},
            }
        },
    ),
    # We can execute a script on the value of the query
    # and use the return value as a feature:
    QueryFeatureExtractor(
        feature_name="query_length",
        query={
            "script_score": {
                "query": {"match_all": {}},
                "script": {
                    "source": "return params['query'].splitOnToken(' ').length;",
                    "params": {
                        "query": "{{query}}",
                    }
                },
            }
        },
    ),
]

一旦特征提取器被定义,它们将被封装在一个eland.ml.ltr.LTRModelConfig对象中,以便在后续的训练步骤中使用:

from eland.ml.ltr import LTRModelConfig

ltr_config = LTRModelConfig(feature_extractors)
提取用于训练的特征
edit

构建您的数据集是训练过程中的关键步骤。这包括提取相关特征并将其添加到您的判断列表中。我们建议使用 Eland 的 eland.ml.ltr.FeatureLogger 辅助类来完成此过程。

from eland.ml.ltr import FeatureLogger

# Create a feature logger that will be used to query {es} to retrieve the features:
feature_logger = FeatureLogger(es_client, MOVIE_INDEX, ltr_config)

FeatureLogger 提供了一个 extract_features 方法,使您能够从判断列表中提取特定文档的特征。同时,您可以将查询参数传递给之前定义的特征提取器:

feature_logger.extract_features(
    query_params={"query": "foo"},
    doc_ids=["doc-1", "doc-2"]
)

我们的示例笔记本解释了如何使用FeatureLogger通过向判断列表添加特征来构建训练数据集。

特征提取的注意事项
edit
  • 我们强烈建议不要自己实现特征提取。在训练环境和Elasticsearch推理之间保持特征提取的一致性至关重要。通过使用与Elasticsearch同时开发和测试的eland工具,您可以确保它们能够一致地协同工作。
  • 特征提取是通过在Elasticsearch服务器上执行查询来完成的。这可能会给您的集群带来很大的压力,特别是当您的判断列表包含大量示例或您有很多特征时。我们的特征记录器实现旨在最小化发送到服务器的搜索请求数量并减少负载。然而,最好使用与任何面向用户的生产流量隔离的Elasticsearch集群来构建您的训练数据集。
将您的模型部署到 Elasticsearch
edit

一旦您的模型训练完成,您将能够在您的 Elasticsearch 集群中部署它。您可以使用 Eland 的 MLModel.import_ltr_model 方法

from eland.ml import MLModel

LEARNING_TO_RANK_MODEL_ID="ltr-model-xgboost"

MLModel.import_ltr_model(
    es_client=es_client,
    model=ranker,
    model_id=LEARNING_TO_RANK_MODEL_ID,
    ltr_model_config=ltr_config,
    es_if_exists="replace",
)

此方法将序列化训练好的模型和学习排序配置(包括特征提取)为Elasticsearch可以理解的格式。然后使用创建训练模型API将模型部署到Elasticsearch。

目前支持以下类型的模型用于Elasticsearch的LTR:

未来将支持更多模型类型。

排序模型管理

edit

一旦您的模型部署在Elasticsearch中,您可以使用训练模型API来管理它。 您现在可以准备好将您的LTR模型作为搜索时的重新排序器来使用。

使用学习排序进行搜索

edit

此功能在8.12.0版本中引入,仅适用于某些订阅级别。 更多信息,请参阅https://www.elastic.co/subscriptions

作为重排序的学习排序

edit

一旦您的LTR模型在Elasticsearch中训练并部署,它可以在搜索API中用作重新评分器

GET my-index/_search
{
  "query": { 
    "multi_match": {
      "fields": ["title", "content"],
      "query": "the quick brown fox"
    }
  },
  "rescore": {
    "learning_to_rank": {
      "model_id": "ltr-model", 
      "params": { 
        "query_text": "the quick brown fox"
      }
    },
    "window_size": 100 
  }
}

第一次传递查询,提供需要重新评分的文档。

上传到 Elasticsearch 的训练模型的唯一标识符。

传递给用于特征的查询模板的命名参数。

每个分片上应由重新评分器检查的文档数量。

已知限制
edit
重排序窗口大小
edit

LTR模型返回的分数通常与第一遍查询返回的分数不可比较,并且可能低于非重排序的分数。这可能导致非重排序的结果文档排名高于重排序的文档。为了防止这种情况,window_size参数对于LTR重排序器是强制性的,并且应大于或等于from + size

分页
edit

当向用户展示分页时,window_size 应保持不变,每页通过传递不同的 from 值来前进。改变 window_size 可能会改变顶部结果,导致用户在翻页时结果混乱地变化。

负分
edit

根据模型的训练方式,模型可能会为文档返回负分。虽然负分在第一阶段的检索和排序中是不允许的,但在LTR重排序器中使用它们是可能的。

作为特征的术语统计
edit

我们目前不支持将术语统计作为特征,但未来的版本将引入这一功能。