/v2/summary 接口逻辑梳理

本文档旨在清晰地解释 /v2/summary 接口的完整工作流程,包括从前端请求到返回结果的整个过程。

1. 接口概览

/v2/summary 是一个用于获取用户活动汇总统计信息的 RESTful API 接口。该接口允许客户端根据时间范围、时区、文章 ID 和广告来源等条件查询用户行为的汇总数据。

1.1 接口签名

GET /v2/summary?startDate={startDate}&endDate={endDate}&zoneId={zoneId}&postId={postId}&fromAd={fromAd}

1.2 请求参数

参数名 类型 必填 描述
startDate String 查询开始日期,格式为 "YYYY-MM-DD"
endDate String 查询结束日期,格式为 "YYYY-MM-DD"
zoneId String 时区标识符
postId String 文章 ID
fromAd Boolean 是否来源于广告

1.3 返回值

返回一个包含用户活动汇总信息的对象,具体字段如下:

  • uniqueVisitors: 唯一访客数
  • engaged: 互动用户数
  • viewedProduct: 查看商品用户数
  • clickedAddToCart: 点击加购按钮用户数
  • clickedBuyNow: 点击立即购买按钮用户数
  • initiatedCheckout: 发起结账流程用户数
  • addedToCart: 添加到购物车用户数
  • placedOrder: 下单用户数
  • orderQuantity: 订单数量
  • device: 设备类型分布
  • platform: 平台分布
  • ui: UI 版本分布

2. 调用链路详解

2.1 Controller 层处理

@GetMapping("/v2/summary")
public R<?> getSummaryV2(String startDate, String endDate, String zoneId, String postId, Boolean fromAd) {
    R<String> checked = checkParamsForSummaryAndStatistic(startDate, endDate, zoneId, postId);
    if (null != checked) return checked;

    return R.result(Success, userActivityService.uniqueVisitorActionSummaryByPostV2(pearEnv, startDate, endDate, zoneId, postId, fromAd));
}

此方法执行以下操作:

  1. 使用 checkParamsForSummaryAndStatistic 方法验证输入参数的有效性
  2. 如果参数验证失败,直接返回错误信息
  3. 如果参数验证成功,调用 Service 层的 uniqueVisitorActionSummaryByPostV2 方法获取汇总数据

2.2 Service 层处理

@Override
public UserActivitySummary uniqueVisitorActionSummaryByPostV2(String environment, String startDate, String endDate,
                                                       String zoneId, String postId, Boolean fromAd) {

    return userActivitySummaryRepositoryV2.summaryUserActivity(environment, startDate, endDate, zoneId, postId, fromAd);
}

Service 层主要起到桥梁作用,将请求转发给 Repository 层处理。

2.3 Repository 层处理

@Override
public UserActivitySummary summaryUserActivity(String environment, String startDate, String endDate, String zoneId, String postId, Boolean fromAd) {
    MongoCollection<Document> summaryCollection = mongoTemplate.getCollection("%sUserActivitySummary_%s_v2".formatted(environment, zoneId));
    List<BsonDocument> summaryPipe = new ArrayList<>() {{
        add(uaa.matchSummaryRange(postId, startDate, endDate, fromAd));
        add(uaa.summaryUserActivity());
        add(uaa.expandSummary());
    }};

    AggregateIterable<Document> summary = summaryCollection.aggregate(summaryPipe);
    return UserActivitySummary.convertDocument(summary.first());
}

Repository 层执行以下关键步骤:

  1. 获取对应环境和时区的 MongoDB 集合:

    MongoCollection<Document> summaryCollection = mongoTemplate.getCollection("%sUserActivitySummary_%s_v2".formatted(environment, zoneId));
    
  2. 构建聚合管道(Aggregation Pipeline):

  3. 执行聚合查询并获取第一条结果

  4. 使用 UserActivitySummary.convertDocument 方法将 MongoDB 的 Document 转换为 Java 对象

2.4 聚合管道详解

2.4.1 匹配阶段 (matchSummaryRange)

构建查询条件,筛选符合以下条件的记录:

  • 指定的 postId
  • 日期范围在 startDateendDate 之间
  • 如果指定了 fromAd 参数,则还需要匹配对应的广告来源标记

2.4.2 汇总阶段 (summaryUserActivity)

使用 MongoDB 的 $group$accumulator 操作符对匹配的数据进行汇总计算:

  1. 初始化累加器状态:

    function() {
      return {
        uniqueVisitors: 0,
        engaged: 0,
        viewedProduct: 0,
        clickedAddToCart: 0,
        clickedBuyNow: 0,
        initiatedCheckout: 0,
        placedOrder: 0,
        addedToCart: 0,
        orderQuantity: 0,
        device: {},
        platform: {},
        ui: {}
      };
    }
    
  2. 累加处理每条记录:

    function(summary, record) {
      if (record["uniqueVisitors"] > 0) summary["uniqueVisitors"] += record["uniqueVisitors"];
      if (record["engaged"] > 0) summary["engaged"] += record["engaged"];
      // ... 其他字段类似处理
      // 合并设备、平台和UI版本的分布统计
      return summary;
    }
    

2.4.3 结果展开阶段 (expandSummary)

使用 $project 操作符将聚合结果展开,去除 _id 字段,保留所需的统计字段。

2.5 数据转换 (convertDocument)

将 MongoDB 返回的 Document 对象转换为 UserActivitySummary Java 对象:

public static UserActivitySummary convertDocument(Document document) {
    if (null == document) return null;
    UserActivitySummary summary = new UserActivitySummary();

    summary.uniqueVisitors = document.getDouble("uniqueVisitors").intValue();
    summary.engaged = document.getDouble("engaged").intValue();
    summary.viewedProduct = document.getDouble("viewedProduct").intValue();
    summary.clickedAddToCart = document.getDouble("clickedAddToCart").intValue();
    summary.clickedBuyNow = document.getDouble("clickedBuyNow").intValue();
    summary.initiatedCheckout = document.getDouble("initiatedCheckout").intValue();
    summary.addedToCart = document.getDouble("addedToCart").intValue();
    summary.placedOrder = document.getDouble("placedOrder").intValue();
    summary.orderQuantity = document.getDouble("orderQuantity").intValue();
    summary.device = document.get("device");
    summary.platform = document.get("platform");
    summary.ui = document.get("ui");

    return summary;
}

3. 总结

/v2/summary 接口通过 MongoDB 聚合管道实现了高效的数据汇总功能。其核心逻辑包括:

  1. 参数校验与传递
  2. 构造 MongoDB 查询条件
  3. 使用聚合管道进行数据筛选、汇总和格式化
  4. 将结果转换为 Java 对象并返回给客户端

整个流程充分利用了 MongoDB 的聚合框架能力,在数据库层面完成了复杂的统计计算,避免了在应用层处理大量数据,提高了系统性能。

results matching ""

    No results matching ""