如何只上传 Top-5 结果?

解读

国内面试场景下,面试官抛出“只上传 Top-5 结果”通常不是让你手写 SQL 的 LIMIT 5,而是考察你对 CouchDB 视图(View)机制Map 端过滤Reduce 排序HTTP 分页参数以及 客户端二次裁剪 的综合理解。
核心矛盾:CouchDB 视图默认返回全量有序数据,而业务只让“上传”5 条。
“上传”一词在国内语境里常被口语化地指“把结果给到上游系统/前端”,所以你要回答的是“如何让 CouchDB 只吐出 5 条最符合业务排序条件的数据,再交给下游”。

知识点

  1. Map 函数:在视图中 emit(key, value) 决定排序键。
  2. Reduce 函数:_count、_sum、_stats 等内置或自定义,用于聚合;不可直接做 Top-N
  3. 视图查询参数
    • descending=true/false
    • startkey/endkey
    • limit=n(硬性截断
    • skip=m(性能黑洞,线上慎用
  4. 书签(bookmark)与分页:CouchDB 2.x+ 支持稳定分页,但 limit 与 skip 组合仍可能全表扫。
  5. 客户端二次排序:若业务排序字段与视图 key 不一致,需拉取候选集再裁剪。
  6. 国内网络与合规:移动端弱网、跨省 CDN 回源时,limit 过大易造成 504,Top-5 是典型安全阈值。

答案

步骤如下,每一步都要在面试时口述清楚

  1. 设计视图
    在 design doc 里新建视图 top_sales,Map 函数按销售额倒序 emit:

    function (doc) {
      if (doc.type === 'order' && doc.amount) {
        emit(-doc.amount, {_id: doc._id, amount: doc.amount});
      }
    }
    

    负号实现倒序,避免 Reduce。

  2. 查询时直接 limit=5

    GET /db/_design/orders/_view/top_sales?limit=5&reduce=false
    

    CouchDB 会在 B+Tree 上提前停扫,只读 5 条,时间复杂度 O(logN+5)不会全表扫

  3. 结果交给上游
    把返回的 5 行 JSON 直接 POST 给业务网关;若上游要求数组打包,再包一层即可。
    关键点:limit 由 CouchDB 服务端完成,网络传输也只有 5 条,符合“只上传 Top-5”的硬性要求。

  4. 防并发更新导致跳变
    国内电商大促场景下,数据实时变化,可在上传前带 update_seq 作为快照版本号,供下游判重。

拓展思考

  1. 如果排序维度是复合指标(销售额×权重),而视图只能单 key,怎么办?
    答:在 Map 里预计算综合得分并 emit,把业务公式下沉到视图;若公式常变,则 emit 原始值,客户端拉 20 条再二次排序裁 5 条,牺牲带宽换灵活

  2. 数据量大到分片集群(国内公有云 CouchDB 3.x 集群版),limit 5 会不会跨 shard 放大?
    答:CouchDB 使用 merge-sort on the fly,协调节点只需每个 shard 取 5 条,再归并 5 条,网络放大系数=shard 数×5,仍是常数级;但 shard 过多时协调节点 CPU 会成为瓶颈,国内经验值:单库 shard≤64

  3. 需要离线优先的 PouchDB 场景,移动端也只想存 Top-5,怎么同步?
    答:在 sync 事件里加 filter 函数,只让 _id 在 Top-5 列表里的文档通过;Top-5 列表由云端定时算好写进一个配置文档,移动端先拉配置再按需同步,节省 90% 流量,符合国内运营商套餐限制。