基于用户行为推荐的轻量化广告投放系统:技术栈、背景意义与核心代码
2026/9/6 15:37:14 网站建设 项目流程

1. 背景与意义

随着互联网流量红利见顶,广告主对投放效率的要求越来越高。传统广告投放系统往往依赖人工圈选人群、固定频控策略和粗粒度的渠道定向,存在三个突出问题:一是投放决策滞后,无法实时响应用户兴趣变化;二是规则配置复杂,中小团队维护成本高;三是数据链路冗长,从行为采集到策略生效往往需要数小时甚至数天。

基于用户行为推荐的轻量化广告投放系统,核心思路是把用户实时行为(点击、浏览、搜索、加购等)作为推荐信号,通过轻量级算法在毫秒级完成广告候选排序与投放决策。相比传统重型推荐平台,它不追求超大模型和全量离线训练,而是强调快速落地、低资源占用和可解释性,特别适合中小型业务团队、垂直行业站点和预算有限的增长团队。

其意义主要体现在三个方面:

  • 提升投放效率:基于实时行为信号动态调整广告排序,减少无效曝光,提高点击率和转化率。
  • 降低落地门槛:采用轻量技术栈和简化数据链路,团队无需搭建大规模分布式计算平台即可上线。
  • 增强可解释性:规则与模型结合,投放决策可回溯、可干预,便于运营人员理解和调优。

2. 系统整体架构

系统整体采用模块化分层设计,核心链路为「行为采集 → 特征加工 → 候选召回 → 排序推荐 → 投放反馈」。整体架构如下图所示:

flowchart TD A[用户端行为埋点] --> B[行为采集服务] B --> C[实时特征计算] C --> D[候选广告召回] D --> E[轻量排序模型] E --> F[广告投放引擎] F --> G[曝光与点击反馈] G --> C

各模块职责如下:

  • 行为采集服务:接收前端埋点数据,进行清洗、去重和标准化,输出统一行为事件。
  • 实时特征计算:基于用户近期行为序列,计算兴趣标签、行为频次、活跃度等特征。
  • 候选广告召回:通过标签匹配、协同过滤或向量检索,从广告库中召回候选集。
  • 轻量排序模型:使用逻辑回归、GBDT 或浅层神经网络对候选广告打分排序。
  • 广告投放引擎:结合频控、预算和投放策略,决定最终展示广告并记录反馈。

3. 技术栈选型

轻量化系统的技术选型遵循「够用、易维护、可扩展」原则,避免引入过重组件。推荐技术栈如下:

层次技术选型说明
前端埋点JavaScript SDK / 小程序 SDK采集点击、曝光、浏览时长等行为数据
接入层Nginx + Spring Boot / Go提供高并发接入与简单路由能力
消息队列Kafka / Redis Stream削峰填谷,异步解耦行为写入与消费
实时计算Flink / Redis + 定时聚合轻量场景可用 Redis 计数 + 窗口聚合替代 Flink
特征存储Redis / RedisJSON存储用户实时行为序列与特征缓存
广告索引Elasticsearch / MySQL + 内存索引支持标签过滤与候选召回
排序模型Python + scikit-learn / XGBoost离线训练,在线加载模型文件进行预测
投放服务Java / Go 微服务负责频控、预算控制与广告下发
数据报表ClickHouse / MySQL + 定时任务汇总曝光、点击、消耗等投放指标

对于日活十万级以内的业务,可以进一步简化:去掉 Flink,使用 Redis 配合定时任务完成分钟级特征聚合;排序模型使用逻辑回归即可获得不错效果。

4. 核心代码实现

下面给出系统中最核心的三个代码片段:行为特征计算、候选召回和轻量排序打分。

4.1 用户行为特征计算

该模块从 Redis 中读取用户最近行为序列,计算兴趣标签权重和活跃度特征。以下为 Java 实现示例:

import redis.clients.jedis.Jedis; import java.util.HashMap; import java.util.List; import java.util.Map; public class UserFeatureService { private static final String BEHAVIOR_KEY_PREFIX = "user:behavior:"; private static final int MAX_SEQUENCE_LENGTH = 50; private final Jedis jedis; public UserFeatureService(Jedis jedis) { this.jedis = jedis; } public Map<String, Object> buildFeatures(String userId) { String key = BEHAVIOR_KEY_PREFIX + userId; List<String> behaviors = jedis.lrange(key, 0, MAX_SEQUENCE_LENGTH - 1); Map<String, Integer> tagWeight = new HashMap<>(); int clickCount = 0; int viewCount = 0; for (String behavior : behaviors) { String[] parts = behavior.split(":"); String type = parts[0]; String tag = parts[1]; int weight = getBehaviorWeight(type); tagWeight.merge(tag, weight, Integer::sum); if ("click".equals(type)) { clickCount++; } else if ("view".equals(type)) { viewCount++; } } Map<String, Object> features = new HashMap<>(); features.put("tagWeight", tagWeight); features.put("clickCount", clickCount); features.put("viewCount", viewCount); features.put("activeScore", clickCount * 2 + viewCount); return features; } private int getBehaviorWeight(String type) { switch (type) { case "click": return 3; case "search": return 4; case "cart": return 5; case "view": default: return 1; } } }

4.2 候选广告召回

召回阶段根据用户兴趣标签从广告索引中筛选候选广告。以下为基于标签匹配的召回实现:

import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class AdRecallService { private final AdIndex adIndex; public AdRecallService(AdIndex adIndex) { this.adIndex = adIndex; } public List<Ad> recall(Map<String, Integer> tagWeight, int topN) { // 按权重排序用户兴趣标签 List<Map.Entry<String, Integer>> sortedTags = new ArrayList<>(tagWeight.entrySet()); sortedTags.sort((a, b) -> b.getValue() - a.getValue()); Set<String> seenAdIds = new HashSet<>(); List<Ad> candidates = new ArrayList<>(); for (Map.Entry<String, Integer> entry : sortedTags) { String tag = entry.getKey(); List<Ad> adsByTag = adIndex.getAdsByTag(tag); for (Ad ad : adsByTag) { if (seenAdIds.add(ad.getAdId())) { candidates.add(ad); if (candidates.size() >= topN) { return candidates; } } } } return candidates; } }

4.3 轻量排序模型打分

排序阶段使用逻辑回归模型对候选广告打分。模型离线训练后导出权重文件,在线服务加载权重进行预测。以下为 Python 训练脚本示例:

import pandas as pd from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from sklearn.metrics import auc, roc_curve import joblib 加载训练数据:特征列 + 是否点击标签 df = pd.read_csv("ad_train_data.csv") feature_cols = ["tag_match_score", "user_active_score", "ad_ctr", "ad_cvr", "time_decay"] X = df[feature_cols] y = df["is_click"] X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42 ) model = LogisticRegression(C=1.0, max_iter=200) model.fit(X_train, y_train) 评估 AUC y_prob = model.predict_proba(X_test)[:, 1] fpr, tpr, _ = roc_curve(y_test, y_prob) print("AUC:", auc(fpr, tpr)) 保存模型权重,供在线服务加载 joblib.dump(model, "lr_ad_model.pkl") print("feature_weights:", dict(zip(feature_cols, model.coef_[0])))

在线服务加载模型后,对召回候选逐条计算点击概率,按概率降序排列,再结合频控和预算策略决定最终投放列表。

5. 投放策略与频控

排序模型给出候选广告的优先级后,投放引擎还需要执行频控和预算控制,避免过度打扰用户或超预算消耗。核心策略包括:

  • 用户级频控:同一用户对同一广告的曝光次数上限,例如 24 小时内最多 3 次。
  • 广告级频控:控制单条广告在全站的总曝光速率,防止流量集中。
  • 预算控制:按天预算和小时预算双重限制,超出后自动暂停投放。
  • 平滑投放:将预算均匀分配到全天时段,避免凌晨或高峰时段集中消耗。

频控判断使用 Redis 计数器实现,具备原子性和低延迟特性,适合高并发投放场景。

6. 总结与优化方向

基于用户行为推荐的轻量化广告投放系统,通过实时行为特征、标签召回和轻量排序模型的组合,能够在较低成本下实现个性化广告投放。系统核心优势在于技术栈轻、落地快、可解释性强,适合中小团队快速验证和迭代。

后续优化可以从以下几个方向展开:

  • 特征扩展:引入用户长期兴趣画像、广告素材特征和上下文特征,提升排序效果。
  • 模型升级:在数据量增长后,从逻辑回归升级为 GBDT 或深度排序模型。
  • 冷启动优化:对新用户采用热门广告兜底和探索策略,积累行为后再个性化推荐。
  • A/B 实验平台:建立分流实验能力,量化评估算法和策略迭代效果。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询