在 Elastic 中实施聚类工作流以提升搜索相关性

2025年2月16日   |   by mebius

作者:来自 ElasticGus CarlockKirti Sodhi

%title插图%num

我们演示了如何利用 OpenAI text-ada-002 向量将自定义聚类模型集成到 Elastic Stack 中,从而简化 Elastic 生态系统内的工作流程。

在本文中,我们将演示如何通过利用示例文本数据集将自定义聚类模型集成到 Elastic Stack 中,从而简化 Elastic 生态系统中的工作流程。你可以按照以下步骤使用此 Jupyter 笔记本创建一个简单的聚类管道。

序言

tgcode

Kibana 中的机器学习应用程序提供了一套全面的高级功能,包括异常和离群值检测,以及分类和回归模型。它支持通过 eland Python 客户端集成来自 scikit-learn 库的自定义模型。虽然 Kibana 提供了强大的机器学习功能,但它目前不支持预构建和自定义模型中的聚类分析。聚类算法对于通过对相似查询进行分组来增强搜索相关性以及安全性至关重要,它们有助于识别数据中的模式以检测潜在威胁和异常。

Elastic 提供了灵活性,可以利用自定义 scikit-learn 模型(例如 k-means)执行聚类等任务 – 例如,按相似性对新闻文章进行分组。虽然这些算法尚未得到官方支持,但你可以使用模型的聚类中心作为采集管道的输入,将这些功能无缝集成到你的 Elastic 工作流中。在以下部分中,我们将指导你实施此方法。

数据集概述

为了验证这一概念,我们利用了 20 个新闻组数据集,这是文本分类和聚类任务的常用基准。该数据集由分为 20 个不同类别的新闻组帖子组成,涵盖体育、技术、宗教和科学等主题。它可通过 `scikit-learn` 库广泛获取。

在我们的实验中,我们专注于 5 个类别的子集:

  • rec.sport.baseball
  • rec.sport.hockey
  • comp.sys.ibm.pc.hardware
  • talk.religion.misc
  • sci.med

选择这些类别是为了确保技术、休闲和多样化主题的混合,以便进行有效的聚类分析。

特征提取和生成文本嵌入:

使用 scikit-learn 的 `feature_extraction` 实用程序删除停用词、标点符号和不相关的标记,清理文本文档,确保文本向量捕获有意义的模式。然后使用这些特征,使用 OpenAI 的语言模型 “text-embedding-ada-002” 生成文本嵌入。

模型 text-embedding-ada-002 是用于生成文本密集向量表示的最先进模型之一,可捕捉文本数据中固有的细微语义含义。我们利用 Azure OpenAI 端点生成嵌入以供分析。有关将此端点与 Elasticsearch 一起使用的说明,请参阅 Elasticsearch 开放推理 API 添加 Azure AI Studio 支持

在训练 k-means 聚类模型以标准化向量幅度之前,对嵌入进行了规范化。规范化是 k-means 的关键预处理步骤,因为它根据欧几里得距离计算聚类。标准化嵌入消除了量级差异,确保聚类决策完全依赖于语义接近度,从而提高了聚类结果的准确性。

我们使用 k=5 训练 k-means 模型以匹配数据集的类别并提取聚类中心。这些中心作为 Kibana 摄取管道的输入,促进传入文档的实时聚类。我们将在下一节中进一步讨论这一点。

使用 Ingest 管道的脚本处理器进行动态聚类

在 Scikit-learn 中训练模型后,使用 Ingest 管道为每个记录分配聚类编号。此 Ingest 管道采用三个可配置参数:

  • clusterCenters – 嵌套列表,每个聚类中心向量都有一个列表。对于本博客,它们是使用 Scikit-learn 生成的。
  • analysisField – 包含密集向量化数据的字段。
  • normalize – 规范化 analysisField 向量。

将 Ingest 管道添加到索引或数据流后,所有新摄取的数据都将被分配一个最接近的聚类编号。

