当前位置: 首页 > news >正文

推荐算法:HNSW【推荐出与用户搜索的类似的/用户感兴趣的商品】

HNSW算法概述

HNSW(Hierarchical Navigable Small Word)算法算是目前推荐领域里面常用的ANN(Approximate Nearest Neighbor)算法了。其目的就是在极大量的候选集当中如何快速地找到一个query最近邻的k个元素

要找到一个query的k个最近邻元素,一个朴素的思想就是我去计算这个query和所有的总量N 个候选元素的距离,然后选择其中的前k 个最小元素,这个经典算法的算法复杂度是O(Nlog(k)),显然这个算法复杂度实在是太高了,无法适用于实际的使用场景。

而要解决这个问题,可以有多种实现方法,这里所要说的HNSW算法就是目前比较常用的一种搜索算法,它算是其前作NSW算法的一个升级版本,但是两者的本质都是基于一个朴素的思路,就是通过图连接的方式给所有的N 个候选元素事先地定义好一个图连接关系,从而可以将前述的算法复杂度当中的N 的部分给减小掉,从而优化整体的检索效率

其整体的一个图结果可以用下图进行表达:

解决的问题做高效率相似性查找。推荐系统中,如何找到与用户query最相近的几个item,然后推荐出去【也就是推荐出与用户搜索的类似的/用户感兴趣的商品】

解决方法有:Annoy,KD-Tree, LSH, PQ,NSW, HNSW等。

近似最近邻搜索算法(Approximate Nearest Neighbor Search,ANNS)发展:近邻图(Proximity Graph)–> NSW --> Skip List --> HNSW

近似最近邻搜索算法(Approximate Nearest Neighbor Search,ANNS)

1. 近邻图(Proximity Graph)

近邻图(Proximity Graph): 最朴素的图算法

思路: 构建一张图, 每一个顶点连接着最近的 N 个顶点。 Target (红点)是待查询的向量。在搜索时, 选择任意一个顶点出发。 首先遍历它的友节点, 找到距离与 Target 最近的某一节点, 将其设置为起始节点, 再从它的友节点出发进行遍历, 反复迭代, 不断逼近, 最后找到与 Target 距离最近的节点时搜索结束。

存在的问题:

  1. 图中的K点无法被查询到。
  2. 如果要查找距离Target (红点)最近的topK个点, 而如果点之间无连线, 将影响查找效率。
  3. D点有这么多友节点吗? 增加了构造复杂度。谁是谁的友节点如何确定?
  4. 如果初始点选择地不好(比如很远),将进行多步查找。

2. NSW算法原理

NSW,即没有分层的可导航小世界的结构(Navigable-Small-World-Graph )。

针对上面的问题,解决办法:

  1. 某些点无法被查询到 -> 规定构图时所有节点必须有友节点。
  2. 相似点不相邻的问题 -> 规定构图时所有距离相近到一定程度的节点必须互为友节点。
  3. 关于某些点有过多友节点 -> 规定限制每个节点的友节点数量。
  4. 初始点选择地很远 -> 增加高速公路机制。

2.1 NSW构图算法

图中插入新节点时,通过随机存在的一个节点出发查找到距离新节点最近的m个节点(规定最多m个友节点,m由用户设置),连接新节点到这最近的m个节点。节点的友节点在新的节点插入的过程中会不断地被更新。

m=3(每个点在插入时找3个紧邻友点)。

第1次构造:图为空,随机插入A,初始点为A。图中只有A,故无法挑选友节点。插入B,B点只有A点可选,所以连接BA。

第2次构造:插入F,F只有A和B可以选,所以连接FA,FB。

第3次构造:插入C,C点只有A,B,F可选,连接CA,CB,CF。

第4次构造:插入E,从A,B,C,F任意一点出发,计算出发点与E的距离和出发点的所有“友节点”和E的距离,选出最近的一点作为新的出发点,如果选出的点就是出发点本身,那么看我们的m等于几,如果不够数,就继续找第二近的点或者第三近的点,本着不找重复点的原则,直到找到3个近点为止。找到了E的三个近点,连接EA,EC,EF。

第5次构造:插入D,与E点的插入一模一样,都是在“现成”的图中查找到3个最近的节点作为“友节点”,并做连接。

第6次构造:插入G,与E点的插入一模一样,都是在“现成”的图中查找到3个最近的节点作为“友节点”,并做连接。

在图构建的早期,很有可能构建出“高速公路”。

第n次构造:在这个图的基础上再插入6个点,这6个点有3个和E很近,有3个和A很近,那么距离E最近的3个点中没有A,距离A最近的3个点中也没有E,但因为A和E是构图早期添加的点,A和E有了连线,我们管这种连线叫“高速公路”,在查找时可以提高查找效率(当进入点为E,待查找距离A很近时,我们可以通过AE连线从E直接到达A,而不是一小步一小步分多次跳转到A)。

结论:一个点,越早插入就越容易形成与之相关的“高速公路”连接,越晚插入就越难形成与之相关的“高速公路”连接。

