非常好的选择!让我们来优化数据收集和存储方式,并添加更多实时指标。这将使我们的分析系统能够处理更大规模的数据,并提供更有价值的实时洞察。

第三十四部分:优化数据收集和存储,添加更多实时指标

  1. 优化数据收集和存储

为了处理更大规模的用户行为数据,我们需要进行以下优化:

a. 使用批量插入 b. 实现数据压缩 c. 使用分区表 d. 添加索引以提高查询性能

首先,更新 src/db/schema.ts

import { sqliteTable, integer, text, real } from "drizzle-orm/sqlite-core";
import { sql } from "drizzle-orm";
 
export const userBehaviors = sqliteTable("user_behaviors", {
  id: integer("id").primaryKey(),
  userId: integer("user_id"),
  data: text("data"), // 存储压缩的JSON数据
  timestamp: integer("timestamp", { mode: "timestamp" }),
  date: text("date").default(sql`DATE('now')`), // 用于分区
});
 
// 添加索引
db.run(`CREATE INDEX IF NOT EXISTS idx_user_behaviors_user_id ON user_behaviors (user_id)`);
db.run(`CREATE INDEX IF NOT EXISTS idx_user_behaviors_date ON user_behaviors (date)`);

更新 src/routes/analytics.ts 中的数据插入逻辑:

import { Elysia } from "elysia";
import { db } from "../db";
import { userBehaviors } from "../db/schema";
import { compress } from "lz-string";
 
let behaviorBuffer = [];
 
export const analyticsRoutes = new Elysia()
  // ... 保留之前的路由
  .post("/api/log-behavior", async ({ body }) => {
    const compressedData = compress(JSON.stringify(body));
    behaviorBuffer.push({
      userId: body.userId,
      data: compressedData,
      timestamp: new Date(),
    });
 
    if (behaviorBuffer.length >= 100) {
      await db.insert(userBehaviors).values(behaviorBuffer);
      behaviorBuffer = [];
    }
 
    return { success: true };
  });
 
// 定期刷新缓冲区
setInterval(async () => {
  if (behaviorBuffer.length > 0) {
    await db.insert(userBehaviors).values(behaviorBuffer);
    behaviorBuffer = [];
  }
}, 60000); // 每分钟刷新一次
  1. 添加更多实时指标

我们将添加实时转化率和实时收入指标。首先,更新 src/db/schema.ts

export const conversions = sqliteTable("conversions", {
  id: integer("id").primaryKey(),
  userId: integer("user_id"),
  type: text("type"), // 例如:'purchase', 'signup', 'download'
  value: real("value"), // 转化的价值(如购买金额)
  timestamp: integer("timestamp", { mode: "timestamp" }),
});
 
// 添加索引
db.run(`CREATE INDEX IF NOT EXISTS idx_conversions_timestamp ON conversions (timestamp)`);

更新 src/routes/analytics.ts 以提供实时指标:

import { Elysia } from "elysia";
import { db } from "../db";
import { userBehaviors, conversions, postViews } from "../db/schema";
 
export const analyticsRoutes = new Elysia()
  // ... 保留之前的路由
  .get("/api/real-time-stats", async () => {
    const now = new Date();
    const fiveMinutesAgo = new Date(now.getTime() - 5 * 60 * 1000);
 
    const activeUsersCount = await db
      .select({ count: sql`count(distinct ${userBehaviors.userId})` })
      .from(userBehaviors)
      .where(sql`${userBehaviors.timestamp} > ${fiveMinutesAgo}`)
      .get();
 
    const pageViewsCount = await db
      .select({ count: sql`count(*)` })
      .from(postViews)
      .where(sql`${postViews.lastViewed} > ${fiveMinutesAgo}`)
      .get();
 
    const conversionsCount = await db
      .select({ count: sql`count(*)` })
      .from(conversions)
      .where(sql`${conversions.timestamp} > ${fiveMinutesAgo}`)
      .get();
 
    const revenue = await db
      .select({ total: sql`sum(${conversions.value})` })
      .from(conversions)
      .where(sql`${conversions.timestamp} > ${fiveMinutesAgo}`)
      .get();
 
    const conversionRate = pageViewsCount.count > 0
      ? (conversionsCount.count / pageViewsCount.count) * 100
      : 0;
 
    const activePagesResult = await db
      .select({
        path: postViews.path,
        count: sql`count(*)`.as("count"),
      })
      .from(postViews)
      .where(sql`${postViews.lastViewed} > ${fiveMinutesAgo}`)
      .groupBy(postViews.path)
      .orderBy(sql`count(*)`, "desc")
      .limit(5)
      .all();
 
    return {
      activeUsers: activeUsersCount.count,
      pageViews: pageViewsCount.count,
      conversions: conversionsCount.count,
      conversionRate: conversionRate.toFixed(2),
      revenue: revenue.total || 0,
      activePages: activePagesResult,
    };
  })
  .post("/api/log-conversion", async ({ body }) => {
    await db.insert(conversions).values(body);
    return { success: true };
  });