下图说明了在 Kibana 中导入聚类的端到端工作流程。

%title插图%num

完整的采集管道脚本可以使用 Python 生成,示例位于笔记本的 “Add clustering ingest pipeline” 部分。我们将在下面深入介绍采集管道的具体细节。

然后将 cluster_centers 加载为浮点数的嵌套列表,每个聚类中心一个列表。

cluster_centers_filepath = 'data/openai_cluster_centers.json'
with open(cluster_centers_filepath, 'r') as f:
    cluster_centers = json.load(f)

在 Painless 脚本的第一部分中,定义了两个函数。第一个是 euclideanDistance,它以浮点数形式返回两个 arrayList 之间的距离。第二个是 l2NormalizeArray,它缩放 arrayList,使其元素平方和等于一。

script = {
 "script": {
   "lang": "painless",
   "source": """ 
     double euclideanDistance(List array1, List array2) {
       double sum = 0.0;
       for (int i=0; i

然后执行 k-Means 推理步骤。对于每个聚类中心,使用摄取管道上下文 (ctx) 和 analysisField 参数计算新传入文档向量之间的距离,该参数选择包含 OpenAI text-ada-002 向量的字段。然后根据最近的聚类中心(即距离最短的文档)将 nearestCluster 编号分配给文档。此外,如果 normalize 参数设置为 true,则在进行距离计算之前先获取传入文档向量的 L2 范数。

     List distances = new ArrayList();
     double minDistance;
     int closestCluster;

     for (itgcodent i=0; i

然后,通过摄取管道上下文将该集群的 nearestCluster 和 minDistance 值传回文档。

     ctx["ml_clustering.closestCluster"] = closestCluster;
     ctx["ml_clustering.minDistance"] = Collections.min(distances);
   """,

有几个可配置参数,上面已描述,但在此仅供参考。第一个是 clusterCenters,一个嵌套的浮点数组,每个聚类中心一个数组。第二个是 analysisField,该字段包含 text-ada-002 向量。最后,normalize 将对文档向量进行 L2 标准化。请注意,只有在训练 k-Means 模型之前对向量也进行了标准化时,normalize 参数才应设置为 True。

   "params": {
     "clusterCenters": cluster_centers,
     "analysisField": "openai_vector",
     "normalize": True
   }
 }
}

最后,一旦管道配置完成,就分配一个ID并将其放到集群上。

es_client.ingest.put_pipeline(
   id="ml_clutgcodestering_5_newsgroup_openai", processors=[script]
)

聚类结果

我们期望聚类结果显示每个类别形成一个不同的聚类。虽然棒球和曲棍球可能由于它们共同的体育背景而重叠;但技术、宗教和医学类别应该形成独立且明确界定的聚类。当使用 t-SNE 降维算法查看 OpenAI text-ada-002 向量时,它们显示这些聚类之间存在明显分离,并且体育主题紧密相关:

实际新闻组标签;在 OpenAI text-ada-002 向量上训练的 2D t-SNE

%title插图%num

点的位置表明分组之间有明显的分离,这表明向量化正在捕捉每篇文章的语义含义。

因此,零样本分类结果非常出色。即使在训练数据中没有为模型提供标签,只提供了聚类数量,在样本数据中,k-means 模型在分配聚类编号时提供了超过 94% 的准确率:

预测的聚类标签;在 OpenAI text-ada-002 向量上训练的 2D t-SNE

%title插图%num

将实际新闻组标签与样本内预测标签进行比较,实际新闻组标签与聚类模型预测的标签之间几乎没有差异。这由混淆矩阵表示:

OpenAI text-ada-002 向量上的零样本分类混淆矩阵

%title插图%num

混淆矩阵的对角线表示每个类别的样本准确度,模型对每个类别预测正确标签的准确率超过 94%。

检测聚类中的异常值

