Elasticsearch:基于多个 kNN 字段对文档进行评分

作者:来自 Elastic Madhusudhan Konda

通过具有多个 kNN 字段的最接近的文档对文档进行评分

Elasticsearch 不仅仅是一个词法(文本)搜索引擎。 Elasticsearch 是多功能搜索引擎,除了传统的文本匹配之外,还支持 k 最近邻 (kNN) 搜索以及语义搜索。

Elasticsearch 中的 kNN 搜索主要用于查找多维空间中给定点的 “最近邻居”。文档被表示为一组数字(向量),在搜索时,kNN 特征会获取更接近查询向量的相关文档。 kNN 搜索通常应用于涉及向量的场景,其中向量是通过使用深度神经网络的 “嵌入” 过程从文本、图像或音频创建的。

另一方面,语义搜索是一种由自然语言处理特征驱动的搜索,它有助于根据意图和含义搜索相关结果,而不仅仅是文本匹配。

在本文中,我们的重点是搜索具有多个 kNN 字段的文档,并根据多个 kNN 向量字段对结果文档进行评分。

由于我们将在本文中详细了解 kNN 搜索,因此让我们花几分钟时间详细了解 kNN 的机制。

kNN 机制

kNN(k 最近邻居)获取的搜索结果几乎是最接近给定用户查询的 k 个文档(使用算法测量)。

它的工作方式是通过计算向量之间的距离(通常是欧几里得相似度或余弦相似度)。当我们使用 kNN 对数据集执行查询时,Elasticsearch 会找到最接近我们的查询向量的前 “k” 个条目。

在执行与搜索相关的活动以获取结果之前,必须使用适当的嵌入对索引进行预处理 —— 嵌入是向量化数据的术语。这些字段的类型是 dense_vector,用于保存数值数据。

让我们举个例子:

如果你有图像数据集,并且已使用神经网络将这些图像转换为向量,则可以使用 kNN 搜索来查找与查询图像最相似的图像。如果你提供 “披萨” 图像的向量表示,kNN 可以帮助你找到视觉上相似的其他图像,例如薄煎饼,也许还有意大利面:)

kNN 搜索是关于在向量空间中查找最近的数据点,因此适用于文本或图像嵌入的相似性搜索。相比之下,语义搜索是为了理解搜索查询中单词的含义和上下文,使其对于意图和上下文都很重要的基于文本的搜索非常强大。

为文当打分

当你有多个 k 最近邻 (kNN) 字段时,根据最接近的文档对文档进行评分需要利用 Elasticsearch 处理向量相似性的能力来对文档进行排名。这种方法在语义搜索和推荐引擎等场景中特别有用。或者我们正在处理多维数据并需要基于多个方面(字段)找到 “最接近” 或最相似的项目的情况。

文本嵌入(text embedding)及向量字段

让我们以电影(movies)索引为例,它由一些文件组成,例如标题(title)、概要(synopsis)等。我们将使用常见的数据类型(例如文本数据类型)来表示它们。除了这些普通字段之外,我们还将创建另外两个字段:title_vector 和 synopsis_vector 字段 - 顾名思义 - 它们是密集向量数据类型字段。这意味着,数据将使用称为 “文本嵌入” 的过程进行向量化。

嵌入模型是一个自然语言处理神经网络,它将输入转换为数字数组。然后,向量化数据将存储在密集向量类型字段中。数据文档可以有多个字段,包括一些用于存储向量数据的 dense_vector 字段。

因此,在下一节中,我们将混合使用普通字段和 kNN 字段来创建索引。

使用 kNN 字段创建索引

让我们创建一个名为 movies 的索引,其中包含示例电影文档。我们的文档将有多个字段,包括几个用于存储向量数据的 kNN 字段。以下片段演示了索引映射代码:

PUT /movies
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "title_vector.predicted_value": {
        "type": "dense_vector",
        "dims": 384
      },
      "synopsis": {
        "type": "text"
      },
      "synopsis_vector.predicted_value": {
        "type": "dense_vector",
        "dims": 384
      },
      "genre": {
        "type": "text"
      }
    }
  }
}

