PHP如何根据数据库存储数据实现分类div按热度排序
PHP实现分类板块按热度动态排序方案
核心逻辑很简单:先按规则统计每个分类的热度分值,按分值倒序排列分类列表,最后按排好的顺序渲染前端div即可。
1. 前置确认:行为表结构
你已经在存储用户搜索、点击行为,确保行为表(示例表名user_behavior)包含以下核心字段即可:
id:主键category_slug:分类唯一标识,比如餐饮分类存restaurants,搜索关键词命中对应分类时也写入对应标识,未命中分类的搜索词留空即可behavior_type:行为类型,比如click代表分类点击、search代表搜索关联分类user_id:操作用户ID(可选,用于防刷)create_time:行为发生时间戳
建议给不同行为设置差异化权重:比如分类点击权重为1,主动搜索对应分类的权重设为2,毕竟搜索行为的用户意向更强,权重可以根据你的业务需求灵活调整。
2. 热度统计SQL
不要每次请求都实时全表统计,后续会加缓存,先写统计逻辑:
SELECT category_slug, SUM( CASE WHEN behavior_type = 'click' THEN 1 WHEN behavior_type = 'search' THEN 2 ELSE 0 END ) AS hot_score FROM user_behavior -- 只统计近30天的行为,避免几个月前的老数据长期占住前排 WHERE create_time >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY)) AND category_slug IS NOT NULL AND category_slug != '' -- 防刷的话加GROUP BY前先去重:先按user_id, category_slug分组把同用户同分类的重复记录合并 GROUP BY category_slug ORDER BY hot_score DESC
执行后会返回按热度从高到低排列的分类标识、对应热度分值。
3. PHP排序逻辑
首先你需要先维护一份全部分类的基础配置数组,包含分类名、图标等展示信息:
// 所有预设分类的基础信息,key为分类唯一标识,和行为表存的category_slug对应 $baseCategories = [ 'restaurants' => ['name' => '餐饮美食', 'icon' => 'food.png'], 'hotels' => ['name' => '酒店住宿', 'icon' => 'hotel.png'], 'education' => ['name' => '教育培训', 'icon' => 'edu.png'], // 其余分类按你原有预设补全即可 ];
接下来读取热度排名,重排分类列表:
// 数据库连接示例,换成你项目自己的DB操作类即可 $pdo = new PDO('mysql:host=localhost;dbname=你的数据库名;charset=utf8mb4', '数据库用户名', '数据库密码'); $cacheKey = 'category_hot_sort'; // 优先读缓存,没有再查库,缓存时间设10分钟即可,分类排名不需要实时更新 // 缓存可以用Redis、文件缓存都行,这里以Redis为例 if (!$sortedSlugs = $redis->get($cacheKey)) { $statRes = $pdo->query("SELECT category_slug,SUM(CASE WHEN behavior_type = 'click' THEN 1 WHEN behavior_type = 'search' THEN 2 ELSE 0 END) AS hot_score FROM user_behavior WHERE create_time >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 30 DAY)) AND category_slug IS NOT NULL AND category_slug != '' GROUP BY category_slug ORDER BY hot_score DESC") ->fetchAll(PDO::FETCH_KEY_PAIR); $sortedSlugs = array_keys($statRes ?: []); $redis->set($cacheKey, $sortedSlugs, 600); // 缓存10分钟 } // 组装排序后的分类列表 $sortedCategories = []; // 先按热度排名放入有统计数据的分类 foreach ($sortedSlugs as $slug) { if (isset($baseCategories[$slug])) { $sortedCategories[$slug] = $baseCategories[$slug]; unset($baseCategories[$slug]); } } // 没有热度数据的冷门类,按你原来的预设顺序接在后面即可 $sortedCategories = array_merge($sortedCategories, $baseCategories);
4. 前端渲染
直接遍历排好序的数组输出div即可,输出顺序就是热度从高到低:
<?php foreach ($sortedCategories as $slug => $info): ?> <div class="category-card" data-slug="<?= htmlspecialchars($slug) ?>"> <img src="/static/category/<?= htmlspecialchars($info['icon']) ?>" alt="<?= htmlspecialchars($info['name']) ?>"> <span><?= htmlspecialchars($info['name']) ?></span> </div> <?php endforeach; ?>
优化建议
- 一定要加缓存,高流量场景下可以把缓存时间调到30-60分钟,分类排名不需要秒级更新,能大幅降低数据库压力
- 可以加时间衰减规则,比如近7天的行为权重是30天前行为的2倍,让近期热门的分类更容易排到前面
- 如果存在恶意刷量的情况,统计热度时先按
user_id + category_slug去重,同一个用户24小时内对同一个分类的多次操作只计1次
分类板块参考效果:
内容的提问来源于stack exchange,提问作者Bob0220
相关产品推荐
相关产品推荐