这个算法设计的妙处就在于扔掉德劳内三角构图法,改用“无脑添加”(NSW朴素插入算法),降低了构图算法时间复杂度的同时还带来了数量有限的“高速公路”,加速了查找。

2.2 NSW查找算法

NSW.png

图中的边有两个不同的目的:

  1. Short-range edges,用作贪婪搜索算法所需的近似 Delaunay 图。
  2. Long-range edges,用于贪婪搜索的对数缩放。负责构造图形的可导航小世界(NSW)属性。

优化查找:

  1. 建立一个废弃列表visitedSet,在一次查找任务中遍历过的点不再遍历。
  2. 建立一个动态列表result,把距离查找点最近的n个点存储在表中,并行地对这n个点进行同时计算“友节点”和待查找点的距离,在这些“友节点”中选择n个点与动态列表中的n个点进行并集操作,在并集中选出n个最近的友点,更新动态列表。

推荐算法:HNSW算法简介-CSDN博客

检索模型-粗排HNSW_hnsw模型-CSDN博客

相关文章:

推荐算法:HNSW【推荐出与用户搜索的类似的/用户感兴趣的商品】

HNSW算法概述 HNSW(Hierarchical Navigable Small Word)算法算是目前推荐领域里面常用的ANN(Approximate Nearest Neighbor)算法了。其目的就是在极大量的候选集当中如何快速地找到一个query最近邻的k个元素。 要找到一个query的…...

C++ //例3.14 找出100~200间的全部素数。

C程序设计 &#xff08;第三版&#xff09; 谭浩强 例3.14 例3.14 找出100~200间的全部素数。 IDE工具&#xff1a;VS2010 Note: 使用不同的IDE工具可能有部分差异。 代码块 方法&#xff1a;使用函数的模块化设计 #include <iostream> #include <iomanip> #i…...

虚幻学习笔记11—C++结构体、枚举与蓝图的通信

一、前言 结构体的定义和枚举类似&#xff0c;枚举的定义有两种方式。区别是结构体必须以“F”开头命名&#xff0c;而枚举不用。 额外再讲了一下蓝图生成时暴露变量的方法。 二、实现 2.1、结构体 1、定义结构体 代码如下&#xff0c;注意这个定义的代码一定要在“UCLASS()”…...

【android开发-19】android中内容提供者contentProvider用法讲解

1&#xff0c;内容URI 在Android系统中&#xff0c;Content URI是一种用于唯一标识和访问应用程序中的数据的方法。它由Android系统提供&#xff0c;通过Content Provider来实现数据的共享和访问。 Content URI使用特定的格式来标识数据&#xff0c;通常以"content://&qu…...

浅谈排序——快速排序(最常用的排序)

快速排序&#xff08;Quick Sort&#xff09;是一种常见的排序算法&#xff0c;由英国计算机科学家东尼霍尔&#xff08;Tony Hoare&#xff09;在1960年发明。这是一种分治算法&#xff0c;基本思想是通过一趟排序将要排序的数据分割成独立的两部分&#xff0c;其中一部分的所…...

Springboot项目实现简单的文件服务器,实现文件上传+图片及文件回显

文章目录 写在前面一、配置1、application.properties2、webMvc配置3、查看效果 二、文件上传 写在前面 平常工作中的项目&#xff0c;上传的文件一般都会传到对象存储云服务中。当接手一个小项目&#xff0c;如何自己动手搭建一个文件服务器&#xff0c;实现图片、文件的回显…...

5V低压步进电机驱动芯片GC6150,应用于摄像机,机器人 医疗器械等产品中。具有低噪声、低振动的特点

GC6150是双通道5V低压步进电机驱动器&#xff0c;具有低噪声、低振动的特点&#xff0c;特别适用于相机变焦对焦系统、万向架、摇头机等精度、低噪声STM控制系统&#xff0c;该芯片为每个通道集成了一个256微步的驱动器。通过SPI & T2C接口&#xff0c;客户可以方使地调整驱…...

3D Web轻量引擎HOOPS Communicator如何实现对大模型的渲染支持?

除了读取轻松外&#xff0c;HOOPS Communicator对超大模型的支持效果也非常好&#xff0c;它可以支持30GB的包含70万个零件和3.5亿个三角面的Catia装配模型&#xff01; 那么它是如何来实现对大模型的支持呢&#xff1f; 我们将从以下几个方面与大家分享&#xff1a;最低帧率…...

『 Linux 』进程地址空间概念

文章目录 &#x1fad9; 前言&#x1fad9; 进程地址空间是什么&#x1fad9; 写时拷贝&#x1fad9; 可执行程序中的虚拟地址&#x1fad9; 物理地址分布方式 &#x1fad9; 前言 在c/C中存在一种内存的概念; 一般来说一个内存的空间分布包括栈区,堆区,代码段等等; 且内存是…...

PySpark大数据处理详细教程

欢迎各位数据爱好者&#xff01;今天&#xff0c;我很高兴与您分享我的最新博客&#xff0c;专注于探索 PySpark DataFrame 的强大功能。无论您是刚入门的数据分析师&#xff0c;还是寻求深入了解大数据技术的专业人士&#xff0c;这里都有丰富的知识和实用的技巧等着您。让我们…...