值得注意的是,文本类型的 title 字段有一个等效的向量类型字段:title_vector.predicted_value。类似地,synopsis 的向量字段是 synopsis_vector.predicted_value 字段。此外,密集向量场的维度 (384) 在上面的代码中提到为 dims。这表明模型将为每个摄取的字段生成 384 个维度。我们可以请求在密集向量字段上生成的最大维度是 2048。

执行此脚本将创建一个名为 movies 的新索引,其中包含两个向量字段:title_vector 和 synopsis_vector。

索引示例文档

现在我们有了索引,我们可以索引一些电影并进行搜索。除了 title 和 synopsis 字段外,文档还将包含向量字段。在索引文档之前,我们需要用相应的向量填充文档。以下代码演示了生成向量后的电影文档示例:

POST /movies/_doc/1
{
  "title": "The Godfather",
  "title_vector": [0.1, 0.5, 3, 4,...], // vectorized data 
  "synopsis": "The aging patriarch of an organized crime dynasty....",
  "synopsis_vector": [0.2, 0.6, 1, 0.7,...] // vectorized data 
}

如你所见,需要准备好向量数据以供文档提取。有几种方法可以做到这一点:

  • 一种是在 Elasticsearch 之外调用 text_embedding 模型上的 inference API 来对数据进行向量化,如上所示(我在这里提到它作为参考,尽管我们更希望使用推理处理器管道)
  • 另一种是设置和使用推理管道。

设置推理处理器(inference processor)

我们可以设置一个摄取管道,该管道将嵌入函数应用于相关字段以生成矢量化数据。例如,以下代码创建 movie_embedding_pipeline 处理器,该处理器将为每个字段生成嵌入并将其添加到文档中:

PUT _ingest/pipeline/movie_embedding_pipeline
{
  "processors": [
    {
      "inference": {
        "model_id": ".multilingual-e5-small",
        "target_field": "title_vector",
        "field_map": { "title": "text_field" }
      }
    },
    {
      "inference": {
        "model_id": ".multilingual-e5-small",
        "target_field": "synopsis_vector",
        "field_map": { "synopsis": "text_field" }
      }
    }
  ]
}

摄取管道可能需要一点解释:

  • 两个字段 - title_vector 和 synopsis_vector - 被称为 target_field - 是 dense_vector 字段类型。因此,它们存储由 multilingual-e5-small 嵌入模型生成的向量化数据
  • field_map 提到文档中的字段(在本例中为 title 和 synopsis 字段)被映射到模型的 text_field 字段
  • model_id 声明用于嵌入数据的嵌入模型
  • target_field 是向量化数据将被复制到的字段的名称

执行上述代码将创建一个 movie_embedding_pipeline 摄取管道。也就是说 - 仅包含 title 和 synopsis 的文档将通过附加字段(title_vector 和 synopsis_vector)进行增强,这些字段将具有内容的向量化版本。

索引文档

电影文档将由 title 和 synopsis 字段组成,正如预期的那样 - 因此我们可以按如下所示对其进行索引。请注意,文档通过 URL 中启用的管道处理器进行增强。以下代码片段显示了索引少量电影:

POST movies/_doc/?pipeline=movie_embedding_pipeline
{
  "title": "The Godfather",
  "synopsis": "The aging patriarch of an organized crime dynasty transfers control of his clandestine empire to his reluctant son."
}

POST movies/_doc/?pipeline=movie_embedding_pipeline
{
  "title": "Avatar",
  "synopsis": "A paraplegic Marine dispatched to the moon Pandora on a unique mission becomes torn between following his orders and protecting the world he feels is his home."
}

POST movies/_doc/?pipeline=movie_embedding_pipeline
{
  "title": "Godzilla",
  "synopsis": "The world is beset by the appearance of monstrous creatures, but one of them may be the only one who can save humanity."
}

POST movies/_doc/?pipeline=movie_embedding_pipeline
{
  "title": "The Good, The Bad and The Ugly",
  "synopsis": "A bounty hunting scam joins two men in an uneasy alliance against a third in a race to find a fortune in gold buried in a remote cemetery."
}

POST movies/_doc/?pipeline=movie_embedding_pipeline
{
  "title": "A Few Good Men",
  "synopsis": "Military lawyer Lieutenant Daniel Kaffee defends Marines accused of murder. They contend they were acting under orders."
}

