学习

使用 Redis 构建分析仪表盘应用

Ajeet Raina
作者
Ajeet Raina, Redis 前开发者增长经理

交互式分析仪表盘有多种用途。它们允许您共享数据,并为您提供所有重要信息,以便更快地做出改变游戏规则的决策。使用传统关系数据库构建实时动态仪表盘可能需要复杂的查询集。通过使用像 Redis 这样的 NoSQL 数据库,您只需使用少量 Redis 命令即可构建功能强大的交互式动态仪表盘。

Redis 是一个开源、内存中的键值数据存储,最常被用作主数据库、缓存、消息代理和队列。Redis 缓存提供亚毫秒级的响应时间,使得游戏、金融科技、广告科技、社交媒体、医疗保健和物联网等行业能够实现快速且功能强大的实时应用。本教程展示了一个使用 NodeJS (JavaScript) 编写的简单分析仪表盘应用,该应用使用了 Redis Bitmap 数据类型。

步骤 1. 准备环境#

  • 安装 Node - v12.19.0
  • 安装 NPM - v6.14.8
  • 安装 Docker - v19.03.13(可选)

步骤 2. 克隆仓库#

 git clone https://github.com/redis-developer/basic-analytics-dashboard-redis-bitmaps-nodejs

步骤 3. 设置后端#

首先,我们将设置一些环境变量。

进入 /server 文件夹 (cd ./server),然后执行以下命令

 cp .env.example .env

步骤 4. 安装依赖项#

 npm install

步骤 5. 运行 Docker Compose 安装 Redis#

 docker network create global
 docker-compose up -d --build

您可能需要在 docker 命令前加上 sudo。如果您不想使用 sudo,请创建一个名为 docker 的 Unix 组并将用户添加到其中。Docker 守护程序启动时,会创建一个可由 docker 组成员访问的 Unix 套接字。Redis 数据库启动并运行后,您可以使用 redis-cli 命令连接到它。

提示
  • 默认情况下,Redis 在端口 6379 上运行,但您可以在 docker compose 文件中指定备用主机端口来更改它。
  • 您可以使用 Redis 配置文件,并将其作为卷挂载到 docker compose YAML 文件中。
  • 您可以使用 redis-cli -h hostname -p port 命令连接到 Redis 实例。
  • 您可以运行 Redis INFO 命令,从 Redis 实例获取统计信息、指标和健康信息,例如缓存、内存统计信息、Redis 指标和已启用的模块。
  • 使用 Redis MONITOR 命令获取客户端发送到 Redis 的命令的实时视图。

步骤 6. 运行后端#

 npm run dev

步骤 7. 设置前端#

进入 /client 文件夹 (cd ./client),然后

 cp .env.example .env

步骤 8. 安装依赖项#

 npm install

步骤 9. 运行前端#

 npm run serve

工作原理是什么?#

数据如何存储:#

事件数据存储在各种键和各种数据类型中。

对于每个时间跨度

  • 年:例如 2021
  • 月:例如 2021-03(表示 2021 年 3 月)
  • 日:例如 2021-03-03(表示 2021 年 3 月 3 日)
  • 月内周:例如 2021-03/4(表示 2021 年 3 月第 4 周)
  • 任意时间

以及对于每个范围

  • 来源
  • 操作
  • 来源 + 操作
  • 操作 + 页面
  • 用户 ID + 操作
  • 全局

以及对于每种数据类型(类型)

  • count(存储为字符串的整数)
  • bitmap
  • set

生成的键格式如下

 rab:{type}[:custom:{customName}][:user:{userId}][:source:{source}][:action:{action}][:page:{page}]:timeSpan:{timeSpan}

其中 [] 中的值是可选的。

  • 对于每个生成的键,例如 rab:count:*,数据存储如下:INCR {key} 示例:
 INCR rab:count:action:addToCart:timeSpan:2015-12/3

对于每个生成的键,例如: rab:set:*,数据存储如下:SADD {key} {userId} 示例

 SADD rab:set:action:addToCart:timeSpan:2015-12/3 8

对于每个生成的键,例如 rab:bitmap:*,数据存储如下:SETBIT {key} {userId} 1。示例

 SETBIT rab:bitmap:action:addToCart:timeSpan:2015-12/3 8 1

同类群组数据#

  • 我们存储注册并随后购买了某些产品的用户(操作顺序很重要)。
  • 对于 12 月的每次购买操作,我们会检查用户之前是否执行过注册操作(注册计数器必须大于零)。
  • 如果是,我们将用户位设置为 1,例如:SETBIT rab:bitmap:custom:cohort-buy:timeSpan:{timeSpan} {userId} 1
  • 例如 用户 Id 2 在 2015-12-17 购买了 2 个产品。此数据不会被存储。
  • 例如 用户 Id 10 在 2015-12-17 购买了 1 个产品,并在 2015-12-16 注册。此数据将存储为:SETBIT rab:bitmap:custom:cohort-buy:timeSpan:2015-12 10 1。
  • 我们假设用户必须先注册才能购买。