k-means 模型可以看作是高斯混合模型 (GMM) 的近似值,但不捕获协方差,其中距离最近聚类的分位数是分布分位数的近似值。这意味着 k-mean 模型可以捕获数据分布的近似值。使用这种方法,可以选择大量聚类(在本例中为 100 个),并训练一个新模型。聚类数量越多,分布的拟合越灵活。因此,在这种情况下,目标不是学习数据的内部分组,而是捕获数据的整体分布。

距离分位数可以通过查询计算。在本例中,使用 100 个聚类训练了一个模型,并选择 75% 的距离作为异常值的截止值。从上面显示实际新闻组标签的 t-SNE 表示的相同图表开始:

实际新闻组标签;在 OpenAI text-ada-002 向量上训练的 2D t-SNE

%title插图%num

当添加训练集中未包含的新闻组数据时,2D t-SNE 表示显示出与数据的良好拟合。此处,橙色数据点不被视为异常值,而深灰色数据点则标记为异常值:

k=100 的异常值结果;在 OpenAI text-ada-002 向量上训练的 2D t-SNE

%title插图%num

整合所有内容

在这篇博客中,我们演示了如何将自定义聚类模型集成到 Elastic Stack 中。我们开发了一个工作流,将 scikit-learn 聚类模型(例如 k-means)导入 Elastic Stack,从而可以直接在 Kibana 中进行聚类分析。通过使用 20 个新闻组数据集,我们演示了如何应用此工作流对类似文档进行分组,同时还讨论了使用高级文本嵌入模型(例如 OpenAI 的“text-embedding-ada-002”)来创建高效聚类所必需的语义表示。

结果部分展示了清晰的聚类分离,表明 “text-embedding-ada-002” 模型可以有效捕获语义含义。k-means 模型在零样本分类中实现了超过 94% 的准确率,混淆矩阵显示预测标签和实际标签之间的差异最小,证实了其强大的性能。

通过此工作流,Elastic 用户可以将聚类技术应用于自己的数据集,无论是用于对搜索中的类似查询进行分组,还是用于检测安全应用程序的异常模式。本文介绍的解决方案提供了一种将高级集群功能集成到 Elastic 的简单方法。我们希望这能激励你探索这些功能并将其应用于你自己的用例。

下一步是什么?

上面的聚类结果表明 Painless 实现准确地对相似主题进行了聚类,性能准确率达到 94%。展望未来,我们的目标是在结构化程度较低、噪声明显较多且聚类数量较多的数据集上测试管道。这将有助于在更具挑战性的场景中评估其性能。虽然 k-means 已经显示出不错的聚类结果,但探索高斯混合模型或均值移位等用于异常值检测的替代方案可能会产生更好的结果。这些方法也可以使用 Painless 脚本或摄取管道来实现。

在未来,我们认为可以使用 ELSER 增强此工作流程,因为我们可以使用 ELSER 首先从数据集中检索相关特征,然后将其用于聚类,从而进一步提高模型在分析中的性能和相关性。此外,我们想解决如何正确设置正确的聚类数量,以及如何有效地处理模型漂移。

与此同时,如果你有类似的实验或用例要分享,我们很乐意听取你的意见!欢迎随时提供反馈或通过我们的社区 Slack 频道讨论论坛与我们联系。

Elasticsearch 包含许多新功能,可帮助你为你的用例构建最佳搜索解决方案。深入了解我们的示例笔记本以了解更多信息,开始免费云试用,或立即在你的本地机器上试用 Elastic。

原文:Implementing clustering workflows in Elastic to enhance search relevance – Elasticsearch Labs

文章来源于互联网:在 Elastic 中实施聚类工作流以提升搜索相关性

相关推荐: 使用 Elasticsearch 导航检索增强生成图表

作者:来自 ElasticLouis Jourdain及Ivan Monnier 了解如何使用知识图谱来增强 RAG 结果,同时在 Elasticsearch 中高效存储图谱。本指南探讨了根据用户查询动态生成知识子图的详细策略。 检索增强生成 (RAG) 通过…

Tags: , , , ,