从零开发短视频电商 OpenSearch k-NN插件

2023-11-29 19:28

本文主要是介绍从零开发短视频电商 OpenSearch k-NN插件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • k-NN索引
      • 简介
      • 索引设置(Setting)
    • Script Score k-NN 精准KNN
      • 创建KNN字段索引
      • 添加数据
      • 精确KNN搜索
    • 近似K-NN搜索
      • 示例
      • 创建KNN字段索引
      • 添加数据
      • 近似KNN查询
    • 带过滤器的k-NN搜索
      • 过滤搜索优化

该篇OpenSearch的版本为2.11

  • https://opensearch.org/docs/2.11/search-plugins/knn/index/

k-NN 插件是 k-近邻的缩写,使用户能够在向量索引中搜索查询点的 k-近邻。要确定邻居,您可以指定要用于测量点之间距离的空间(距离函数)。

用例包括推荐(例如,音乐应用程序中的“您可能喜欢的其他歌曲”功能)、图像识别和欺诈检测。有关 k-NN 搜索的更多背景信息,请参阅维基百科。

该插件支持三种不同的方法来从向量索引中获取 k 最近邻:

  1. 近似 k-NN ,通常,这些算法会牺牲索引速度和搜索准确性,以换取性能优势,例如更低的延迟、更小的内存占用和更具可扩展性的搜索。要了解有关算法的更多信息,请参阅 nmslib 和 faiss 的文档。
    • 近似 k-NN 是需要低延迟的大型索引(即数十万个向量或更多)搜索的最佳选择。如果您想在 k-NN 搜索之前对索引应用过滤器,则不应使用近似 k-NN,这会大大减少要搜索的向量数量。在这种情况下,您应该使用Script Score k-NN或 Painless 扩展。
  2. Script Score k-NN,精确的 k-NN 搜索。通过这种方法,您可以对索引中的向量子集运行 k-NN 搜索(有时称为预过滤搜索)。使用此方法搜索较小的文档主体或需要预过滤器时。对大型索引使用此方法可能会导致高延迟。预过滤,先keyword过滤后向量搜索。
  3. Painless extensions ,可以在更复杂的组合中使用它。与 k-NN 脚本评分类似,您可以使用此方法在索引中执行强力、精确的 k-NN 搜索,该搜索也支持预过滤。与 Script Score k-NN相比,此方法的查询性能稍慢。如果您的用例需要对最终分数进行更多自定义,则应使用此方法而不是Script Score k-NN

总的来说,对于较大的数据集,您通常应该选择近似最近邻方法,因为它的扩展性明显更好。对于较小的数据集,您可能想要应用过滤器,您应该选择Script Score k-NN。如果您有更复杂的用例,需要使用距离函数作为评分方法的一部分,则应该使用Painless extensions

k-NN索引

简介

k-NN 插件引入了自定义数据类型 knn_vector ,它允许用户将其 k-NN 向量提取到 OpenSearch 索引中并执行不同类型的 k-NN 搜索。 knn_vector 字段是高度可配置的,可以服务于许多不同的 k-NN 工作负载。

Mapping映射参数必需的默认可更新描述
nametruen/afalse最近邻方法的标识符。hnsw、ivf(需要训练),一般都是选hnsw
space_typefalsel2false用于计算向量之间距离的向量空间类型。
enginefalsenmslibfalse用于索引和搜索的近似 k-NN 库。可用的库有 faiss、nmslib 和 lucene。
parametersnullfalse用于最近邻法的参数。

Mapping示例

{"type": "knn_vector","dimension": 100,"method": {"name":"hnsw","engine":"lucene","space_type": "l2","parameters":{"m":2048,"ef_construction": 245}}
}{"type":"knn_vector","dimension":100,"method":{"name":"hnsw","engine":"faiss","space_type":"l2","parameters":{"encoder":{"name":"pq","parameters":{"code_size":8,"m":8}}}}
}{"type":"knn_vector","dimension":100,"method":{"name":"ivf","engine":"faiss","space_type":"l2","parameters":{"nlist":4,"nprobes":2}}
}

选择建议

构建 knn_vector 字段时有很多选项可供选择。要确定选择正确的方法和参数,做出哪些权衡。

要考虑的因素包括

(1) 查询延迟

(2) 查询质量

(3) 内存限制

(4) 索引延迟

  • 如果内存不是问题,HNSW 提供非常强大的查询延迟/查询质量权衡。
  • 如果您想使用比 HNSW 更少的内存和更快的索引,同时保持类似的查询质量,您应该用IVF。
  • 如果内存是一个问题,请考虑将 PQ 编码器添加到您的 HNSW 或 IVF 索引中。由于PQ是有损编码,查询质量会下降。