留存数据#

  • 留存是指在两个不同日期购买的用户
  • 对于每次购买操作,我们检查用户在任意时间购买的产品数量是否多于在特定日期购买的产品数量(不包括当前购买)。
  • 如果是,我们将用户 ID 添加到 set,例如:SADD rab:set:custom:retention-buy:timeSpan:{timeSpan} {userId}
  • 例如 用户 Id 5 在 2015-12-15 购买了 3 个产品。他的留存不会被存储(当天购买的产品:2,任意时间购买的产品:0)。
  • 例如 用户 Id 3 在 2015-12-15 购买了 1 个产品,在此之前 - 在 2015-12-13 购买了 1 个产品。他的留存将被存储(当天购买的产品:0,任意时间购买的产品:1),例如:SADD rab:set:custom:retention-buy:timeSpan:2015-12 3。

数据如何访问:#

  • 总流量:

12 月: BITCOUNT rab:bitmap:custom:global:timeSpan:2015-12 12 月第 X 周: BITCOUNT rab:bitmap:custom:global:timeSpan:2015-12/{X} 示例

 BITCOUNT rab:bitmap:custom:global:timeSpan:2015-12/3
  • 每页流量({page} 是以下之一:homepage, product1, product2, product3):
December: BITCOUNT rab:bitmap:action:visit:page:{page}:timeSpan:2015-12

示例

 BITCOUNT rab:bitmap:action:visit:page:homepage:timeSpan:2015-12
  • 12 月第 X 周:
BITCOUNT rab:bitmap:action:visit:page:{page}:timeSpan:2015-12/{X}

示例

 BITCOUNT rab:bitmap:action:visit:page:product1:timeSpan:2015-12/2
  • 按来源流量({source} 是以下之一:google, Facebook, email, direct, referral, none):

12 月

BITCOUNT rab:bitmap:source:{source}:timeSpan:2015-12

示例

 BITCOUNT rab:bitmap:source:referral:timeSpan:2015-12
  • 12 月第 X 周: BITCOUNT rab:bitmap:source:{source}:timeSpan:2015-12/{X}

示例

 BITCOUNT rab:bitmap:source:google:timeSpan:2015-12/1
  • 趋势流量({page} 是以下之一:homepage, product1, product2, product3):
  • 12 月:从 BITCOUNT rab:bitmap:action:visit:{page}:timeSpan:2015-12-01 到 BITCOUNT rab:bitmap:action:visit:{page}:timeSpan:2015-12-31
  • 12 月第 1 周:与上述类似,但日期范围为 2015-12-01 至 2015-12-07
  • 12 月第 2 周:与上述类似,但日期范围为 2015-12-08 至 2015-12-14
  • 12 月第 3 周:与上述类似,但日期范围为 2015-12-15 至 2015-12-21
  • 12 月第 4 周:与上述类似,但日期范围为 2015-12-22 至 2015-12-28
  • 12 月第 5 周:与上述类似,但日期范围为 2015-12-29 至 2015-12-31
  • 示例:
 BITCOUNT rab:bitmap:action:visit:homepage:timeSpan:2015-12-29 => BITCOUNT rab:bitmap:action:visit:homepage:timeSpan:2015-12-30 => BITCOUNT rab:bitmap:action:visit:homepage:timeSpan:2015-12-31
  • 购买产品总数:
  • 12 月: GET rab:count:action:buy:timeSpan:2015-12
  • 12 月第 X 周: GET rab:count:action:buy:timeSpan:2015-12/{X} 示例:
 GET rab:count:action:buy:timeSpan:2015-12/1
  • 加入购物车产品总数:

12 月: GET rab:count:action:addToCart:timeSpan:2015-12 12 月第 X 周: GET rab:count:action:addToCart:timeSpan:2015-12/{X} 示例

 GET rab:count:action:addToCart:timeSpan:2015-12/1
  • 购买产品份额({productPage} 是以下之一:product1, product2, product3):

12 月: GET rab:count:action:buy:page:{productPage}:timeSpan:2015-12 示例

 GET rab:count:action:buy:page:product3:timeSpan:2015-12

12 月第 X 周: GET rab:count:action:buy:page:{productPage}:timeSpan:2015-12/{X} 示例:

 GET rab:count:action:buy:page:product1:timeSpan:2015-12/2

客户和同类群组分析#

  • 注册人数:BITCOUNT rab:bitmap:action:register:timeSpan:2015-12
  • 注册后购买人数(顺序很重要):BITCOUNT rab:bitmap:custom:cohort-buy:timeSpan:2015-12
  • 流失率:(注册后购买人数 / 注册人数) * 100 [%]
  • 仅购买指定产品的客户({productPage} 是以下之一:product1, product2, product3):
SMEMBERS rab:set:action:buy:page:{productPage}:timeSpan:2015-12

示例

 SMEMBERS rab:set:action:buy:page:product2:timeSpan:2015-12
  • 购买 Product1 和 Product2 的客户:
SINTER rab:set:action:buy:page:product1:timeSpan:anytime rab:set:action:buy:page:product2:timeSpan:anytime
  • 客户留存(在不同日期购买的客户):SMEMBERS rab:set:custom:retention-buy:timeSpan:anytime

参考资料#