PHP推荐权重算法以及分页

    1. 如果用户浏览的第一页,则清空浏览历史
    1. 每次加载完数据,都保存到read_log, 方便下一页数据排重
  • 数据权重分析:
    • 1获取文章高点赞,高评论的50%数量的文章
    • 2获取用户有点赞过作者的文章,那就推荐该作者的最新文章,拿30%
    • 其余随机文章20%
    • 如果1和2点还不够limit的文章数量,那就再随机补足文章数量
  • todo 以下代码还待优化,只是先提供思路
php 复制代码
<?php
// 1. 查询用户最近交互过的文章相关作者(点赞/评论记录)
use app\common\service\HelperService;
use think\facade\Db;

// 初始化变量
$interacted_authors = [];

// 用户参数设置
$user_id = 1; // 当前用户ID
$page_type = 0; // 推荐页面类型
$filter_conditions = []; // 查询过滤条件
$page_number = input('page', 1); // 页码
$page_size = input('limit', 10); // 每页记录数
$random_seed = '11'; // 随机数种子,用于随机推荐的一致性

// 当访问第一页时,重置用户阅读记录
if ($page_number == 1) {
    // 清除该用户在此类型页面的阅读记录
    Db::name('user_article_read_log')->where('type', $page_type)->where('user_id', $user_id)->delete();
}

// 获取用户最近点赞过的文章作者
$liked_authors = Db::name('articles_like')
    ->alias('al')
    ->join('articles a', 'a.id = al.article_id')
    ->where('al.user_id', $user_id)
    ->where($filter_conditions)
    ->whereTime('al.create_time', '-30 days') // 最近30天内
    ->column('a.user_id');

// 获取用户最近评论过的文章作者
$commented_authors = DB::name('articles_comment')
    ->alias('ac')
    ->join('articles a', 'a.id = ac.article_id')
    ->where($filter_conditions)
    ->where('ac.user_id', $user_id)
    ->whereTime('ac.create_time', '-30 days') // 最近30天内
    ->column('a.user_id');

// 合并并去重用户交互过的作者ID
$interacted_authors = HelperService::arrayFilterUnique(array_merge($liked_authors, $commented_authors));

// 2. 构建推荐查询 - 使用子查询和UNION方式组合多种推荐策略

// 策略1: 获取热门文章(高点赞、高评论)- 占50%权重
$hot_article_limit = ceil($page_size * 0.5);
$hot_article_query = DB::name('articles')
    ->alias('a')
    ->join('user_article_read_log rl', 'rl.article_id = a.id and rl.user_id='.$user_id, 'left')
    ->where('a.status', 1)
    ->whereNull('rl.id') // 排除已阅读的文章
    ->where($filter_conditions)
    ->where('a.create_time', '>', time() - 7 * 24 * 3600) // 最近7天内
    ->order('a.like_count DESC, a.comment_count DESC, a.create_time DESC')
    ->field('a.*')
    ->limit($hot_article_limit)
    ->buildSql();

// 策略2: 如果用户有交互历史,则获取相关作者的最新文章 - 占30%权重
$related_article_query = '';
$related_article_limit = ceil($page_size * 0.3);
if (!empty($interacted_authors)) {
    $related_article_query = DB::name('articles')
        ->alias('a')
        ->join('user_article_read_log rl', 'rl.article_id = a.id and rl.user_id='.$user_id, 'left')
        ->where($filter_conditions)
        ->whereNull('rl.id') // 排除已阅读的文章
        ->where('a.status', 1)
        ->whereIn('a.user_id', $interacted_authors)
        ->whereTime('a.create_time', '-15 days') // 最近15天
        ->order('a.create_time DESC')
        ->limit($related_article_limit)
        ->field('a.*')
        ->buildSql();
}

// 策略3: 随机推荐文章以增加多样性 - 占20%权重或在无交互历史时占50%
$random_article_limit = empty($interacted_authors) ? ceil($page_size * 0.5) : ceil($page_size * 0.2);
$random_article_base_query = DB::name('articles')
    ->alias('a')
    ->join('user_article_read_log rl', 'rl.article_id = a.id and rl.user_id='.$user_id, 'left')
    ->whereNull('rl.id') // 排除已阅读的文章
    ->where($filter_conditions)
    ->where('a.status', 1)
    ->whereTime('a.create_time', '-30 days') // 最近30天
    ->orderRaw('RAND('.$random_seed.')')
    ->field('a.*');

// 构建随机文章的SQL
$random_article_sql = $random_article_base_query->limit($random_article_limit)->buildSql();

// 组合所有查询
$union_queries = array_filter([$hot_article_query, $related_article_query, $random_article_sql]);
$combined_sql = implode(' UNION ', $union_queries);
$combined_sql = '(' . $combined_sql . ')';

// 执行合并查询
$recommended_articles = Db::table($combined_sql . ' a')
    ->select()->toArray();

// 如果推荐结果不足,补充随机文章
if (count($recommended_articles) < $page_size) {
    $additional_articles = $random_article_base_query
        ->whereNotIn('a.id', array_column($recommended_articles, 'id'))
        ->limit($page_size - count($recommended_articles))
        ->select()
        ->toArray();
    
    $recommended_articles = array_values(array_filter(array_merge(
        $recommended_articles ?: [],
        $additional_articles ?: []
    )));
}

// 设置返回数据
$article_list = $recommended_articles;
$total_count = Db::name('articles')->count();

// 记录用户阅读日志,用于下次推荐时排除已读内容
$read_logs = [];
foreach ($article_list as $article) {
    $read_logs[] = [
        'user_id' => $user_id,
        'article_id' => $article['id'],
        'type' => $page_type
    ];
}

// 批量插入阅读记录
if (!empty($read_logs)) {
    Db::name('user_article_read_log')->insertAll($read_logs);
}
相关推荐
刘恒1234567892 小时前
Windows 10 docker 配置(PHP+Nginx+Mysql)(thinkphp5项目)环境
windows·docker·php
ccLianLian2 小时前
计算机视觉·TagCLIP
人工智能·算法
千弥霜3 小时前
codeforces1997(div.3)E F
算法
利刃大大3 小时前
【动态规划:01背包】01背包详解 && 模板题 && 优化
c++·算法·动态规划·力扣·背包问题
im_AMBER3 小时前
算法笔记 10
笔记·学习·算法·leetcode
JaguarJack3 小时前
PHP 开发中 你可能不知道的非常好用 PhpStorm 插件
后端·php
workflower3 小时前
FDD与其他方法的相似和区别
数据库·算法·需求分析·个人开发
电鱼智能的电小鱼8 小时前
基于电鱼 AI 工控机的智慧工地视频智能分析方案——边缘端AI检测,实现无人值守下的实时安全预警
网络·人工智能·嵌入式硬件·算法·安全·音视频
孫治AllenSun9 小时前
【算法】图相关算法和递归
windows·python·算法