内存估计

HNSW 所需的内存估计为 1.1 * (4 * dimension + 8 * M) 字节/向量。

例如,假设您有 100 万个向量,维度为 256,M 为 16。内存需求可估计如下:

1.1 * (4 * 256 + 8 * 16) * 1,000,000 ~= 1.267 GB
  • m:插件为每个新元素创建的双向链接的数量。增加和减少该值会对内存消耗产生很大影响。将此值保持在 2 到 100 之间。

IVF 所需的内存估计为 1.1 * (((4 * dimension) * num_vectors) + (4 * nlist * d)) 字节。

例如,假设您有 100 万个向量,维度为 256,nlist 为 128。内存需求可估计如下:

1.1 * (((4 * 256) * 1,000,000) + (4 * 128 * 256))  ~= 1.126 GB
  • nlist:将向量划分成的桶的数量。较高的值可能会导致更准确的搜索,但会牺牲内存和训练延迟。

索引设置(Setting)

k-NN 插件引入了几个索引设置,也可用于配置 k-NN 结构。

设置中定义的几个参数正在弃用过程中。这些参数应该在映射(Mapping)中设置,而不是在索引(Index)设置中。映射中设置的参数将覆盖索引设置中设置的参数。在映射中设置参数允许索引拥有多个具有不同参数的 knn_vector 字段。

SettingDefaultUpdatableDescription
index.knnfalsefalse索引是否应该为 knn_vector 字段构建本机库索引。如果设置为 false, knn_vector 字段将存储在文档值中,但近似 k-NN 搜索功能将被禁用。
index.knn.algo_param.ef_search512truek-NN 搜索期间使用的动态列表的大小。值越高,搜索越准确,但搜索速度越慢。仅适用于 nmslib。
index.knn.algo_param.ef_construction512false1.0.0 中已弃用。请使用映射参数来设置该值。
index.knn.algo_param.m16false1.0.0 中已弃用。请使用映射参数来设置该值。
index.knn.space_typel2false1.0.0 中已弃用。请使用映射参数来设置该值。

Script Score k-NN 精准KNN

可以在执行最近邻搜索之前对索引应用过滤器。这对于索引主体可能根据其他条件而变化的动态搜索情况很有用。

如果您打算仅使用分数脚本方法(而不是近似方法),您可以将 index.knn 设置为 false

创建KNN字段索引

创建一个包含两个 knn_vector 字段的索引

PUT my-knn-index-2
{"mappings": {"properties": {"my_vector": {"type": "knn_vector","dimension": 2},"color": {"type": "keyword"}}}
}

添加数据

POST _bulk
{ "index": { "_index": "my-knn-index-2", "_id": "1" } }
{ "my_vector": [1, 1], "color" : "RED" }
{ "index": { "_index": "my-knn-index-2", "_id": "2" } }
{ "my_vector": [2, 2], "color" : "RED" }
{ "index": { "_index": "my-knn-index-2", "_id": "3" } }
{ "my_vector": [3, 3], "color" : "RED" }
{ "index": { "_index": "my-knn-index-2", "_id": "4" } }
{ "my_vector": [10, 10], "color" : "BLUE" }
{ "index": { "_index": "my-knn-index-2", "_id": "5" } }
{ "my_vector": [20, 20], "color" : "BLUE" }
{ "index": { "_index": "my-knn-index-2", "_id": "6" } }
{ "my_vector": [30, 30], "color" : "BLUE" }

精确KNN搜索

在识别最近的邻居之前,使用 script_score 查询预先过滤您的文档:

GET my-knn-index-2/_search
{"size": 2,"query": {"script_score": {"query": {"bool": {"filter": {"term": {"color": "BLUE"}}}},"script": {"lang": "knn","source": "knn_score","params": {"field": "my_vector","query_value": [9.9, 9.9],"space_type": "l2"}}}}
}

所有参数都是必需的。

  • lang 是脚本类型。该值通常为 painless ,但此处必须指定 knn
  • source 是脚本的名称 knn_score
  • field 是包含矢量数据的字段。
  • query_value 是您要查找最近邻居的点。对于欧几里得和余弦相似空间,该值必须是与字段映射中设置的维度相匹配的浮点数组。对于汉明位距离,该值可以是有符号长整型或 Base64 编码字符串(分别适用于长整型和二进制字段类型)。
  • space_type 对应距离函数。l1,l2,linf,cosinesimil,innerproduct,hammingbit
    • 余弦相似度返回 -1 到 1 之间的数字,并且由于 OpenSearch 相关性分数不能低于 0,因此 k-NN 插件加 1 以获得最终分数。

近似K-NN搜索