我们当然可以使用 _bulk API 来一次性索引文档 - 请查看此 Bulk API 文档以了解更多详细信息。

一旦这些文档被索引,你就可以通过执行搜索查询来获取电影来检查是否添加了向量化内容:

GET movies/_search

这将导致 movies 索引具有由向量化内容组成的两个附加字段,如下图所示:

现在我们已经对文档进行了索引,让我们使用 kNN 搜索功能对这些文档进行搜索。

kNN 搜索

Elasticsearch 中的 k-最近邻搜索会获取最接近给定(查询)向量的向量(文档)。Elasticsearch 支持两种类型的 kNN 搜索:

  • 近似 kNN 搜索
  • 强力(或精确)KNN 搜索

虽然两种搜索都会产生结果,但强力搜索会以最大资源利用率和查询时间为代价找到准确的结果。近似 kNN 足以满足大多数搜索情况,因为它可以提供接近准确的结果。

Elasticsearch 为近似搜索提供 knn 查询,而我们应该使用 script_score 查询进行精确 kNN 搜索。

近似搜索

让我们对 movies 进行近似搜索,如下所示。Elasticsearch 提供了一个 kNN 查询,其中包含由我们的查询要求组成的 query_build_vector 块。让我们先编写代码片段,然后再讨论其组成部分:

GET movies/_search
{
  "knn": {
    "field": "title_vector.predicted_value",
    "query_vector_builder": {
      "text_embedding": {
        "model_id": ".multilingual-e5-small",
        "model_text": "Good"
      }
    },
    "k": 3,
    "num_candidates": 100
  },
  "_source": [
    "id",
    "title"
  ]
}

传统的搜索查询支持 query 功能,但是 Elasticsearch 引入了 knn 搜索功能作为查询向量的一等公民。

knn 块由我们要搜索的字段组成 - 在本例中,它是标题向量 - title_vector.predicted_value 字段。请记住,这是我们之前在映射中提到的字段的名称。

query_vector_builder 是我们需要提供查询以及嵌入查询所需的模型的地方。在本例中,我们将 multilingual-e5-small 设置为我们的模型,文本只是 “Good”。Elasticsearch 将使用文本嵌入模型 (multilingual-e5-small) 对相关查询进行向量化。然后,它将向量查询与可用的标题向量进行比较。

k 值表示需要返回多少文档作为结果。

此查询应该为我们提供前三份文档:

"hits": [
      {
        "_index": "movies",
        "_id": "ZADvgo4BDf-WoG_MTka1",
        "_score": 0.92932993,
        "_source": {
          "title": "The Good, The Bad and The Ugly"
        }
      },
      {
        "_index": "movies",
        "_id": "uJ3wgo4BMlgFmHKKtFSp",
        "_score": 0.91828954,
        "_source": {
          "title": "A Few Good Men"
        }
      },
      {
        "_index": "movies",
        "_id": "tp15fY4BMlgFmHKK6VRV",
        "_score": 0.90952975,
        "_source": {
          "title": "The Godfather"
        }
      }
    ]

当我们针对片名搜索 “Good” 时,得分最高的电影是《The Good, The Bad and the Ugly》。请注意,即使结果电影不匹配,kNN 搜索也总能得到结果 - 这是 kNN 匹配的固有特性。

记下每个文档的相关性分数 (_score) - 正如预期的那样,文档是根据此分数排序的。

搜索多个 kNN 字段

我们有两个向量字段 - 电影文档中的 title_vector 和 synopsis_vector 字段 - 我们当然可以针对这两个字段进行搜索,并根据组合分数期望得到结果文档。

假设我们想在 title 中搜索 “Good”,但在 synopsis 字段中搜索 “orders”。记得从之前使用 “Good” 的单个 title 字段搜索中,我们检索到了《The Good, The Bad and the Ugly》这部电影。让我们看看根据概要的 “orders” 部分作为搜索条件,将获取哪部电影。

以下代码声明了我们的多 kNN 字段搜索:

POST movies/_search
{
  "knn":[
    {
     "field": "title_vector.predicted_value",
     "query_vector_builder": {
      "text_embedding": {
        "model_id": ".multilingual-e5-small",
        "model_text": "Good"
      }
    },
     "k": 3,
     "num_candidates": 100
    },
    {
     "field": "synopsis_vector.predicted_value",
     "query_vector_builder": {
      "text_embedding": {
        "model_id": ".multilingual-e5-small",
        "model_text": "orders"
      }
     },
     "k": 3,
     "num_candidates": 100
    }
  ]
}

正如你所想象的,knn 查询可以接受多个搜索字段作为数组 - 在这里我们从两个字段中提供了搜索条件。答案是 “A Few Good Men”,因为包含 “order” 向量的概要向量就是这部电影。

何时使用多 kNN 字段进行搜索

我们可以使用多个 kNN 字段进行搜索的一些情况如下:

  • 根据图像相似性(视觉 kNN 字段)和推文相似性(文本 kNN 字段)搜索 “tweets”。
  • 根据音频特征(音频作为 kNN 字段)推荐类似的歌曲,如节奏和韵律;可能还有标题/艺术家/流派信息(文本 kNN 字段)。
  • 根据用户行为(用于用户交互的 kNN 字段)和电影/产品属性(基于这些属性的 kNN 字段)推荐电影或产品。

就这样了。在本文中,我们研究了 kNN 搜索的机制,以及当我们有多个向量化字段时如何找到最近的文档。

准备好自己尝试一下了吗?开始免费试用。

想要获得 Elastic 认证吗?了解下一次 Elasticsearch 工程师培训何时开始!

原文:Elasticsearch Scoring: Based on multiple kNN fields — Elastic Search Labs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/670511.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

海外高清短视频:四川京之华锦信息技术公司

海外高清短视频:探索世界的新窗口 在数字化时代的浪潮下,海外高清短视频成为了人们探索世界、了解异国风情的新窗口。四川京之华锦信息技术公司这些短视频以其独特的视角、丰富的内容和高清的画质,吸引了无数观众的目光,让人们足…

DI-engine强化学习入门(一)使用强化学习模型控制月球着陆器

