查看原文
其他

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

Jina AI 工程团队 Jina AI 2023-03-21

在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 是一个可以同时表示文本和图像的神经网络模型,因此我们可以使用 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,这个数据集包含带有图片和元数据(例如品牌、国家和颜色)的商品项。


我们的 demo 以展示为主,所以我们只需从 Jina Cloud 下载该数据集的一个子集即可,并将数据集预处理成 DocArray 格式。

首先,使用终端向 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 围巾,蓝色”:


还有其余推荐的一些商品:



它们是如何满足用户过滤器的呢?让我们检查推荐列表中的第三项,并用过滤器 color='Navy' 来寻找最佳的匹配结果:


recommended = view(recommended[2], view_history, color='Navy')

飞起来的推荐速度

本项目的数据集和源代码都已经开源,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


更多资料

💻 GitHub: github.com/docarray/docarray

📖 文档docarray.jina.ai

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

🧑‍💻 本项目地址https://github.com/jina-ai/product-recommendation-redis-docarray

更多技术文章

Jina AI创始人肖涵博士解读多模态AI的范式变革

语音生成图像任务|跨模态实践教程

Jina AI正式将DocArray捐赠给Linux基金会


点击“阅读原文”,即刻了解 Jina

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存