标准 k-NN 搜索方法使用强力方法计算相似度,该方法测量查询与多个点之间的最近距离,从而产生准确的结果。这在许多应用中效果很好。然而,在高维数据集非常大的情况下,这会产生缩放问题,从而降低搜索效率。近似 k-NN 搜索方法可以通过使用更有效地重构索引并降低可搜索向量的维数的工具来克服这个问题。使用这种方法需要牺牲准确性,但会显着提高搜索处理速度。

OpenSearch 利用的近似 k-NN 搜索方法使用 nmslib、faiss 和 Lucene 库中的近似最近邻 (ANN) 算法来支持 k-NN 搜索。这些搜索方法采用 ANN 来改善大型数据集的搜索延迟。在 k-NN 插件提供的三种搜索方法中,此方法为大型数据集提供了最佳的搜索可扩展性。当数据集达到数十万个向量时,此方法是首选方法。

k-NN 插件在索引期间为每个 knn 向量字段/Lucene 段对构建向量的本机库索引,可用于在搜索期间有效地查找查询向量的 k 最近邻。

由于本机库索引是在索引期间构建的,因此不可能对索引应用过滤器然后使用此搜索方法。所有过滤器都应用于近似最近邻搜索产生的结果。

示例

要使用 k-NN 插件的近似搜索功能,您必须首先创建一个 k-NN 索引,并将 index.knn 设置为 true 。此设置告诉插件为索引创建本机库索引。

接下来,您必须添加一个或多个 knn_vector 数据类型的字段。此示例创建一个包含两个 knn_vector 字段的索引,一个使用 faiss 字段,另一个使用 nmslib 字段:

创建KNN字段索引

PUT my-knn-index-1
{"settings": {"index": {"knn": true,"knn.algo_param.ef_search": 100}},"mappings": {"properties": {"my_vector1": {"type": "knn_vector","dimension": 2,"method": {"name": "hnsw","space_type": "l2","engine": "nmslib","parameters": {"ef_construction": 128,"m": 24}}},"my_vector2": {"type": "knn_vector","dimension": 4,"method": {"name": "hnsw","space_type": "innerproduct","engine": "faiss","parameters": {"ef_construction": 256,"m": 48}}}}}
}

knn_vector 数据类型支持浮点数向量,对于 nmslib 和 faiss 引擎,该向量的维度计数最多为 16,000,由维度映射参数设置。 Lucene 库的最大维度数为 1,024。

添加数据

POST _bulk
{ "index": { "_index": "my-knn-index-1", "_id": "1" } }
{ "my_vector1": [1.5, 2.5], "price": 12.2 }
{ "index": { "_index": "my-knn-index-1", "_id": "2" } }
{ "my_vector1": [2.5, 3.5], "price": 7.1 }
{ "index": { "_index": "my-knn-index-1", "_id": "3" } }
{ "my_vector1": [3.5, 4.5], "price": 12.9 }
{ "index": { "_index": "my-knn-index-1", "_id": "4" } }
{ "my_vector1": [5.5, 6.5], "price": 1.2 }
{ "index": { "_index": "my-knn-index-1", "_id": "5" } }
{ "my_vector1": [4.5, 5.5], "price": 3.7 }
{ "index": { "_index": "my-knn-index-1", "_id": "6" } }
{ "my_vector2": [1.5, 5.5, 4.5, 6.4], "price": 10.3 }
{ "index": { "_index": "my-knn-index-1", "_id": "7" } }
{ "my_vector2": [2.5, 3.5, 5.6, 6.7], "price": 5.5 }
{ "index": { "_index": "my-knn-index-1", "_id": "8" } }
{ "my_vector2": [4.5, 5.5, 6.7, 3.7], "price": 4.4 }
{ "index": { "_index": "my-knn-index-1", "_id": "9" } }
{ "my_vector2": [1.5, 5.5, 4.5, 6.4], "price": 8.9 }

近似KNN查询

GET my-knn-index-1/_search
{"size": 2,"query": {"knn": {"my_vector2": {"vector": [2, 3, 5, 6],"k": 2}}}
}

k 是每个图的搜索将返回的邻居数量。您还必须包含 size 选项,该选项指示查询实际返回的结果数量。该插件返回每个分片(和每个段)的 k 数量的结果以及整个查询的 size 数量的结果。该插件支持的最大 k 值为 10,000。

带过滤器的k-NN搜索

1.高效的 k-NN 过滤:此方法在 k-NN 搜索期间应用过滤,而不是在 k-NN 搜索之前或之后,这确保返回 k 结果(如果至少有 k 总计结果)。此方法由以下引擎支持:

  • 具有分层可导航小世界 (HNSW) 算法的 Lucene 引擎(k-NN 插件版本 2.4 及更高版本)
  • 具有 HNSW 算法(k-NN 插件版本 2.9 及更高版本)或 IVF 算法(k-NN 插件版本 2.10 及更高版本)的 Faiss 引擎