控制程序观前提醒:本章内容为训练一个强化学习模型,并使用强化学习模型控制月球着陆器。安装和运行DI-engine示例。 什么是DI-engine? DI-engine 是一个由 OpenDILab 提供的开源强化学习(Reinforcement Learning,简称RL&#xf…

一次职业院校漏洞挖掘

这个是之前挖掘到的漏洞,目前网站进行重构做了全新的改版,但是这个漏洞特别经典,拿出来进行分享。看到src上面的很多敏感信息泄露,所以自己也想找一个敏感信息泄露,官网如图: 发现在下面有一个数字校园入口…

电源滤波器怎么选用

电源滤波器怎么选用 滤波器应用场景及作用第一步:第二步:第三步:第四步: 滤波器应用场景及作用 可以有效解决EMC测试无法通过、端口防护、滤除干扰、设备保护等问题 主要功能有: 1、降低主电源谐波; 2、保护驱动装置电力电子元件…

硬币检测电路设计

一、来源:凡亿教育 第一场:硬币检测装置原理分析、电路设计以及器件选型_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Zh4y1V7Px/?p1&vd_source43eb1cb50ad3175d7f3b9385905cd88f 二、开发软件:KEIL MDK 三、主控芯片&#…

大型制造业集团IT信息化总体规划方案(65页PPT)

方案介绍: 本大型制造业集团IT信息化总体规划方案旨在通过构建先进、高效、稳定的IT信息化系统,支撑集团各业务领域的运营和管理需求,促进集团整体运营效率和竞争力的提升。通过实施本项目,集团将能够更好地应对市场变化和客户需…

嫁接打印:经济与实用的完美结合

在制造领域,寻求经济且好用的技术方案至关重要。而在模具制造中,3D 打印随形水路在提升冷却效率和产品良率方面的卓越表现已得到广泛认同。如何更经济的应用3D打印技术,就不得不说嫁接打印了。 在嫁接打印的制造过程中,产品的一部…

Uniapp写一个简单的商品瀑布流界面+商品详情

最终效果: 整体内容比较简单,参考了一篇瀑布流文章和一篇商品详情文章随便修改整了下,主要是给想做这方便面的新人一个简单逻辑的展示(其实我也是第一次写这个emmm) 一.组件下载: uni-icon uni-goods-nav…

InsightFace | 基于 AI 增强的人脸检测

点击下方卡片,关注“小白玩转Python”公众号 概述 我将使用InsightFace,这是一个以其在复杂面部分析任务中的卓越表现而闻名的开源AI工具包。该工具包可以帮助完成诸如人脸检测、关键点识别、情感识别、年龄和性别估算以及属性分析等任务。 示例 !pip in…

yolov10/v8 loss详解

v10出了就想看看它的loss设计有什么不同,看下来由于v8和v10的loss部分基本一致就放一起了。 v10的论文笔记,还没看的可以看看,初步尝试耗时确实有提升 好记性不如烂笔头,还是得记录一下,以免忘了,废话结束…

tcp链接中的三次挥手是什么原因

一、tcp链接中的正常四次挥手过程? 刚开始双方都处于 ESTABLISHED 状态,假如是客户端先发起关闭请求。四次挥手的过程如下: 1、客户端打算关闭连接,此时会发送一个 TCP 首部 FIN 标志位被置为 1 的报文,也即 FIN 报文…

Pycharm的基础设置+Pycharm与AutoDL服务器连接

一.pycharm的基础设置 1.下载pycharm profession版,配置之前博客里面的解释器mask2 2.run detect.py 3.终端的设置 (1)先直接在终端里面pip install 我们再创建一个测试python文件:terninal_test.py 虽然上面安装成功了包&#x…

Nested KVM Hypervisor Support

Description Nested KVM是指基于虚拟化技术的虚拟机管理系统。 Nested KVM在Intel处理器上,KVM使用Intel的vmx(virtualmachine eXtensions)来提高虚拟机性能,即硬件辅助虚拟化技术。如果一台虚拟机能够和物理机一样支持vmx&…

秘塔AI搜索,看看如今的AI搜索能有多懂你

你们正在用的浏览器是哪一款? 平时搜索时是否也有过这样的经历,在搜索引擎里输入关键词,然后在一堆广告中大海捞针,一不小心就入了一刀999的坑,又或是陈年资料令人发懵,压根儿就别想找到宝藏资源&#xff…

【Qt秘籍】[007]-LineEdit Pushbutton控件

Qt的中有着各种各样的控件,相较于传统C/C的输出默认只能在控制台实现,Qt中可以有不同的接口实现各种不同的功能,下面我们将实现不同功能的输出 hello world! 标签Label 【Qt秘籍】[006]-Label实现Hello World程序-编程第一步-CSD…

Prime1 - 提权的另一种解法,彻底搞懂OpenSSL解密渗透提权,超强思路版。

提权枚举 现在我们直接从低权限用户开始;我们先按照提权步骤,简单的系统枚举 虽然我们知道可以利用系统版本低进行内核提权,内核提权虽然比较快比较方便,但也比较暴力,缺点非常明显;很容易导致系统服务中…

GIS结合物联网:塑造智慧地球的新篇章

在信息技术飞速发展的今天,地理信息系统(GIS)与物联网(IoT)的深度融合,正以前所未有的方式重塑着我们对世界的认知。本文将深入探讨GIS与物联网结合的原理、应用实践以及面临的挑战与未来展望,共…

刷代码随想录有感(88):贪心算法——加油站

题干&#xff1a; 代码&#xff1a; class Solution { public:int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {int totalcost 0;for(int i 0; i < gas.size(); i){totalcost gas[i] - cost[i];}if(totalcost < 0)return -1;int …

数据库、数据表的基本操作

1.数据库的基本操作 &#xff08;1&#xff09;创建数据库 &#xff08;2&#xff09;删除数据库 &#xff08;3&#xff09;将数据库的字符集修改为gbk gbk是汉字内码扩展规范&#xff0c;是GB2312和GB13000的扩展&#xff0c;主要用于简体中文。 &#xff08;4&#xff09;…

vmware 正版免费下载

Broadcom 已经收购了 vmware 并且对普通用户提供免费服务. 那么我们怎么去获取这个玩意呢, 注册完之后打开就是这么个狗屎 , 根本不知道在哪里下载&#xff0c;注册的时候还不能用国内邮箱更是超级狗屎 转到 dashboard 搜索 workstation Pro你会搜索到这么一个奇怪的网址然后…