DocArray 和 Redis 联手,让推荐系统飞起来

2023-11-04

在DocArray中使用Redis后端,基于向量相似性搜索可以快速搭建一个实时商品推荐系统。现在,跟上我们的脚步,一起了解搭建系统的关键步骤,并且深入了解推荐的原理吧!

推荐系统会根据用户画像、历史行为(如购买、喜欢、浏览等),给用户的兴趣建模,主动提供个性化推荐。它可以提升转化率并保持用户忠诚度,因而被广泛应用在各类电子商务网站。

图片来自:https://www.mdpi.com/2076-3417/10/16/5510/htm

过去,构建并部署推荐系统通常是一个非常复杂的任务。但现在,通过在 DocArray 中使用 Redis 后端,使用最新的向量相似度搜索技术,可以快速构建实时商品推荐系统。

为电子商务网站构建推荐系统涉及很多挑战,以下列出了一些要考虑的问题:

  • 定制化: 用户希望可以按照价格范围、品牌和尺寸等要素筛选商品,所以推荐系统应该满足用户的需求。
  • 多模态:商品清单不应该只是文本描述,还可以包含图片、视频、音频或者 3D 网格。在推荐时,所有模态的信息都应该被充分利用。
  • 实时性:推荐结果应该快速返回,否则就没有意义了。
  • 数据量:网站拥有的客户和商品越多,有效推荐的难度就越高。即便使用规模很大的数据集,计算过程也应该迅速完成。

随着技术的不断发展,用户需求的不断增长,构建推荐系统的方法也应该不断提升。

在本文中,我们将向您展示如何使用最新的向量搜索技术构建实时商品推荐系统,并使用自定义过滤器来提供个性化推荐。我们使用的工具包括 Redis 和 DocArray。

from docarray import DocumentArray

redis_da = DocumentArray(storage='redis')

在 DocArray 中使用 Redis 后端非常简单方便,更多信息可以查阅文档。

https://docarray.jina.ai/advanced/document-store/redis/

如何构建推荐系统?

在构建推荐系统时,有一些常见的方法:

  • 协同过滤推荐: 基于相似用户的偏好来推荐商品。
  • 基于内容推荐: 为用户建立特征向量,然后根据向量间的相似度来预测用户可能感兴趣的商品。
  • 混合算法推荐:混合了协同过滤和基于内容的过滤算法,以及其他算法来实现推荐功能。

本文重点是改进基于内容的过滤算法。如果您对此算法不熟悉,可以阅读一下谷歌的基于内容的过滤算法概述。

https://developers.google.com/machine-learning/recommendation/content-based/basics

在实现基于内容的过滤算法时,需要考虑两个因素。

首先,在为用户和商品建立特征向量时,充分利用所有模态数据是非常重要的。仅仅依靠关键词或者一组特征可能无法有效地代表复杂的数据。因此,使用前沿的 AI 模型是很有必要的,它们可以将复杂的多模态数据表示为嵌入向量 embedding。

CLIP 是一个可以同时表示文本和图像的神经网络模型,因此我们可以使用<a href="http://http://mp.weixin.qq.com/s?__biz=MzkyODIxMjczMA==&mid=2247494451&idx=3&sn=def4556c7f945b0052fbd2793614dd3a&chksm=c21e98a6f56911b0d24680fda11674b616f2750aa4914f60c4fc2e713d11a37ae788e4501216&scene=21#wechat_redirect"> CLIP-as-service 作为推理引擎来支持我们的推荐系统。

其次,如果不能高效地计算向量相似度,计算过程可能会非常慢并且成本高昂。而且在批处理中提前计算用户和 item 间的向量相似度并不现实,因为我们的应用程序需要遵守用户过滤器,并提供低延迟推荐。所以在这个实时商品推荐系统里,我们需要使用高效算法,例如 Hierarchical Navigable Small World(HNSW) 来实时计算相似度。

这些技术都集成在向量数据库中,RediSearch 2.4 中提供向量搜索功能。因为 Redis 是一个内存数据库,所以推荐可以保证实时进行。

由于推荐系统包含 特征表示 和 向量相似度计算,所以我们需要一种数据结构跨越多模态数据和向量数据库之间的鸿沟。DocArray 就是不二之选,DocArray 提供了便捷的多模态数据处理功能,具备基于 Protobuf 提供高性能的网络传输性能,同时也为多种向量存储方案提供统一的 API 接口。