2.后过滤:由于它是在 k-NN 搜索之后执行的,因此此方法可能会返回明显少于限制性过滤器的 k 结果。您可以为此方法使用以下两种过滤策略:

  • 布尔后置过滤器:此方法运行近似最近邻 (ANN) 搜索,然后对结果应用过滤器。两个查询部分独立执行,然后根据查询中提供的查询运算符( shouldmust 等)组合结果。
  • post_filter 参数:此方法对完整数据集运行 ANN 搜索,然后将过滤器应用于 k-NN 结果。

3.评分脚本过滤器:此方法涉及预过滤文档集,然后对过滤后的子集运行精确的 k-NN 搜索。当过滤的子集很大时,它可能具有高延迟并且无法扩展。

下表总结了前面的过滤用例。

Filter何时应用过滤器搜索类型支持的引擎和方法在哪里放置 filter 子句
Efficient k-NN filtering 高效的 k-NN 过滤搜索期间(预过滤和后过滤的混合)Approximate 近似- lucene (hnsw) - lucene ( hnsw ) - faiss (hnsw, ivf) - faisshnswivf在 k-NN 查询子句内。
Boolean filter 布尔过滤器After search (post-filtering) 搜索后(后过滤)Approximate 近似- lucene - nmslib - faiss在 k-NN 查询子句之外。必须是叶子句。
post_filter 参数After search (post-filtering) 搜索后(后过滤)Approximate 近似- lucene - nmslib - faissOutside the k-NN query clause. 在 k-NN 查询子句之外。
Scoring script filter 评分脚本过滤器Before search (pre-filtering) 搜索前(预过滤)Exact 精确N/A在脚本分数查询子句内。

过滤搜索优化

一旦您估计了索引中的文档数量、过滤器的限制性以及所需的最近邻居数量,请使用下表选择可优化召回或延迟的过滤方法。

索引中的文档数过滤器返回的文档百分比k用于提高召回率的过滤方法用于降低延迟的过滤方法
10M2.5100高效的 k-NN 过滤/评分脚本评分脚本
10M38100高效的 k-NN 过滤高效的 k-NN 过滤
10M80100高效的 k-NN 过滤高效的 k-NN 过滤
1M2.5100高效的 k-NN 过滤/评分脚本评分脚本
1M38100高效的 k-NN 过滤高效的 k-NN 过滤
1M80100高效的 k-NN 过滤高效的 k-NN 过滤

这篇关于从零开发短视频电商 OpenSearch k-NN插件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/434034

相关文章

使用Python开发一个带EPUB转换功能的Markdown编辑器

《使用Python开发一个带EPUB转换功能的Markdown编辑器》Markdown因其简单易用和强大的格式支持,成为了写作者、开发者及内容创作者的首选格式,本文将通过Python开发一个Markd... 目录应用概览代码结构与核心组件1. 初始化与布局 (__init__)2. 工具栏 (setup_t

Spring Shell 命令行实现交互式Shell应用开发

《SpringShell命令行实现交互式Shell应用开发》本文主要介绍了SpringShell命令行实现交互式Shell应用开发,能够帮助开发者快速构建功能丰富的命令行应用程序,具有一定的参考价... 目录引言一、Spring Shell概述二、创建命令类三、命令参数处理四、命令分组与帮助系统五、自定义S

pytorch之torch.flatten()和torch.nn.Flatten()的用法

《pytorch之torch.flatten()和torch.nn.Flatten()的用法》:本文主要介绍pytorch之torch.flatten()和torch.nn.Flatten()的用... 目录torch.flatten()和torch.nn.Flatten()的用法下面举例说明总结torch

基于Python和MoviePy实现照片管理和视频合成工具

《基于Python和MoviePy实现照片管理和视频合成工具》在这篇博客中,我们将详细剖析一个基于Python的图形界面应用程序,该程序使用wxPython构建用户界面,并结合MoviePy、Pill... 目录引言项目概述代码结构分析1. 导入和依赖2. 主类:PhotoManager初始化方法:__in

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

使用Python开发一个简单的本地图片服务器

《使用Python开发一个简单的本地图片服务器》本文介绍了如何结合wxPython构建的图形用户界面GUI和Python内建的Web服务器功能,在本地网络中搭建一个私人的,即开即用的网页相册,文中的示... 目录项目目标核心技术栈代码深度解析完整代码工作流程主要功能与优势潜在改进与思考运行结果总结你是否曾经

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优