现在,更新 src/views/analytics.eta 以显示这些新的实时指标:

<% layout('./layouts/main.eta', { title: 'Analytics' }) %>
 
<h1>Real-time Analytics Dashboard</h1>
 
<div class="real-time-stats">
  <div class="stat-box">
    <h2>Active Users</h2>
    <p id="active-users-count">0</p>
  </div>
  <div class="stat-box">
    <h2>Page Views</h2>
    <p id="page-views-count">0</p>
  </div>
  <div class="stat-box">
    <h2>Conversions</h2>
    <p id="conversions-count">0</p>
  </div>
  <div class="stat-box">
    <h2>Conversion Rate</h2>
    <p id="conversion-rate">0%</p>
  </div>
  <div class="stat-box">
    <h2>Revenue</h2>
    <p id="revenue">$0</p>
  </div>
</div>
 
<div class="stat-box">
  <h2>Top Active Pages</h2>
  <ul id="active-pages-list"></ul>
</div>
 
<!-- 保留之前的图表和脚本 -->
 
<script>
  // ... 保留之前的代码
 
  // 更新实时统计数据的函数
  async function updateRealTimeStats() {
    const response = await fetch('/api/real-time-stats');
    const stats = await response.json();
    
    document.getElementById('active-users-count').textContent = stats.activeUsers;
    document.getElementById('page-views-count').textContent = stats.pageViews;
    document.getElementById('conversions-count').textContent = stats.conversions;
    document.getElementById('conversion-rate').textContent = `${stats.conversionRate}%`;
    document.getElementById('revenue').textContent = `$${stats.revenue.toFixed(2)}`;
    
    const activePagesList = document.getElementById('active-pages-list');
    activePagesList.innerHTML = '';
    stats.activePages.forEach(page => {
      const li = document.createElement('li');
      li.textContent = `${page.path}: ${page.count} views`;
      activePagesList.appendChild(li);
    });
  }
 
  // 定期更新实时统计数据
  setInterval(updateRealTimeStats, 5000); // 每5秒更新一次
 
  // 初始加载
  updateRealTimeStats();
</script>
 
<style>
  .real-time-stats {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
    margin-bottom: 2em;
  }
  .stat-box {
    background-color: #f0f0f0;
    border-radius: 8px;
    padding: 1em;
    text-align: center;
    margin: 0.5em;
    flex: 1 1 200px;
  }
</style>

这些改进实现了以下功能:

  1. 优化数据收集和存储:

    • 使用批量插入减少数据库操作次数
    • 实现数据压缩以减少存储空间
    • 使用分区表(通过日期字段)以提高大规模数据的查询效率
    • 添加索引以提高查询性能
  2. 添加更多实时指标:

    • 实时活跃用户数
    • 实时页面浏览量
    • 实时转化次数
    • 实时转化率
    • 实时收入
    • 实时最活跃页面列表

主要改进包括:

  • 优化了数据存储和查询方式,使系统能够处理更大规模的用户行为数据
  • 提供了更全面的实时指标,包括业务关键指标如转化率和收入
  • 改进了实时数据的可视化展示,使用更直观的布局

接下来的步骤可以包括:

  1. 实现数据归档策略,定期将旧数据移动到历史表中
  2. 添加更多的数据可视化图表,如实时转化漏斗、用户行为流图等
  3. 实现自定义仪表板功能,允许用户选择他们最关心的指标
  4. 添加异常检测功能,当指标出现异常波动时发出警报
  5. 实现预测分析,如预测未来一小时的收入或转化率

你希望继续深入哪个方向,或者有其他想法吗?