也就是说 DocArray 既支持多模态数据的处理、传输、存储,又可以作为通用向量数据库的客户端。在这个推荐系统中,DocArray 既可以用来表示用户和物品的信息,又可以对它们进行特征表示。更重要的,只需几行代码就可以轻松构建推荐系统。

DocArray 可以处理多模态数据,例如图像、视频、音频和 3D 网格,并且它可以将数据存储到不同的向量数据库中,如 Redis、ElasticSearch、 Weaviate、 Qdrant。

DocArray + Redis 的解决方案

我们已经为应用组装了 Redis、CLIP-as-service 和 DocArray,其中 Redis 用于向量相似性搜索,CLIP-as-service 用于编码文本和图片,DocArray 用来表示多模态 document 并存储到Redis。我们将应用这些技术来搭建一个基于内容过滤的推荐系统。

具体过程如下:

  1. 将数据集加载成 DocArray 格式。
  2. 使用 CLIP-as-service 编码商品图像,以此建立商品模型。
  3. 计算最近 K 次浏览商品的 embedding 的加权平均数,以此来建立用户画像。
  4. 索引 Redis 中的商品数据。
  5. 用 Redis 向量相似性搜索来推荐和用户浏览历史中最相似的商品,同时根据用户的偏好过滤这些结果。

安装 DocArray 和 Redis

首先需要配置 Redis 实例,你可以使用 Docker 创建一个本地的 Redis 实例:

docker run -d -p 6379:6379 redis/redis-stack:latest

接下来需要安装 DocArray、 Jina 和 clip-client:

pip install docarray[redis] jina clip-client

下载数据集

在以下的示例中我们使用的数据来自于 Amazon Berkeley Objects Dataset,这个数据集包含带有图片和元数据(例如品牌、国家和颜色)的商品项。

首先,使用终端向 Jina AI Cloud 发送身份验证:

jina auth login

接着,下载数据集:

from docarray import DocumentArray, Document
da = DocumentArray.pull('amazon-berkeley-objects-dataset', show_progress=True)

这会返回一个包含 Amazon Berkeley Objects 数据集样本的 DocumentArray 对象。使用summary() 可以获取对象概览:

da.summary()

╭────────────────────── Documents Summary ──────────────────────╮
│                                                               │
│   Type                   DocumentArrayInMemory                │
│   Length                 5809                                 │
│   Homogenous Documents   True                                 │
│   Common Attributes      ('id', 'mime_type', 'uri', 'tags')   │
│   Multimodal dataclass   False                                │
│                                                               │
╰───────────────────────────────────────────────────────────────╯
╭───────────────────── Attributes Summary ─────────────────────╮
│                                                              │
│   Attribute   Data type   #Unique values   Has empty value   │
│  ──────────────────────────────────────────────────────────  │
│   id          ('str',)    5809             False             │
│   mime_type   ('str',)    1                False             │
│   tags        ('dict',)   5809             False             │
│   uri         ('str',)    4848             False             │
│                                                              │
╰──────────────────────────────────────────────────────────────╯

我们可以用plot_image_sprites()方法来显示第一批商品的图像。

da[:12].plot_image_sprites()

每一个商品包含的元数据信息都在tags字段中,查看tags中的内容:

da[0].tags

{'height': '1926',
'country': 'CA',
'width': '1650',
'product_type': 'ACCESSORY',
'color': 'Blue',
'brand': 'Thirty Five Kent',
'item_name': "Thirty Five Kent Men's Cashmere Zig Zag Scarf, Blue"}

稍后,我们会使用元数据和用户的喜好过滤推荐结果。

创建 embedding

为了给我们的数据集创建embedding,我们需要用于 CLIP-as-service 的 token

jina auth token create fashion -e 30

然后就可以编码我们的数据了,一定要将创建的 token 发送给客户端对象:

from clip_client import Client

c = Client(
    'grpcs://api.clip.jina.ai:2096', credential={'Authorization': 'your-auth-token'}
)

encoded_da = c.encode(da, show_progress=True)

编码数据集需要几分钟,完成后,就可以继续下一步了。