三(五)ts非基础类型(对象)

在ts里面定义对象的方式也有很多。 普通定义 let obj1:{} {} // obj1.name fufu 报错&#xff0c;只能定义为空对象且不能修改 // 但是可以在赋初始值的时候直接添加属性&#xff0c;这是ts在类型推断时&#xff0c;它会宽容地匹配对象的结构。 let obj2:{} {name: fufu}…...

HeartBeat监控Redis状态

目录 一、概述 二、 安装部署 三、配置 四、启动服务 五、查看数据 一、概述 使用heartbeat可以实现在kibana界面对redis服务存活状态进行观察&#xff0c;如有必要&#xff0c;也可在服务宕机后立即向相关人员发送邮件通知 二、 安装部署 参照文章&#xff1a;HeartBeat监…...

FairGuard无缝兼容小米澎湃OS、ColorOS 14 、鸿蒙4!

随着移动互联网时代的发展&#xff0c;各大手机厂商为打造生态系统、构建自身的技术壁垒&#xff0c;纷纷投身自研操作系统。 而对于一款游戏安全产品&#xff0c;在不同操作系统下&#xff0c;是否能够无缝兼容并且提供稳定的、高强度的加密保护&#xff0c;成了行业的一大痛…...

【Copilot】Edge浏览器的copilot消失了怎么办

这种原因&#xff0c;可能是因为你的ip地址的不在这个服务的允许范围内。你需要重新使用之前出现copilot的ip地址&#xff0c;然后退出edge的账号&#xff0c;重新登录一遍&#xff0c;最后重启edge&#xff0c;就能够使得copilot侧边栏重新出现了。...

C++入门【6-C++ 修饰符类型】

C 修饰符类型 C 允许在 char、int 和 double 数据类型前放置修饰符。 修饰符是用于改变变量类型的行为的关键字&#xff0c;它更能满足各种情境的需求。 下面列出了数据类型修饰符&#xff1a; signed&#xff1a;表示变量可以存储负数。对于整型变量来说&#xff0c;signe…...

STP笔记总结

STP --- 生成树协议 STP&#xff08;Spanning Tree Protocol&#xff0c;生成树协议&#xff09;是根据 IEEE802.1D标准建立的&#xff0c;用于在局域网中消除数据链路层环路的协议。运行STP协议的设备通过彼此交互信息发现网络中的环路&#xff0c;并有选择地对某些端口进行阻…...

Qt开发 之 记一次安装 Qt5.12.12 安卓环境的失败案例

文章目录 1、安装Qt2、安卓开发的组合套件2.1、CSDN地址2.2、官网地址2.3、发现老方法不适用了 3、尝试用新方法解决3.1、先安装JDK&#xff0c;搞定JDK环境变量3.1.1、安装jdk3.1.2、确定jdk安装路径3.1.3、打开系统环境变量配置3.1.4、配置系统环境变量3.1.5、验证JDK环境变量…...

基于SpringBoot的就业信息管理系统设计与实现(源码+数据库+文档)

摘 要 在新冠肺炎疫情的影响下&#xff0c;大学生的就业问题已经变成了一个引起人们普遍重视的社会焦点问题。在这次疫情的冲击之下&#xff0c;大学生的就业市场的供求双方都受到了不同程度的影响&#xff0c;大学生的就业情况并不十分乐观。目前&#xff0c;各种招聘平台上…...

Java面试整理(四)Java IO流

我记得自己刚开始学Java的时候,都听过师兄的分享,说IO流是很重要,而且很难。 自己正式接触之后,其实IO流这块知识并不是特别难,而且随着IT的发展,IO流这块反而用得不是很多。特别是在应用开发这个层面,用得更少。 当然,可能会有朋友跳出来说“这怎么可能?你不懂Java吧…...

《安富莱嵌入式周报》第328期:自主微型机器人,火星探测器发射前失误故障分析,微软推出12周24期免费AI课程,炫酷3D LED点阵设计,MDK5.39发布

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 更新一期视频教程&#xff1a; 【实战技能】 单步运行源码分析&#xff0c;一期视频整明白FreeRTOS内核源码框架和运行…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

探索Selenium:自动化测试的神奇钥匙

目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...

在 Visual Studio Code 中使用驭码 CodeRider 提升开发效率:以冒泡排序为例

目录 前言1 插件安装与配置1.1 安装驭码 CodeRider1.2 初始配置建议 2 示例代码&#xff1a;冒泡排序3 驭码 CodeRider 功能详解3.1 功能概览3.2 代码解释功能3.3 自动注释生成3.4 逻辑修改功能3.5 单元测试自动生成3.6 代码优化建议 4 驭码的实际应用建议5 常见问题与解决建议…...

Matlab实现任意伪彩色图像可视化显示

Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中&#xff0c;如何展示好看的实验结果图像非常重要&#xff01;&#xff01;&#xff01; 1、灰度原始图像 灰度图像每个像素点只有一个数值&#xff0c;代表该点的​​亮度&#xff08;或…...

6.9-QT模拟计算器

源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...