本文目录导读:

- 方案一:基于数据库查询的动态分群(适合中小型项目,逻辑简单)
- 方案二:基于标签系统的静态分群(最常用、通用性强)
- 方案三:基于规则引擎的实时分群(适合复杂逻辑、大数据量)
- 方案四:基于大数据组件的分群(适合百万级以上用户)
- 实战建议:从简单到复杂的演进路线
- 关于PHP性能的特别提示
在PHP项目中实现用户分群,通常有几种主流的模式,具体选择哪种方案,取决于你的数据量大小、分群逻辑的复杂度以及实时性要求。
以下是几种从简单到复杂的实现方案,按推荐程度和场景进行分类:
基于数据库查询的动态分群(适合中小型项目,逻辑简单)
这是最直接的方法,不单独存储“分群”结果,而是在需要使用人群时,动态查询数据库。
原理: 根据用户属性(注册时间、等级、是否付费)或行为(最近登录、购买次数)编写SQL。
代码示例:
// 查询 "高活跃付费用户" 分群
$sql = "SELECT user_id FROM users
WHERE last_login > DATE_SUB(NOW(), INTERVAL 7 DAY)
AND total_spent > 1000
AND status = 1";
$result = $db->query($sql);
// 遍历用户群发送优惠券
foreach ($result as $user) {
sendCoupon($user['user_id'], 'VIP_DISCOUNT');
}
优点: 实现简单,数据绝对实时。
缺点: 复杂查询时数据库压力大,不支持复杂的用户行为分析(如“过去30天购买了A但没购买B”)。
适用场景: 管理后台筛选用户、临时性的运营活动。
基于标签系统的静态分群(最常用、通用性强)
为核心用户打上各种“标签”,通过标签组合来定义分群,这是很多互联网公司主流的做法。
数据库结构:
- users表: 基础信息。
- user_tags表: (多对多关系)user_id, tag_id, created_at
- tags表: id, tag_name (
VIP,苹果用户,流失风险,母婴爱好者)
流程:
-
打标签: 通过定时脚本(Cron Job)或消息队列(RabbitMQ/Redis),分析原始数据并给用户打标签。
function addTagToUser($userId, $tagName) { // 逻辑:查找tagId,插入到user_tags表 } -
创建分群: 在后台可以创建一个名为“高价值宝妈”的分群,其规则是
[VIP标签] AND [母婴爱好者标签] AND [苹果用户标签]。// 查询拥有指定标签组合的用户 $sql = "SELECT user_id FROM user_tags WHERE tag_id IN (1, 2, 3) GROUP BY user_id HAVING COUNT(DISTINCT tag_id) = 3"; $result = $db->query($sql);
优点: 灵活、查询速度快、易于扩展。
缺点: 标签需要预先计算,有一定延迟;标签组合爆炸时管理复杂。
适用场景: 精准营销、推荐系统、用户画像。
基于规则引擎的实时分群(适合复杂逻辑、大数据量)
当分群规则非常复杂(“近30天访问了3次页面A,且未购买商品B,且距离上次投诉超过7天”),简单的SQL或标签难以表达时,可以使用规则引擎。
实现方式:
- 用户行为表: 存储用户的每一次行为(event_type, event_data, user_id, time)。
- 规则定义: 将分群规则写成JSON、PHP数组或DSL(领域特定语言)。
$rule = [ 'logic' => 'AND', 'conditions' => [ ['field' => 'event', 'operator' => '>=', 'value' => ['page_view', 3, '30 days']], ['field' => 'event', 'operator' => '=', 'value' => ['purchase', 'product_B', 'not']], ['field' => 'timestamp', 'operator' => '>', 'value' => 'last_complaint + 7 days'] ] ]; - 匹配引擎: 使用PHP的
ConditionalValidator类或引入RulerZ、Symfony ExpressionLanguage等库,逐条检查用户行为是否符合规则。
优点: 支持极端复杂的业务逻辑。
缺点: 实现难度大,实时匹配性能较差,通常需要配合ClickHouse、Elasticsearch等大数据组件。
适用场景: 风控系统、复杂的A/B测试分组。
基于大数据组件的分群(适合百万级以上用户)
PHPPHP直接处理百万用户的分群逻辑会比较吃力,PHP通常作为调度层或API层,真正的计算交给专业组件。
架构:
- 数据存储: MySQL(用户基础信息) + Redis(缓存标签) + ClickHouse(事件分析)。
- 数据同步: PHP后台编辑分群规则,写入MySQL的
segments表。 - 离线计算: 用Python/Go编写脚本(或使用Spark),从ClickHouse拉取数据,根据规则计算分群结果,生成一张
segment_user表(segment_id, user_id)。 - PHP调用: 运营后台直接读取
segment_user表。// 分群结果已经预计算好 $users = $db->query("SELECT user_id FROM segment_user WHERE segment_id = 123");
优点: 性能极高,支持亿级用户。
缺点: 需要引入大数据栈,开发成本高。
适用场景: 大型电商、内容平台(如抖音、拼多多后台的分群系统)。
实战建议:从简单到复杂的演进路线
针对普通PHP项目,我不建议一开始就上大数据方案,建议按以下步骤迭代:
- 阶段1(MVP): 使用方案一,直接在User表加字段(如
is_vip,last_active_date),用简单的WHERE查询实现分群。 - 阶段2(增长期): 引入方案二,建立标签系统,这是性价比最高的阶段,可以用MySQL或在Redis里用Set存储标签。
- Redis例子:
SADD tag:vip:users 1001 1002 1003 - 取交集
SINTER tag:vip:users tag:apple:users
- Redis例子:
- 阶段3(规模化): 如果需要处理复杂事件(如漏斗分析、行为序列),引入方案四,将PHP作为前端,计算交给ClickHouse或Elasticsearch。
关于PHP性能的特别提示
- 不要在PHP里循环查数据库来判断分群,如果一个分群有10万人,永远不要在
foreach循环里查数据库。 - 使用批量操作,一次性获取所有用户ID,然后批量处理(例如批量发推送,批量存到Redis)。
- 使用缓存,对于经常使用的分群(如“每日活跃用户”),定时计算后存入Redis Set,PHP直接从Redis读取。
| 方案 | 复杂度 | 实时性 | 适用场景 | 建议 |
|---|---|---|---|---|
| 数据库查询 | 低 | 高 | 小型系统、后台筛选 | 入门 |
| 标签系统 | 中 | 中 | 中型项目、精准营销 | 强烈推荐 |
| 规则引擎 | 高 | 中 | 复杂风控、个性化规则 | 有经验团队可用 |
| 大数据组件 | 极高 | 低 | 大型平台、用户画像 | 需要专业团队 |
建议先从 标签系统(方案二) 开始,这是技术复杂度、灵活性和维护成本的最佳平衡点。