使用 Redis 服务器

支持 DocumentArray

此时,我们的数据已经完成编码并准备索引。

为此,我们创建了一个连接 Redis 服务器的 DocumentArray 实例,记得指定正确的嵌入维度以及过滤列。

# Configure a new DocumentArray with a Redis document store
redis_da = DocumentArray(storage='redis', config={
    'n_dim': 768,
    'columns': {
        'color': 'str',
        'country': 'str',
        'product_type': 'str',
        'width': 'int',
        'height': 'int',
        'brand': 'str',
    }
})

# Index data
redis_da.extend(encoded_da)

详细信息,请参阅 DocArray 中的 Redis DocumentStore:

https://docarray.jina.ai/advanced/document-store/redis/

获取推荐结果

为了更好地理解推荐系统的运行逻辑,举个例子:小美想要购买一条围巾,并且逛了我们的商店。她最喜欢海军蓝色,预算在 100 元以下。我们的系统在推荐时应该综合考虑用户的要求和基于浏览历史的推荐item,尤其是最近查看的 item。因此,可以通过给最近浏览的 item 赋予更高的权重来组合 embedding。

import numpy as np

def recommend(view_history, color=None, country=None):
    embedding = np.average(
        [doc.embedding for doc in view_history],
        weights=range(len(view_history), 0, -1),
        axis=0
    )

    user_filter = ''
    
    if color:
        user_filter += f'@color:{color} '
    
    if country:
        user_filter += f'@country:{country} '
    
    return redis_da.find(embedding, filter=user_filter)

在商品视图展示推荐

为了在用户浏览商品的过程中展示相关推荐,我们需要以下三步:

  1. 展示商品的图片和描述。
  2. 将商品添加进最近 k 次浏览的商品列表中。
  3. 展示最近 k 次浏览商品的相关推荐。

可以用下面的函数实现以上三步:

k = 5
view_history = []

def view(item: Document, view_history, color=None, country=None):
    print(item.tags['item_name'], ':')
    item.display()
    view_history.insert(0, item)
    view_history = view_history[:k]
    recommendations = recommend(view_history, color=color, country=country)
    recommendations.plot_image_sprites()
    return recommendations

效果验证

让我们一起试试这个实时推荐系统,首先,查看店铺中的第一个商品及其推荐:

recommended = view(redis_da[0], view_history)

这张图展示了一条围巾,并且标着“Thirty Five Kent(品牌名)男士山羊绒 Zig Zag 围巾,蓝色”:

飞起来的推荐速度

本项目的数据集和源代码都已经开源,GitHub 地址:https://github.com/jina-ai/product-recommendation-redis-docarray

这个演示只是展示了向量相似性搜索是如何在实时推荐系统中满足用户的偏好以及过滤器的筛选的,但是它究竟快到什么程度呢?你可以在控制台中找到运行日志,日志中包含了推荐查询的延迟。

Retrieving products ... Retrieving products takes 0 seconds (0.01s)

这意味着推荐的计算仅仅只需要 10 毫秒左右。

当然对于推荐系统来说,无论是速度还是推荐的质量方面都有提升的空间,例如,我们可以用更复杂的算法建模用户画像和用户偏好。此外,我们还可以使用更复杂的数据,如 3D 模型和视频等等。这些就留给你们慢慢探索了。

下一步的探索!

向量相似性搜索是基于上下文语义的实时搜索技术,你可以继续探索:

  • 使用最前沿的 AI 模型将多模态数据编码成特征向量。
  • 使用向量数据库实时计算向量相似度,为了实现低时延,像 Redis 这样的内存数据库将成为推荐系统的理想选择。
  • DocArray提供了便捷的多模态数据处理功能,同时也为多种向量存储方案提供了统一的AP接口,使用 DocArray 能够能跨越不同数据类型之间的鸿沟,减少应用的数据传输成本。更多详情参阅 docarray.jina.ai

更多资料

GitHubhttp://github.com/docarray/docarray

文档:docarray.jina.ai

原文链接https://jina.ai/news/real-time-product-recommendation-using-redis-and-docarray/

‍ 本项目地址https://github.com/jina-ai/prod

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

