4. 评分引擎核心设计:定义评分规则引擎接口、策略模式实现可插拔规则、规则优先级与权重配置、评分结果数据结构设计

评分引擎是整个低延迟接口的计算核心。本章将围绕“可扩展、可配置、高性能”三个目标,设计一套支持策略模式、优先级调度与权重聚合的评分规则引擎。我们从接口定义开始,逐步构建完整的评分骨架。

4.1 评分规则引擎接口定义

引擎接口是评分系统的契约。所有评分规则必须实现该接口,保证引擎能够统一调用。接口设计遵循单一职责原则,只暴露评分计算与元数据获取两个核心方法。

方法签名 返回值 说明
evaluate(context: ScoreContext): ScoreResult ScoreResult 执行评分逻辑,返回单项评分结果
getRuleMeta(): RuleMeta RuleMeta 返回规则元数据(名称、优先级、权重等)
isApplicable(context: ScoreContext): boolean boolean 判断当前上下文是否适用该规则
// 评分规则引擎核心接口
public interface ScoringRule {
    ScoreResult evaluate(ScoreContext context);
    RuleMeta getRuleMeta();
    boolean isApplicable(ScoreContext context);
}

// 规则元数据
public class RuleMeta {
    private String ruleId;          // 规则唯一标识
    private String name;            // 规则名称
    private int priority;           // 优先级(数值越小优先级越高)
    private double weight;          // 权重(0.0 ~ 1.0)
    private String description;     // 规则描述
    // getters & setters ...
}

// 评分上下文
public class ScoreContext {
    private String userId;
    private String targetId;
    private Map<String, Object> attributes;  // 扩展属性
    // getters & setters ...
}
设计要点:接口中的 isApplicable 方法允许引擎在运行时动态过滤规则,避免无效计算。这是低延迟优化的第一道关卡。

4.2 策略模式实现可插拔规则

策略模式让评分规则可以独立变化、自由组合。每个规则是一个策略,引擎作为上下文持有策略集合,运行时按需调度。新增规则时只需添加新实现类,无需修改引擎代码。

策略模式评分引擎架构 ScoreEngine <<接口>> ScoringRule ContentQualityRule 内容质量评分 UserActivityRule 用户活跃度评分 TimelinessRule 时效性评分 ReputationRule 信誉评分 ScoreAggregator 新增规则只需实现 ScoringRule 接口,注册到引擎即可,无需修改现有代码
// 引擎核心实现
public class ScoreEngine {
    private List<ScoringRule> rules;

    public ScoreEngine(List<ScoringRule> rules) {
        // 按优先级排序
        this.rules = rules.stream()
            .sorted(Comparator.comparingInt(r -> r.getRuleMeta().getPriority()))
            .collect(Collectors.toList());
    }

    public ScoreResult evaluate(ScoreContext context) {
        List<ScoreResult> results = new ArrayList<>();
        for (ScoringRule rule : rules) {
            if (rule.isApplicable(context)) {
                long start = System.nanoTime();
                ScoreResult result = rule.evaluate(context);
                result.setElapsedNanos(System.nanoTime() - start);
                results.add(result);
            }
        }
        return ScoreAggregator.aggregate(results);
    }
}

4.3 规则优先级与权重配置

优先级决定规则执行顺序,权重决定最终分数的贡献比例。两者共同构成评分引擎的调度与聚合策略。

4.3.1 优先级调度策略

  • 数值越小优先级越高:优先级 1 的规则先于优先级 10 执行。
  • 短路机制:高优先级规则返回致命分数(如 0 分)时,可跳过后续规则。
  • 分组执行:相同优先级的规则可并行执行,提升吞吐量。

4.3.2 权重配置示例

规则名称 优先级 权重 说明
ContentQualityRule 1 0.40 内容质量权重最高
UserActivityRule 2 0.25 用户活跃度次之
TimelinessRule 3 0.20 时效性
ReputationRule 4 0.15 信誉评分
// 权重聚合器实现
public class ScoreAggregator {
    public static ScoreResult aggregate(List<ScoreResult> results) {
        double totalScore = 0.0;
        double totalWeight = 0.0;
        Map<String, Object> details = new LinkedHashMap<>();

        for (ScoreResult result : results) {
            double weight = result.getWeight();
            totalScore += result.getScore() * weight;
            totalWeight += weight;
            details.put(result.getRuleId(), result.getScore());
        }

        // 归一化处理
        double finalScore = totalWeight > 0 ? totalScore / totalWeight : 0.0;

        return new ScoreResult(finalScore, details);
    }
}
性能优化提示:权重配置建议从外部配置中心(如 Apollo、Nacos)动态加载,避免硬编码。引擎启动时一次性加载规则列表,运行时只做计算,不做反射或动态编译。

4.4 评分结果数据结构设计

评分结果需要同时满足“快速序列化”和“丰富信息”两个要求。我们设计两级结构:顶层为总分,底层为规则明细。

评分结果数据结构 ScoreResult totalScore: double ruleDetails: Map elapsedNanos: long status: String ruleDetails: { ruleId -> score, weight, elapsed } ruleDetails 支持按需展开,序列化时可选只返回 totalScore 以降低带宽消耗
// 评分结果实体
public class ScoreResult {
    private double totalScore;                    // 最终总分
    private Map<String, RuleDetail> ruleDetails; // 规则明细
    private long elapsedNanos;                   // 引擎总耗时(纳秒)
    private String status;                       // SUCCESS / PARTIAL / FAILED

    // 内部明细类
    public static class RuleDetail {
        private double score;
        private double weight;
        private long elapsedNanos;
        // getters & setters ...
    }
}

// JSON 序列化示例(只返回总分)
// { "totalScore": 87.5, "status": "SUCCESS", "elapsedMs": 1.2 }

// 完整返回示例
// {
//   "totalScore": 87.5,
//   "status": "SUCCESS",
//   "elapsedMs": 1.2,
//   "ruleDetails": {
//     "contentQuality": { "score": 90.0, "weight": 0.4, "elapsedMs": 0.3 },
//     "userActivity":   { "score": 85.0, "weight": 0.25, "elapsedMs": 0.2 },
//     "timeliness":     { "score": 80.0, "weight": 0.2, "elapsedMs": 0.4 },
//     "reputation":     { "score": 95.0, "weight": 0.15, "elapsedMs": 0.1 }
//   }
// }
序列化优化:对于低延迟场景,建议在 API 层提供 ?detail=false 参数,默认只返回总分和状态,减少 JSON 体积和序列化时间。ruleDetails 仅在调试或审计时启用。

4.5 本章小结

  • 接口设计:ScoringRule 接口定义了评分、元数据、适用性三个核心方法,保证引擎与规则解耦。
  • 策略模式:每个规则独立实现,引擎通过组合方式调度,新增规则零侵入。
  • 优先级与权重:优先级控制执行顺序,权重控制分数贡献,两者配合实现灵活评分策略。
  • 结果结构:ScoreResult 包含总分、明细、耗时、状态,支持按需序列化,兼顾信息完整性与传输效率。