本文目录导读:

在PHP项目中分配不同场景的权重,通常取决于你的业务目标和技术架构,没有一种通用的绝对公式,但可以根据以下几种常见场景和策略来实现。
下面我从业务逻辑层、算法层、架构层三个维度来说明,并给出PHP实现示例。
常见权重分配场景
| 场景 | 权重含义 | 典型例子 |
|---|---|---|
| 推荐系统 | 不同行为对用户兴趣的贡献度 | 浏览=1,收藏=3,购买=5 |
| 搜索排序 | 不同字段/因素对排序的影响 | 标题权重>描述权重 |
| 负载均衡 | 不同服务器处理请求的比例 | A机器70%,B机器30% |
| 消息队列/任务调度 | 不同任务优先级 | 支付任务权重高,日志任务权重低 |
| A/B测试 | 不同方案分流的比例 | 方案A 80%,方案B 20% |
| 风控评分 | 不同规则对风险的贡献 | 异地登录+30分,频繁操作+50分 |
权重分配的常见方法
静态权重(固定比例)
最简单,适合规则稳定的场景。
class WeightConfig
{
// 场景权重配置
const WEIGHTS = [
'browse' => 1,
'click' => 2,
'favorite' => 3,
'cart' => 4,
'purchase' => 5,
'share' => 3,
];
public static function get(string $action): int
{
return self::WEIGHTS[$action] ?? 0;
}
}
// 计算用户行为总分
$score = 0;
foreach ($userActions as $action) {
$score += WeightConfig::get($action['type']);
}
归一化权重(总和为1)
适合按比例分配,比如负载均衡、A/B测试。
class WeightedRandom
{
/**
* @param array $items 形如 ['A' => 70, 'B' => 20, 'C' => 10]
*/
public static function pick(array $items)
{
$total = array_sum($items);
$rand = mt_rand(1, $total);
foreach ($items as $key => $weight) {
$rand -= $weight;
if ($rand <= 0) {
return $key;
}
}
return array_key_first($items);
}
}
// 使用:A出现概率70%
$node = WeightedRandom::pick(['server_A' => 70, 'server_B' => 30]);
动态权重(基于数据/时间调整)
权重随用户行为、实时数据变化。
class DynamicWeight
{
// 热度衰减:越久远的行为权重越低
public static function timeDecay(float $baseWeight, int $timestamp): float
{
$hoursAgo = (time() - $timestamp) / 3600;
// 每小时衰减5%
return $baseWeight * pow(0.95, $hoursAgo);
}
// 结合用户画像调权
public static function personalize(float $baseWeight, array $userProfile): float
{
$factor = 1.0;
if ($userProfile['vip'] ?? false) {
$factor *= 1.5;
}
return $baseWeight * $factor;
}
}
层次分析法(AHP)/ 多因素加权
适合复杂的多维度评分,如风控、排序。
// 多因素加权评分
$factors = [
'price_score' => ['value' => 80, 'weight' => 0.4],
'quality_score' => ['value' => 90, 'weight' => 0.3],
'delivery_score' => ['value' => 70, 'weight' => 0.2],
'service_score' => ['value' => 85, 'weight' => 0.1],
];
$total = 0;
foreach ($factors as $f) {
$total += $f['value'] * $f['weight'];
}
// 结果:81.5
架构层面的权重分配
配置化(推荐)
把权重放到配置文件或数据库,方便运营调整。
// config/weights.php
return [
'recommend' => [
'browse' => 1,
'click' => 2,
'favorite' => 3,
'purchase' => 5,
],
'search' => [
'title' => 0.5,
'description' => 0.2,
'tags' => 0.3,
],
];
$weights = config('weights.recommend');
数据库存储 + 缓存
适合频繁调整的场景。
class WeightService
{
public function get(string $scene): array
{
return Cache::remember("weights:$scene", 3600, function () use ($scene) {
return DB::table('scene_weights')
->where('scene', $scene)
->pluck('weight', 'key')
->toArray();
});
}
}
策略模式(不同场景不同算法)
interface WeightStrategy
{
public function calculate(array $data): float;
}
class RecommendStrategy implements WeightStrategy
{
public function calculate(array $data): float
{
return $data['browse'] * 1 + $data['purchase'] * 5;
}
}
class SearchStrategy implements WeightStrategy
{
public function calculate(array $data): float
{
return $data['title'] * 0.5 + $data['tags'] * 0.3;
}
}
class WeightContext
{
public function __construct(private WeightStrategy $strategy) {}
public function score(array $data): float
{
return $this->strategy->calculate($data);
}
}
权重分配的注意事项
- 归一化:多因素加权时,权重总和建议为 1,避免结果不可比。
- 避免极端值:权重差距过大(如 1 vs 1000)会掩盖其他因素,建议先做 log 或 sqrt 平滑。
- 可解释性:业务方需要能理解权重的意义,别用纯黑盒模型。
- 可调优:A/B测试 + 数据反馈,持续优化权重。
- 冷启动:新场景没有数据时,先用专家经验设定,再逐步替换为数据驱动。
- 性能:高频调用场景(如推荐接口)应缓存权重,避免每次查库。
完整示例:推荐场景权重
class RecommendScorer
{
private array $weights;
public function __construct()
{
// 从配置/数据库加载
$this->weights = [
'browse' => 1,
'click' => 2,
'favorite' => 4,
'cart' => 5,
'purchase' => 8,
'share' => 6,
];
}
public function score(array $behaviors): float
{
$score = 0;
foreach ($behaviors as $b) {
$w = $this->weights[$b['type']] ?? 0;
// 时间衰减
$decay = pow(0.95, (time() - $b['time']) / 3600);
$score += $w * $decay;
}
return $score;
}
// 归一化到 0-100
public function normalize(float $score, float $maxScore): float
{
return min(100, $score / $maxScore * 100);
}
}
| 需求 | 推荐方法 |
|---|---|
| 规则固定 | 静态配置 |
| 按比例分流 | 归一化 + 加权随机 |
| 实时变化 | 动态权重 + 缓存 |
| 多因素综合 | 加权求和 / AHP |
| 多场景差异大 | 策略模式 + 配置化 |
核心思想:权重本质是业务优先级的数字化表达,一定要让权重可配置、可解释、可调优,而不是硬编码在代码里。
如果你能告诉我具体是哪个场景(推荐、搜索、调度还是风控),我可以给出更针对性的实现方案。