DocArray 和 Redis 联手,让推荐系统飞起来 的相关文章

  • Docker&Celery - 错误:Pidfile (celerybeat.pid) 已存在

    应用程序包括 姜戈 雷迪斯 芹菜 码头工人 Postgres 在将项目合并到 docker 之前 一切都运行顺利且正常 但是一旦将其移入容器 就开始出现问题 起初它开始得很好 但过了一会儿我确实收到了以下错误 celery beat 1 E
  • Laravel - 缓存 Eloquent 并频繁更新

    是否可以对经常修改的对象使用缓存 例如 假设我们有一个 BlogPost 对象 并且有一个经常更改的 num of views 列 以及其他列 是否可以更新缓存和数据库中的 num of views 字段 而不破坏缓存对象并重新创建它 我可
  • 如何从 python 将无穷大传递给 redis?

    我正在使用 redis py 并希望将 inf 和 inf 与 ZRANGEBYSCORE 一起使用 我尝试使用 inf 的字符串和浮点来执行此操作 但它们返回一个空集 我怎样才能做到这一点 EDIT 我尝试执行以下命令 redis Str
  • connect-redis - 如何保护会话对象免受竞争条件影响

    我使用 nodejs 和 connect redis 来存储会话数据 我将用户数据保存在会话中 并在会话生命周期中使用它 我注意到两个更改会话数据的请求之间可能存在竞争条件 我尝试过使用 redis lock 来锁定会话 但这对我来说有点问
  • python 3.5 中的 json.loads 和 Redis

    我使用 json dumps 创建了一个 JSON 对象 并在 Redis 列表中将其 RPUSH ed 当使用 LRANGE redis lrange 返回 JSON 时 我收到一个二进制字符串 b si 00 ff 所以 json lo
  • 使用 AWS ElastiCache 请求中的 Airflow CROSSSLOT 密钥未散列到同一插槽错误

    我在 AWS ECS 上运行 apache airflow 1 8 1 并且有一个 AWS ElastiCache 集群 redis 3 2 4 运行 2 个分片 2 个启用多可用区的节点 集群 Redis 引擎 我已经验证气流可以毫无问题
  • 如何在节点redis客户端上设置读取超时?

    在 github 上我没有看到读取超时的选项 https github com NodeRedis node redis https github com NodeRedis node redis There s connect timeo
  • Spring Data Redis JedisConnectionException:流意外结束

    雷迪斯3 0 5Spring数据Redis 1 3 6绝地武士2 6 3 我们的 Web 应用程序通过 pub sub 从 Redis 接收数据 还以键 值对的形式在 Redis 上执行数据读 写 读 写发生在监听线程 独立监控线程和htt
  • 如何将 ActionController::Live 与 Resque + Redis 一起使用(用于聊天应用程序)

    我正在尝试为我的 Rails 应用程序构建聊天功能 我在用ActionController Live Puma Resque Redis为了这 所以基本上在这种情况下 redissubscribe方法正在后台运行 使用resque 到目前为
  • redis 阻塞直到 key 存在

    我是 Redis 新手 想知道是否有办法能够await get通过它的键来获取值 直到该键存在 最小代码 async def handler data await self fetch key async def fetch key ret
  • 通过 StackExchange.Redis 连接到 Redis Servier

    我尝试使用以下方法制作一个测试项目Redis https redis io服务器 通过 Virtual Box 安装在 Linux Ubuntu 虚拟机上 Linux 机器通过 Virtual Box 的桥接适配器与本地网络连接 Virtu
  • 如何测试我的 Redis 缓存是否正常工作?

    我已经安装了 django redis cache 和 redis py 我遵循了 Django 的缓存文档 据我所知 以下设置就是我所需要的 但我如何判断它是否正常工作 设置 py CACHES default BACKEND redis
  • 使用Redis从有限范围内生成唯一ID

    我有一些数据库项目 除了主键之外 还需要项目所属组的唯一索引 我们来调用属性nbr 以及将项目分组在一起并定义唯一范围的属性nbr 我们会打电话group This nbr必须在 1 N 范围内 并且may从外部源导入项目时进行设置 由于所
  • 使用 Sentinels 升级 Redis 的最佳实践?

    我有 3 个 Redis 节点 由 3 个哨兵监视 我进行了搜索 文档似乎不清楚如何最好地升级此类配置 我目前使用的是 3 0 6 版本 我想升级到最新的 5 0 5 我对这方面的程序有几个疑问 升级两个大版本可以吗 我在我们的暂存环境中执
  • redis - 使用哈希

    我正在使用 redis 为我的 Web 应用程序实现社交流和通知系统 我是 redis 的新手 我对哈希值及其效率有一些疑问 我读过这篇很棒的文章Instagram 帖子 http instagram engineering tumblr
  • 有没有办法让特定的key在集群模式下定位到特定的redis实例上?

    我想让我的多锁位于不同的redis实例上 我发现redission可以指定一个实例来执行命令 但是如果该命令与key相关 则指定的实例会将命令传输到另一个实例 你能给我一些建议吗 你可以 但这并不是微不足道的 首先 Redis 在键中使用大
  • 使用 Celery 通过 Gevent 进行实时、同步的外部 API 查询

    我正在开发一个 Web 应用程序 该应用程序将接收用户的请求 并且必须调用许多外部 API 来编写对该请求的答案 这可以直接从主 Web 线程使用 gevent 之类的东西来扇出请求来完成 或者 我在想 我可以将传入的请求放入队列中 并使用
  • 如何使redis中的“HSET”子键“过期”?

    我需要使 Redis 哈希中所有超过 1 个月的密钥过期 这不可能 https github com antirez redis issues 167 issuecomment 2559040 为了保持 Redis 简单 https git
  • 如何在Redis中只保存一个数据库?

    我是 Redis 新手 有一个与备份相关的问题 目前 我有一个实例在 Windows 服务器上运行 在这个实例中 我当前有一项 工作 将数据存储在一个数据库中 我不想备份这些数据 我必须创造一份新工作 我的第一个想法是将数据存储在另一个数据
  • 使用redis进行树形数据结构

    我需要为基于树的键值开发一个缓存系统 与Windows注册表编辑器非常相似 其中缓存键是字符串 表示树中到值的路径 可以是原始类型 int string bool double 等 或子树本身 例如 key root x y z w val

