Gorse Learning

参考的资料:

Gorse 推荐系统入门:从零到一构建推荐引擎 - 技术漫游 - 博客园

gorse-io/gorse | DeepWiki

主页 | Gorse

入门

什么是推荐系统

三个要素:

  • 记录行为
  • 理解兴趣
  • 预测可能喜欢

启动与使用

直接使用 docker 启动(参阅官方文档)。

基于 Web 的,直接访问 localhost:8088 可以浏览。

使用 curl 进行插入数据、创建物品、插入反馈、获取推荐等。

核心工作原理的概述

四个核心概念:

  • 用户
    • 基础信息:ID、标签等(如年龄、性别)
    • 行为历史:浏览、点击、购买...
  • 物品
    • 基础信息:ID、标签
    • 统计数据:热度、评分
  • 反馈
    • 用户+物品+类型+时间
  • 推荐
    • 根据历史行为预测用户可能喜欢的物品

流程图:

  1. 用户产生行为
  2. 系统记录反馈
  3. 模型定期执行分析、训练
  4. 生成推荐
  5. 用户看到推荐
  6. 循环迭代,回到 1

Gorse 的推荐策略:多源融合

  1. 协同过滤:找到相似用户,推荐他们喜欢的物品
  2. 物品相似:推荐和用户历史物品相似的其他物品
  3. 热门推荐:推荐最热门的物品
  4. 最新推荐:字面意思

所谓融合策略:推荐结果 = 30% 协同过滤 + 30% 物品相似 + 20% 热门推荐 + 20% 最新推荐

Gorse 的架构设计

三层架构:

flowchart TD
    A["用户 / 应用<br/>Web · App · 小程序"]
    B["Server 节点<br/>RESTful API + 实时推荐"]
    C["Master 节点<br/>模型训练 + 任务调度 + Dashboard"]
    D["Worker 节点(多个)<br/>离线计算 + 批量推荐"]
    E["存储层<br/>MySQL + Redis<br/>用户数据 + 物品数据 + 推荐缓存"]

    A -->|HTTP / HTTPS| B
    B -->|gRPC| C
    C -->|gRPC| D
    D --> E

关于 gRPC

RPC = Remote Procedure Call,远程过程调用。核心思想就是「像调用本地函数一样调用另一台机器上的函数」。

gRPC = Google 开源的一套 RPC 框架。

Protobuf = gRPC 通常使用的数据描述和序列化格式。你会写一个 .proto 文件定义「有哪些函数、参数是什么、返回值是什么」。

比如 Gorse 架构里:

Server  ──gRPC──>  Master
Master  ──gRPC──>  Worker

假设 Master 提供一个函数:

GetModel(name string) Model

Server 想调用它。但问题是:Master 和 Server 是两个独立进程,甚至可能运行在不同机器上,Server 显然不能直接:

model := master.GetModel("ranking")

gRPC 做的事情,就是让这种远程调用看起来很像普通函数调用

model, err := client.GetModel(ctx, request)

实际上背后发生的是:

Server
  │
  │ 调用 GetModel(...)
  ↓
gRPC Client
  │
  │ 序列化成 Protobuf
  │ 通过 HTTP/2 发送
  ↓
网络
  ↓
Master 上的 gRPC Server
  │
  │ 反序列化
  ↓
真正执行 GetModel(...)

Master 节点

可以理解为 Gorse 架构的大脑。

  • 模型训练
  • AutoML: Automated Machine Learning(自动机器学习)
  • 任务调度,触发 Worker
  • Dashboard:监控、数据管理

Worker 节点

理解为 Gorse 架构的手脚。

  • 批量推荐:为每个用户生成推荐列表
  • 相似度计算:计算物品之间的相似,计算用户之间的相似度
  • 水平扩展:启动多个 Worker,负载均衡

Server 节点

理解为「嘴巴」。

  • 提供 RESTful API
  • 实时推荐
  • 在线更新

综合

flowchart LR
    A["用户行为"] --> B["Server"]
    B --> C["DataStore<br/>MySQL"]

    C --> D["Master<br/>定期加载数据"]
    D --> E["训练模型"]

    E --> F["Worker<br/>计算推荐"]
    F --> G["CacheStore<br/>Redis"]

    G --> H["Server"]
    H --> I["返回用户"]

    %% 局部调整布局
    subgraph Train[" "]
        direction TB
        D --> E
    end

    subgraph Recommend[" "]
        direction TB
        F --> G
    end

理解 Gorse 的管道(pipeline)

管道 | Gorse

  • 数据源输入输入层之后,传入检索层
  • 检索层由多个推荐器构成,为用户生成候选物品
  • 排序层合并来自不同推荐器的所有输出,删除用户已经看过的物品(已读物品),并根据用户与剩余物品互动的可能性对其进行评分

默认的管道是只推荐最新物品。

管道中的缓存

以下中间结果被缓存并定期更新:

  • 用户到用户推荐器的用户邻居。
    • 简单来说,用户 A 的相似用户是 B C D,那么这个结果会被缓存
  • 物品到物品推荐器的物品邻居。
    • 和上面同理,相似物品缓存
  • 非个性化推荐器的结果。
    • 和具体用户没有太大关系的内容,比如说最新榜、热门榜
  • 每个用户的排序器输出
    • 就是最后排序器输出的结果

Gorse 工作原理

管道以分布式方式执行。Gorse 中有三种类型的节点:主节点、工作节点和服务器节点。也就是上面说的 Master Worker Server,不再赘述。

深入 Gorse 推荐系统:数据结构与存储层设计剖析

深入 Gorse 推荐系统:数据结构与存储层设计剖析 - 技术漫游 - 博客园

我感觉也是这个作者的 AI 文章自己洗了一遍...总之大概看看吧。

字符串->索引的映射

显然我们会有大量的 JSON(也可以是 Go 里面的 map[string][]),里面都是字符串作为 key。

字符串作为 key,效率很低(主要是哈希比较带来的开销是 $O(len(string))$