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

news/2025/2/8 15:48:05/

作者:来自 Elastic Gus Carlock 及 Kirti Sodhi

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

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

序言

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 中导入聚类的端到端工作流程。

完整的采集管道脚本可以使用 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<array1.length; i++) {sum += Math.pow((array1[i]-array2[i]), 2.0);}return Math.sqrt(sum);}List l2NormalizeArray(List array) {double sumSquared = 0.0;for (element in array) {sumSquared += Math.pow(element, 2.0)}double l2Norm = Math.sqrt(sumSquared);// create a new array to not overwrite ctxList outputArray = new ArrayList();for (element in array) {outputArray.add(element/l2Norm)}return outputArray}

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

     List distances = new ArrayList();double minDistance;int closestCluster;for (int i=0; i<params.clusterCenters.length; i++) {double distance;if (params.normalize == true) {distance = euclideanDistance(params.clusterCenters[i], l2NormalizeArray(ctx[params.analysisField]));} else {distance = euclideanDistance(params.clusterCenters[i], ctx[params.analysisField]);}distances.add(distance);if (i == 0) {minDistance = distance;closestCluster = i;} else {if (distance < minDistance) {minDistance = distance;closestCluster = 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_clustering_5_newsgroup_openai", processors=[script]
)

聚类结果

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

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

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

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

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

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

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

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

检测聚类中的异常值

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

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

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

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

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

整合所有内容

在这篇博客中,我们演示了如何将自定义聚类模型集成到 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


http://www.ppmy.cn/news/1570355.html

相关文章

【Linux开发工具】包管理器yum和文本编辑器vim

目录 一、前言 二、Linux中的软件商店yum 1.三种安装软件的方式 2.yum的使用方法 三、Linux中的编辑器vim 1.vim的三种模式及切换 2.命令模式详解 3.底行模式详解 4.替换模式 5.视图模式 6.vim下的多线程操作 7.vim的配置 四、总结 一、前言 在初步认识了Linux的基…

windows11上,使用pipx安装Poetry,Poetry的安装路径是什么?

当使用 pipx 安装 Poetry 时&#xff0c;pipx 会将 Poetry 安装到一个独立的虚拟环境中&#xff0c;并将其可执行文件链接到一个集中的目录中。以下是 pipx 安装 Poetry 时的路径信息&#xff1a; 1. Poetry 的安装路径 pipx 会为每个工具&#xff08;如 Poetry&#xff09;创…

k8sollama部署deepseek-R1模型,内网无坑

这是目录 linux下载ollama模型文件下载到本地,打包迁移到k8s等无网络环境使用下载打包ollama镜像非k8s环境使用k8s部署访问方式非ollama运行deepseek模型linux下载ollama 下载后可存放其他服务器 curl -L https://ollama.com/download/ollama-linux-amd64.tgz -o ollama-linu…

开源CodeGPT + DeepSeek-R1 是否可以替代商业付费代码辅助工具

开源CodeGPT + DeepSeek-R1 是否可以替代商业付费代码辅助工具 背景与研究目的 在快速发展的软件开发领域,代码辅助工具已成为提高开发效率和质量的关键。然而,商业付费工具如通义灵码和腾讯AI代码助手,尽管功能强大,但其高昂的成本和许可证限制,使得许多企业寻求更具吸…

K8S组件架构

master节点上 kube-apiserver&#xff1a;服务端&#xff0c;提供k8s api接口服务&#xff0c;接受外部请求管理和控制整个集群。 kube-secheduler&#xff1a;调度计算&#xff0c;负责根据资源需求和约束条件&#xff0c;将pod调度到合适的主机上。 kube-controller-manag…

TCN时间卷积神经网络多变量多步光伏功率预测(Matlab)

代码下载&#xff1a;TCN时间卷积神经网络多变量多步光伏功率预测&#xff08;Matlab&#xff09; TCN时间卷积神经网络多变量多步光伏功率预测 一、引言 1.1、研究背景和意义 随着全球能源危机的加剧和环保意识的提升&#xff0c;可再生能源&#xff0c;尤其是太阳能&…

每日Attention学习22——Inverted Residual RWKV

模块出处 [arXiv 25] [link] [code] RWKV-UNet: Improving UNet with Long-Range Cooperation for Effective Medical Image Segmentation 模块名称 Inverted Residual RWKV (IR-RWKV) 模块作用 用于vision的RWKV结构 模块结构 模块代码 注&#xff1a;cpp扩展请参考作者原…

3.Python分支和循环:if判断语句、运算符、if-else语句、while循环、for循环、break、continue

1. if 判断语句 if 语句用于根据条件判断执行不同的代码块。语法格式如下&#xff1a; if condition:# 如果 condition 为 True&#xff0c;执行这部分代码statement_1condition 是一个表达式&#xff0c;计算结果为 True 或 False。如果条件为 True&#xff0c;执行缩进的语…