随机推荐

  • AIX系统文件压缩解压缩及性能诊断常用命令

    AIX系统文件压缩解压缩及性能诊断常用命令 磁带设备 顺序读取 文件类型 dev rmtx dev rmtx 1 dev rmtx 2 掌握 zip tar tape archive 保留原有权限 没有压缩 只是打包 创建 tar cvf
  • Basic Level 1091 N-自守数 (15分)

    题目 如果某个数 K 的平方乘以 N 以后 结果的末尾几位数等于 K 那么就称这个数为 N 自守数 例如 3 9 2 2 25392
  • 【python】excel文件(.xls文件)处理

    目录 概述 xlrd xlwt xlutils 概述 xlrd 用于读取文件 xlwt 用于写入文件 xlutils 是两个工具包的桥梁 也就是通过xlrd 读取 xls文件 然后通过xlutils 将文件内容交给xlwt处理并且保存 xl
  • 新手linux安装vasp_一步一步教你如何在linux 下安装VASP 【真的是从零开始】

    首先我是一个linux 小白 只接触过linux 的基本用法 听说VASP 编译很复杂 故想学习之 如果大神见了 请直接飘过 非常期待和大家互动交流 下面就直接进入主题 如何在linux 下面安装VASP 首先我想说说什么叫编译 为什么要编
  • 线阵相机、镜头及光源的选型

    线阵相机顾名思义就是取像是成线性的 它的传感器是成线型的 举个例子 比如面阵相机的分辨率是640 480就是说这个相机横向有640个像元 纵向有480个像元 而线阵相机分辨率只体现在横向 比如2048像素的线阵相机就是说横向有2048个像元
  • 颜色空间YUV简介

    YUV概念 YUV是被欧洲电视系统所采用的一种颜色编码方法 属于PAL Phase Alternation Line 是PAL和SECAM模拟彩色电视制式采用的颜色空间 其中的Y U V几个字母不是英文单词的组合词 Y代表亮度 其实Y就是图
  • java集合的copy

    java拷贝集合的方法有很多种 常用的比较简单的做法有两种 直接使用集合构造方法实现浅拷贝 这种方法只是保证list和listCopy的引用不一样 但是集合元素的引用时一样的 List
  • 生产管理MES系统框架

    1 总体框架描述 生产管理MES系统框架涵盖了涉及生产制造范畴内的所有业务管理内容 包括 产品生产数据 销售订单管理 材料需求计算和计划 采购管理 仓库物流管理 主生产计划 生产作业管理 生产过程物料加工 生产过程工装组装管理 品质管理 检
  • idea 插件的使用 进阶篇(个人收集使用中的)

    idea 插件的使用 进阶篇 个人收集使用中的 恭喜你 如果你已经看到这篇文章 证明在idear使用上已经初有小成 那么就要向着大神进发了 下边就是大神之路 插件的设置 在 IntelliJ IDEA 的安装讲解中我们其实已经知道 Inte
  • Quartz和Spring Task定时任务的简单应用和比较

    一 Quartz 引入quartz的jar包 配置文件中定义org springframework scheduling quartz MethodInvokingJobDetailFactoryBean 并指定它的targetObject
  • 理解HTML、CSS、javascript之间的关系

    理解HTML CSS javascript之间的关系 版权属于 博客园 牧云流 本文作者 牧云流 原文链接 https www cnblogs com dreamingbaobei p 10407626 html 网页主要有三部分组成 结构
  • pygame从入门到放弃(一)

    首先pip 那个pygame 然后看代码 临时写的 图片就不插了 防止舍友砍我 现在是凌晨 TOC 井字棋游戏 此代码基本能立于不败之地 import random 可视化输出 def draw Board board print prin
  • gcc中预定义的宏__GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__

    今天在看Linux系统编程这本书的代码的时候看到了 GNUC 不太清楚这个宏所以去查了一下 以此记录 GNU C预定义了一系列的宏 这些宏都是以双下划线开始的 这里只讲一下 GNUC GNUC MINOR GNUC PATCHLEVEL 完
  • vue中this.$set()的用法

    1 this set 的作用 向响应式对象中添加一个属性 并确保这个新属性同样是响应式的 且触发视图更新 this set 用于向响应式对象上添加新属性 因为 Vue 无法探测普通的新增属性 简单来说 就是我们在methods中给数据添加了
  • 整数拆分--

    题目描述 一个整数总可以拆分为2的幂的和 例如 7 1 2 4 7 1 2 2 2 7 1 1 1 4 7 1 1 1 2 2 7 1 1 1 1 1 2 7 1 1 1 1 1 1 1 总共有六种不同的拆分方式 再比如 4可以拆分成 4
  • [每日两题系列]刷算法题咯~~

    今日题目 最小栈 有效的括号 本系列所选题目均来自力扣或者牛客网站 所选题目主要是以其中的简单题为主 中等题为辅 包含少数困难题 原因是 本人目前能力还不够 开展这个系列的目的是督促自己 在暑假的时间里也要保持有一定的刷题量 拒绝摆烂 话不
  • FISCO BCOS 联盟链Max搭建

    FISCO BCOS Max版本 版本说明 为了能够支撑海量交易上链场景 v3 0 0推出了Max版本FISCO BCOS Max版本FISCO BCOS旨在提供海量存储服务 高性能可扩展的执行模块 高可用的故障恢复机制 Max版FISCO
  • ZYNQ #2 - Linux环境下烧录BOOT.BIN从QSPI-FLASH启动

    这篇博文讲述的是在Linux环境下 将生成的新BOOT BIN利用dd指令写入板上qspi flash中 板子从flash启动后 转至SD卡执行linux内核 这篇博文是为了之后不使用SD卡 将linux内核以及根文件系统放入emmc启动做
  • Web前端复习——Javascript(字符串)

    1 什么是字符串 字符串是多个字符组成的一个 只读 的集合 数组 注意 1 凡是数组对象中 不修改原对象的API 字符串都能用 比如 length属性 字符个数 用 i 访问每个字符 slice indexof 2 凡是数组对象中 直接修改
  • DocArray 和 Redis 联手,让推荐系统飞起来

    在DocArray中使用Redis后端 基于向量相似性搜索可以快速搭建一个实时商品推荐系统 现在 跟上我们的脚步 一起了解搭建系统的关键步骤 并且深入了解推荐的原理吧 推荐系统会根据用户画像 历史行为 如购买 喜欢 浏览等 给用户的兴趣建模