news 2026/10/22 5:56:36

Python+Django融合协同过滤的新闻推荐平台设计与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python+Django融合协同过滤的新闻推荐平台设计与实现

新闻推荐这个方向,说实话是计算机毕业设计里相当能出活儿的选题。市面上大多数同学的做法是爬点新闻数据,套个模板写个列表页,再挂个简单搜索,最后画几张折线图就算交差了。但这样的项目拿去答辩,老师一眼就能看出含金量不足。真正能拉开差距的,是把这个题目做成一个完整的闭环:数据采集、行为建模、推荐算法、可视化分析、部署展示,每一个环节都有扎实的技术点可以讲深讲透。

这篇文章想和你聊的是,如何用 Python + Django 从零搭一个融合协同过滤算法的新闻推荐平台,把推荐链路、数据分析可视化和工程化落地一次走通。内容全部来自实际项目的踩坑与验证,包含可以直接照抄的代码逻辑、表结构设计、接口定义和部署方案。不管你是准备毕业设计,还是单纯想系统掌握推荐系统在Web场景下的落地方式,这篇都值得收藏。

文章会沿着需求剖析、数据准备、算法实现、系统开发、可视化、性能优化、常见问题的顺序展开,尽量把每一步的“为什么这么做”也说清楚,而不是只给你一堆代码片段。

1. 项目定位于设计思路拆解

1.1 为什么选新闻推荐这个方向

我见过很多同学在毕业设计选题时纠结,既要工作量够,又要难度适中,还得方便展示。电商推荐、短视频推荐这种方向不是不好,而是数据获取和业务复杂度容易被卡住。电商需要商品SKU、库存、销量、评价等一堆字段,短视频推荐则对实时性和多模态特征要求很高,这些都不是一个人一个月能做得完整的。

新闻推荐恰恰是三者兼顾的选择:

  • 数据可获取性高:公开的新闻数据集很多,即使不用爬虫,也能找到大量带分类、带时间、带标题正文的语料。
  • 推荐效果可解释性强:新闻的类目清晰,用户兴趣容易抽象成标签,协同过滤的结果可以直接用“看了A也看了B”这种逻辑向答辩老师解释。
  • 功能延展空间大:可以在基础推荐之上加热度排序、时间衰减、关键词提取,甚至接大模型摘要生成,每一个点都能成为创新点。

这个项目的核心价值不只是“能登录、能展示列表”,而是通过用户行为流数据驱动推荐结果变化,再通过可视化页面把“用户爱看什么、系统推荐了什么、推荐转化率如何”呈现出来,形成完整的智能平台形态。

1.2 技术选型背后的逻辑

为什么用 Python:数据清洗、中文分词、相似度计算、科学计算这一套生态在 Python 里实在太成熟了。你不需要像 Java 那样什么都自己封装,pandas 处理用户行为日志,jieba 做关键词切分,numpy 算余弦相似度,几行代码就能把推荐核心逻辑写完,把节省下来的时间投入到系统功能和效果优化上。

为什么用 Django:Django 自带 ORM、Admin后台、用户认证、模板引擎,这些对于毕设系统来说是天然的加速器。而且 Django 的 MTV 架构和 RESTful 接口设计非常适合前后端分离开发,你不需要额外搭建一个后端框架,一个项目解决接口、后台、登录注册所有需求。

为什么协同过滤是主线:推荐算法有很多种,基于内容的推荐、基于知识的推荐、混合推荐。但协同过滤是面试官和答辩老师听得最多、也最希望通过真实代码看到实现的算法。它不依赖内容理解,只需要用户行为数据就能完成推荐,逻辑简单、效果直观,对毕设的体量来说刚刚好。

1.3 功能模块全景拆解

整个平台按职责拆成六个模块,每个模块都是一个可以单独展开讲解的得分点:

模块核心职责关键技术点
用户模块注册、登录、偏好标签维护Django自带认证+扩展Profile
新闻采集与展示新闻入库、列表展示、详情页爬虫/数据集清洗、分页
用户行为采集浏览、收藏、点赞、停留时长记录埋点接口、异步写入
推荐引擎生成个性化推荐列表ItemCF+UserCF+热度加权混合
数据分析可视化热度趋势、用户画像、推荐效果报表ECharts图表、JSON接口
后台管理新闻管理、用户管理、行为日志查询Django Admin定制

这样的模块划分会让你的工作量看起来非常饱满,同时每个模块都有明确的技术深度,答辩时无论老师问哪一块你都有东西可讲。

2. 数据准备与预处理:推荐系统的弹药库

2.1 新闻数据的获取策略

做推荐系统最怕的是没有数据,或者数据质量太差。这里给你三个由易到难的方案,按自己的时间预算选择:

方案一:直接使用公开数据集。这是最高效的办法。找一个新闻数据集,字段包含标题、正文、分类、发布时间,规模在几千到几万条足够演示。这种数据只需要做简单的去重和空值处理就可以入库。

方案二:爬虫定向采集。如果你想展示爬虫能力,可以爬取几个新闻源站的列表页和详情页。注意控制爬取频率,做好去重和异常处理。这里涉及的政策风险要自己拿捏,建议只做少量演示数据,不要大规模爬取。

方案三:程序自动生成模拟数据。如果实在找不到合适的数据源,可以用 Faker 库结合新闻素材语料库模拟生成一批风格相近的新闻数据。虽然真实度差一些,但对于演示推荐算法逻辑完全够用。

从实战角度,我建议以公开数据集为主,再补充少量自己采集的数据作为增量,这样既有数据量支撑算法效果,又能体现你对数据获取渠道的理解。

2.2 中文文本的清洗与关键词抽取

拿到原始新闻数据后,不能直接丢进推荐引擎。中文文本和英文不同,词与词之间没有空格,需要经过分词才能变成可计算的特征。整体流程是:

  1. 去除HTML标签、特殊字符、多余空格。
  2. 去除停用词,比如“的”“了”“和”“是”这类对语义无贡献的虚词。
  3. 使用 jieba 进行分词,并对分词结果做词频统计。
  4. 提取 top-N 关键词作为新闻的内容标签,存入新闻表。

分词和关键词抽取的意义在于,它是基于内容推荐的基础,同时也能为协同过滤提供补充特征。当行为数据稀疏时,内容标签可以直接作为冷启动推荐依据。

import jieba import jieba.analyse import re def clean_text(text: str) -> str: # 去掉HTML标签和特殊字符 text = re.sub(r'<[^>]+>', '', text) text = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9]', ' ', text) return text.strip() def extract_tags(text: str, topK: int = 5): text = clean_text(text) # 基于TF-IDF提取关键词 tags = jieba.analyse.extract_tags(text, topK=topK, withWeight=False) return ",".join(tags)

2.3 用户行为评分矩阵的设计

协同过滤的核心输入是“用户-新闻”行为矩阵。但用户行为有很多种:浏览、点赞、收藏、评论。这些行为的价值权重不同,不能简单都记成1。我在项目里设计的评分规则是:

  • 浏览:1分
  • 点赞:3分
  • 收藏:5分
  • 评论:4分
  • 停留时间超过阈值:额外加2分

这样处理以后,行为日志表里的每条记录都能换算成一个权重值,最终生成打分矩阵。这个思路很朴素,但它非常实用,比单纯统计用没用过要精确得多,推荐的排序效果也更好。

数据预处理完成后,下一步就是把这份数据喂给推荐算法,这是全项目的核心环节。

3. 推荐算法实现:融合协同过滤与热度加权

3.1 ItemCF与UserCF在新闻场景的取舍

协同过滤分为两类,很多人纠结到底选哪个。我的建议是:主体用基于物品的协同过滤,也就是 ItemCF。

原因有三个:

  • 新闻场景的“物品”数量远小于“用户”数量,相似度矩阵规模更可控。
  • 用户的兴趣会漂移,但新闻之间的语义关联相对稳定,ItemCF 可以做到实时根据近期行为推荐相关新闻。
  • 可解释性好,能给用户看“因为你看过哪篇文章,所以推荐这篇”。

UserCF 并不是不用,而是作为辅助。当用户历史行为足够丰富时,用 UserCF 找出相似用户群,再用群体偏好做补充召回。两种算法按权重融合,就是标题里说的“融合协同过滤”。

3.2 相似度计算与推荐列表生成

相似度计算采用余弦相似度,这是协同过滤里最常见也最稳定的计算方式。两个物品的相似度,取决于哪些用户同时对它们产生过行为,行为向量在高维空间中的夹角越小,相似度越高。

实际工程里,物品的评分向量可能是几万维的,直接两两计算相似度在数据量大时开销很大。但在毕设场景中,新闻量级在几千条,完全可以在后台定时任务中离线计算,把结果缓存到数据库。

import numpy as np from sklearn.metrics.pairwise import cosine_similarity class ItemCF: def __init__(self, user_item_matrix): # user_item_matrix: DataFrame, 行是用户, 列是新闻ID, 值是行为评分 self.user_item_matrix = user_item_matrix.fillna(0) self.item_sim_matrix = None def train(self): # 转置后计算新闻之间的余弦相似度 item_matrix = self.user_item_matrix.T sim = cosine_similarity(item_matrix) self.item_sim_matrix = pd.DataFrame( sim, index=item_matrix.index, columns=item_matrix.index ) def recommend(self, user_id, top_n=10): user_vector = self.user_item_matrix.loc[user_id] # 用户产生过行为的新闻 interacted = user_vector[user_vector > 0].index.tolist() scores = {} for item in interacted: sim_scores = self.item_sim_matrix[item] for candidate, sim_score in sim_scores.items(): if candidate in interacted: continue if candidate not in scores: scores[candidate] = 0.0 scores[candidate] += sim_score * user_vector[item] # 按分数降序取前N个 sorted_scores = sorted(scores.items(), key=lambda x: x[1], reverse=True) return [item for item, score in sorted_scores[:top_n]]

这段代码的逻辑是:先找到用户已经产生过行为的新闻,再遍历这些新闻的相似新闻,用行为评分作为权重累加候选新闻的得分。最终得分可以理解为“该新闻和用户历史偏好之间的加权平均相似度”。

3.3 融合热度加权的排序优化

纯协同过滤有个问题是会把所有历史行为一视同仁,导致老新闻因为累积评分高而反复被推荐。新闻是强时效性内容,昨天的头条今天可能就是垃圾信息。

所以我在最终排序阶段加入了时间衰减和热度因子:

  • 时间衰减:新闻发布每过一天,基础权重衰减5%。
  • 热度因子:近24小时浏览量越高的新闻,额外获得加权。

最终排序分 = 协同过滤得分 * 时间衰减系数 + 热度得分 * 调节比例

这个融合策略让平台的推荐结果既有相关性又有新鲜度,视觉上非常合理,在答辩演示时也能很明显地展示出来。

3.4 冷启动问题的兜底策略

冷启动是推荐系统最经典的难题。新用户没有任何行为记录,协同过滤算不出任何东西;新新闻没有任何用户评分,也参与不了协同过滤。

我的处理方式是三层兜底:

  1. 新用户:引导选择感兴趣的分类标签,根据标签推荐该分类下热门新闻。
  2. 未登录用户:直接推荐全局热度最高的新闻。
  3. 新新闻:进入“最新发布”池,用发布时间排序曝光,积累初始行为数据后再进入协同过滤推荐池。

实现方式很简单,在推荐接口里先判断用户是否有行为记录,如果没有或记录很少,直接走规则推荐,不再调用算法模块。别小看这几行代码,它在你的项目演示中能避免很尴尬的“空白推荐”情况,而且这是推荐系统真实业务里一定会遇到的问题。

4. Django平台工程化实现

4.1 项目目录结构规划

Django 项目要按业务边界划分 app,而不是把所有功能堆在默认的 app 里。我的推荐结构是这样的:

news_recommend/ ├── manage.py ├── config/ # 全局配置 ├── apps/ │ ├── users/ # 用户模块 │ ├── news/ # 新闻模块 │ ├── behavior/ # 行为采集模块 │ ├── recommend/ # 推荐引擎模块 │ └── analytics/ # 数据分析模块 ├── utils/ # 公共工具 ├── static/ └── templates/

注意我用了apps/目录把各功能模块收纳在一起,Django 配置里需要把每个 app 的路径加到INSTALLED_APPS中,比如apps.users。这样做的好处是代码结构清晰,且每个模块都职责单一,答辩时讲解系统架构图会非常方便。

4.2 数据模型设计

数据表的设计直接决定了后续代码的复杂度。设计原则是:业务表尽量冗余字段,行为表尽量精简流程。冗余字段即查询时所需信息直接查出来,避免反复连表,代价是写入时多存一点数据,在毕设场景中这是完全划算的。

四张核心表设计如下:

from django.db import models from django.contrib.auth.models import User class News(models.Model): title = models.CharField(max_length=255, verbose_name="标题") content = models.TextField(verbose_name="正文") category = models.CharField(max_length=32, db_index=True, verbose_name="分类") tags = models.CharField(max_length=255, verbose_name="关键词") source = models.CharField(max_length=64, default="", verbose_name="来源") publish_time = models.DateTimeField(db_index=True, verbose_name="发布时间") view_count = models.IntegerField(default=0, verbose_name="浏览量") created_at = models.DateTimeField(auto_now_add=True) class Meta: db_table = "news" ordering = ["-publish_time"] class UserBehavior(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) news = models.ForeignKey(News, on_delete=models.CASCADE) behavior_type = models.CharField(max_length=16, verbose_name="行为类型") score = models.FloatField(default=1.0, verbose_name="行为评分") created_at = models.DateTimeField(auto_now_add=True, db_index=True) class Meta: db_table = "user_behavior" class NewsSimilarity(models.Model): news = models.ForeignKey(News, related_name="similar_base", on_delete=models.CASCADE) similar_news = models.ForeignKey(News, related_name="similar_target", on_delete=models.CASCADE) similarity = models.FloatField(verbose_name="相似度") created_at = models.DateTimeField(auto_now=True) class Meta: db_table = "news_similarity" class RecommendCache(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) news = models.ForeignKey(News, on_delete=models.CASCADE) rank = models.IntegerField(verbose_name="排名") score = models.FloatField(verbose_name="推荐得分") created_at = models.DateTimeField(auto_now_add=True) class Meta: db_table = "recommend_cache"

NewsSimilarity表用来存储离线计算的新闻相似度结果,RecommendCache表用来存储已经计算好的推荐结果。用户请求推荐接口时,优先读缓存表,这个设计能显著提升系统响应速度。

4.3 行为采集接口的实现

推荐系统依赖用户行为,所以第一步是让前端能实时地把用户行为上报到后端。我用一个统一的行为上报接口接收不同类型的行为记录,然后异步写入数据库。

from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST import json @csrf_exempt @require_POST def collect_behavior(request): """统一行为采集接口""" data = json.loads(request.body) user = request.user if request.user.is_authenticated else None news_id = data.get("news_id") behavior_type = data.get("behavior_type") # view/like/favorite/comment if not news_id or not behavior_type: return JsonResponse({"code": 400, "msg": "参数缺失"}) # 根据行为类型和停留时长计算评分 score_map = {"view": 1, "like": 3, "favorite": 5, "comment": 4} score = score_map.get(behavior_type, 1) stay_seconds = data.get("stay_seconds", 0) if behavior_type == "view" and stay_seconds > 30: score += 2 # 匿名用户也可以记录行为,方便冷启动召回 UserBehavior.objects.create( user=user, news_id=news_id, behavior_type=behavior_type, score=score, ) # 更新新闻热度 News.objects.filter(id=news_id).update(view_count=F("view_count") + 1) return JsonResponse({"code": 200, "msg": "ok"})

前端只需要在用户点击新闻详情、点击收藏按钮、点赞按钮时发起 POST 请求,带上对应的行为类型即可。整个采集链路没有强耦合的业务逻辑,响应速度很快。

4.4 推荐结果的定期更新任务

推荐结果不能每次请求都现算,那样性能太差。我的做法是通过后台定时任务,每隔一段时间批量计算一次相似度矩阵和每个活跃用户的推荐列表,然后把结果缓存到 RecommendCache 表。

实现定时任务的方案有两种:

  • 如果部署环境是 Linux,直接用系统 cron 调用 Django 管理命令。
  • 如果项目里有 Celery,可以做成 Celery Beat 定时任务。

考虑到毕设项目的体量,直接用 cron 最省事,不需要引入额外的中间件。我写了一个 Django 管理命令来自动化整个推荐更新流程:

# apps/recommend/management/commands/update_recommend.py from django.core.management.base import BaseCommand from apps.recommend.core import update_all_recommendations class Command(BaseCommand): help = "更新推荐结果缓存" def handle(self, *args, **options): update_all_recommendations() self.stdout.write(self.style.SUCCESS("推荐缓存更新完成"))

Linux 下只需要一行 crontab 配置,即可在每天凌晨更新:

0 3 * * * cd /path/to/project && python manage.py update_recommend >> logs/recommend.log 2>&1

5. 数据分析可视化:让推荐效果看得见

5.1 可视化指标体系设计

推荐平台如果没有数据可视化,就只是一个普通新闻网站。可视化页面的核心价值在于回答三个问题:

  • 平台内容生态怎么样:各分类新闻数量分布、发布趋势。
  • 用户行为有什么规律:用户活跃时段、行为类型占比、分类偏好。
  • 推荐系统效果好不好:推荐内容的点击率、曝光量、用户行为转化。

不要试图在一个页面上展示所有图表,信息过载反而显得业余。我的建议是设计三个页签:内容分析、用户画像、推荐效果。每个页签放两到三个图表,每个图表都有明确的分析结论。

5.2 后端JSON接口设计

可视化页面采用前端请求后端 JSON 接口的方式获取数据。后端负责从数据库聚合统计,前端收到数据后渲染图表。这里给出两个典型接口的实现思路。

分类热度趋势接口:统计每个分类在最近7天的新闻发布量和浏览量,返回给前端绘制堆叠折线图。

from django.http import JsonResponse from django.db.models import Count, Sum from django.utils import timezone from datetime import timedelta from apps.news.models import News, UserBehavior def category_trend(request): end_date = timezone.now().date() start_date = end_date - timedelta(days=6) result = [] for i in range(7): day = start_date + timedelta(days=i) stats = News.objects.filter(publish_time__date=day).values("category").annotate( count=Count("id"), views=Sum("view_count") ) result.append({ "date": day.strftime("%m-%d"), "categories": {item["category"]: {"count": item["count"], "views": item["views"]} for item in stats} }) return JsonResponse({"code": 200, "data": result})

用户行为分布接口:从 UserBehavior 表按行为类型聚合数量,绘制饼图,直观展现用户的参与深度。

def behavior_distribution(request): stats = UserBehavior.objects.values("behavior_type").annotate( total=Count("id") ) # 统计数据总体占比较小,比如行为类型只有4种,无需分页 data = {item["behavior_type"]: item["total"] for item in stats} return JsonResponse({"code": 200, "data": data})

5.3 前端图表渲染方案

前端推荐使用 ECharts,它支持图表类型多、交互效果好、中文文档完善,接入成本很低。

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>平台数据分析</title> <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script> </head> <body> <div id="trendChart" style="width: 100%; height: 400px;"></div> <script> fetch('/api/analytics/category_trend/') .then(res => res.json()) .then(res => { const data = res.data; const dates = data.map(item => item.date); const categories = Object.keys(data[0].categories || {}); const series = categories.map(cat => ({ name: cat, type: 'line', data: data.map(item => (item.categories[cat] || { views: 0 }).views) })); const chart = echarts.init(document.getElementById('trendChart')); chart.setOption({ title: { text: '新闻分类浏览量趋势' }, tooltip: { trigger: 'axis' }, legend: { data: categories }, xAxis: { type: 'category', data: dates }, yAxis: { type: 'value' }, series }); }); </script> </body> </html>

可视化页面不需要做得很炫酷,关键是数据准确、结论清晰。你可以把图表和分析结论放在一起,比如图表下面加一段文字说明:“从图中可以看出,科技类新闻的浏览量在工作日达到峰值,建议在晚间增加科技类内容的推荐权重。”这种话术配合图表在答辩时非常有说服力。

6. 性能优化与部署上线

6.1 推荐接口的响应优化

如果推荐接口每次都要把相似度矩阵读过一遍现算,那系统一定慢到没法用。我在项目中做了两级缓存:

第一级:预计算结果缓存表。推荐列表提前算好存库,用户请求直接查 RecommendCache 表,通过索引和 limit 查询,响应时间通常在几十毫秒级别。

第二级:Redis 缓存。如果系统里已经装了 Redis,可以把热门用户的推荐结果直接缓存到 Redis Key 中,设置过期时间 1 小时,进一步减少数据库查询压力。

import redis import json r = redis.Redis(host="localhost", port=6379, db=0) def get_recommend_from_cache(user_id): key = f"recommend:{user_id}" cached = r.get(key) if cached: return json.loads(cached) # 查数据库 recs = RecommendCache.objects.filter(user_id=user_id).order_by("rank")[:20] data = [{"news_id": r.news_id, "title": r.news.title, "score": r.score} for r in recs] r.setex(key, 3600, json.dumps(data)) return data

6.2 数据库查询优化

数据库是 Django 项目最容易出性能问题的地方,最常见的坑是 N+1 查询。比如在新闻列表页显示每条新闻的作者、分类名称时,如果循环查询每个外键,会造成大量重复 SQL。

解决办法是使用select_related或prefetch_related提前联表查询:

# 错误写法:每行额外查询N次 news_list = News.objects.all() for n in news_list: print(n.category) # 每次触发一次查询 # 正确写法:一次JOIN查完 news_list = News.objects.select_related("category").all()

在我的项目中,新闻列表、推荐列表都使用了这个方法,整体查询数从几百次降到了个位数,页面加载速度提升非常明显。

6.3 部署环境准备

本项目可以用阿里云或腾讯云的轻量服务器部署,选 2核4G 配置即可,价格不高,完全够演示使用。部署过程建议使用 Nginx + Gunicorn + MySQL 的组合。

部署的几个关键配置点:

  1. settings.py中设置DEBUG = False,配置ALLOWED_HOSTS。
  2. 通过python manage.py collectstatic收集静态文件,交给 Nginx 处理。
  3. Gunicorn 启动命令指定多 worker,比如 3 个,提升并发能力。
  4. MySQL 字符集要设置为utf8mb4,避免中文乱码。
# gunicorn启动脚本示例 gunicorn config.wsgi:application \ --bind 0.0.0.0:8000 \ --workers 3 \ --max-requests 1000 \ --timeout 120

Nginx 配置的核心是反向代理 Django 服务,同时托管静态文件:

server { listen 80; server_name your_domain.com; location /static/ { alias /path/to/project/static/; } location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

整个部署流程走通以后,你不仅完成了一个推荐平台,还具备了对互联网应用从开发到上线的全链路认知,这个能力在答辩和简历上都很加分。

7. 常见问题与排查技巧实录

做这个项目时我遇到且解决过的问题远不止下面几条,但下面这六个是出现频率最高也最具代表性的,拿出来分享。

7.1 新手最容易踩的坑速查表

问题典型表现原因解决方案
推荐结果全是同一分类新闻列表页内容高度相似相似度矩阵训练不充分,只关注了强关联内容在排序中加入分类多样性惩罚,或对相似度做阈值过滤
新用户推荐列表为空前端页面空白没有处理冷启动增加用户偏好选择,走规则推荐兜底
行为数据无法统计图表显示0前端未正确调用埋点接口,或跨域问题检查前端请求、后端日志,用curl手动模拟POST
相似度计算缓慢管理命令执行超时相似度矩阵是O(N^2)的计算复杂度控制新闻总量在万条内,或分批次计算并缓存
推荐结果不实时更新用户行为后推荐没变化定时任务还没到执行时间复制管理命令,在需要时手动执行更新
中文乱码页面显示“?”或乱码符号数据库字符集不是utf8mb4修改数据库表和连接配置,重建数据

7.2 数据稀疏导致的推荐质量问题

协同过滤对行为数据量的要求很高,如果本地测试只有一两个用户产生行为,推荐结果基本就是平的,没有个性差异。我在调试时用脚本批量生成了50个模拟用户的行为数据,每个用户随机对20到50篇新闻产生浏览、点赞行为,一下就缓解了数据稀疏问题。

生成模拟行为的脚本并不复杂,但非常实用:

import random from apps.users.models import User from apps.news.models import News, UserBehavior def generate_mock_behavior(): users = User.objects.filter(is_superuser=False) news_ids = list(News.objects.values_list("id", flat=True)) intercept = len(news_ids) // 3 # 确保有一定量的公共行为,丰富相似度矩阵 for user in users: sample = random.sample(news_ids, random.randint(20, 50)) for nid in sample: behavior = random.choice(["view", "like", "favorite"]) score = {"view": 1, "like": 3, "favorite": 5}[behavior] if random.random() < 0.3: UserBehavior.objects.create( user=user, news_id=nid, behavior_type=behavior, score=score )

7.3 相似度矩阵对角线过热问题

在计算新闻相似度时,物品和自己肯定是完全相似的,相似度为1。如果不做过滤,推荐时会大量推荐用户看过的新闻本身或者是同一篇文章的转载版本。这个问题的处理方式很简单:

# 在训练后把对角线置为0,并且过滤相似度低于0.3的记录 np.fill_diagonal(self.item_sim_matrix.values, 0) sim_matrix = sim_matrix[sim_matrix > 0.3]

同时,在推荐代码里已经排除了用户交互过的新闻,但转载和同主题内容还是可能混进来,这时候内容标签就能派上用场:如果两条新闻提取出的关键词重合度超过80%,视为重复内容,只保留最新发布的一篇。

7.4 推荐接口超时的排查思路

我曾经遇到过一个很奇怪的现象:推荐接口在本地测试一切正常,部署到服务器后经常超时。排查后发现是服务器上的 MySQL 配置没有调优,默认的连接数太小,而推荐缓存表没有加索引,导致全表扫描。

解决方法是给 RecommendCache 表的 user_id 字段加复合索引:

class RecommendCache(models.Model): class Meta: db_table = "recommend_cache" indexes = [ models.Index(fields=["user", "rank"]), ]

此外,把缓存数据的更新时间改为增量更新模式:只在用户产生新行为的10分钟内更新对应单个用户的推荐缓存,而不是全量重算所有用户的推荐列表。这个优化把服务器的CPU占用率从90%降到了30%以下。

7.5 前端跨域问题的快速处理

如果前端页面和 Django 服务不在同一个域名下,需要处理跨域请求。最简单的方案是安装django-cors-headers:

pip install django-cors-headers

在 settings.py 里配置:

INSTALLED_APPS = [ # ... "corsheaders", ] MIDDLEWARE = [ # ... "corsheaders.middleware.CorsMiddleware", ] CORS_ALLOW_ALL_ORIGINS = True

注意这是开发环境的方便配置,生产环境应该把CORS_ALLOW_ALL_ORIGINS设为 False,改用CORS_ALLOWED_ORIGINS指定具体域名。

7.6 定时任务不执行的潜在问题

使用 crontab 跑 Django 管理命令时,最常见的问题是 Python 环境和项目目录配置不正确。crontab 执行时的环境变量与登录 shell 不同,需要手动指定绝对路径:

0 3 * * * cd /path/to/project && /usr/bin/python3 manage.py update_recommend >> /path/to/logs/recommend.log 2>&1

切记先打印日志,看看到底是定时任务没触发,还是触发了但报错。只要在 crontab 里把标准错误重定向到日志文件,绝大多数问题都能通过日志定位到。

8. 扩展方向与我的个人体会

项目做到这里,基础功能已经非常完整。但如果还有时间和精力,我建议从下面几个方向去做扩展,这些都是当前推荐系统和大模型结合的热门方向:

接入大语言模型生成个性化摘要。每篇新闻详情页除了展示原始正文,还可以用大模型生成一段简洁摘要,让用户更快了解文章要点。更进一步,可以根据用户的历史兴趣偏好,用大模型生成针对性的推荐理由,比如“因为你关注人工智能,所以推荐这篇关于大模型应用的报道”。这种个性化解释在答辩时就是一个很大的亮点,而且能自然地说明你不是只会调API,而是对推荐产品的交互设计有思考。

把规则推荐升级为逻辑回归排序模型。融合协同过滤目前还是用人工加权的方式合并得分。你可以准备一个特征集,包括协同过滤得分、新闻热度、时效性、用户对分类的偏好强度等,训练一个逻辑回归模型去做最终排序。这样就把项目从“协同过滤”升级到了“学习排序”,技术深度再上一个台阶。

增加用户兴趣画像的可视化。除了推荐列表,还可以为用户生成一个兴趣标签云,展示用户最喜欢的内容分类和关键词。这个功能不需要额外开发算法,只需要从行为记录里统计标签出现频率,用词云组件渲染即可。视觉效果好、实现成本低,能进一步提升平台的完整度。

我的体会是:做这类项目,最重要的是把主干链路先跑通,再逐步加花。如果一开始就想着把所有推荐算法都实现一遍、把页面做到极致精致,很容易陷入焦虑和无止境的调试。你只要先把“用户看新闻 -> 行为记录 -> 推荐列表 -> 展示分析图表”这个闭环走通,整个系统就成功了一大半。之后再根据时间和精力,去选择一个最有把握的方向做深入优化。

最后再说一个小技巧:项目的 README 文档一定要认真写。把架构图、功能清单、算法说明、部署步骤、测试账号都整理好,这不仅是答辩前复习的最佳资料,也是面试时可以给面试官展示的项目说明书。代码可能被遗忘,但一份好的项目文档能帮你把整个项目的价值稳定地传递给别人。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 5:53:47

SSA-VMD自适应分解:麻雀算法自动优化VMD参数的方法与实践

1. 变分模态分解的参数之痛&#xff1a;K和alpha为什么让人头疼先说个我自己的经历。早几年我第一次用变分模态分解&#xff08;VMD&#xff09;处理振动信号时&#xff0c;被两个参数折腾得够呛&#xff1a;一个是模态分解数K&#xff0c;一个是惩罚因子alpha。K是指定把信号拆…

作者头像 李华
网站建设 2026/10/22 5:53:40

2026蓝队护网应急响应全流程:从告警发现到溯源恢复的实战拆解

做蓝队应急响应这几年&#xff0c;身边总有朋友问我&#xff1a;“护网期间你们蓝队到底在忙什么&#xff1f;是不是一直在盯着告警屏幕&#xff1f;”说实话&#xff0c;大部分时间确实是在盯告警、看日志、封IP&#xff0c;但这只是表面。真正考验人的是当一条高危告警弹出来…

作者头像 李华
网站建设 2026/10/22 5:52:09

AI Agent入门:先建思维模型,再学框架

1. 这不是学编程&#xff0c;是重建“做事的思维模型”“AI Agent 入门&#xff1a;新手和转行者先学什么&#xff0c;别一上来就啃框架”——这句话我去年在某高校开放日现场听一位带过三十多个AI项目的学生导师讲完&#xff0c;台下二十多个刚辞职准备转行的35岁从业者集体沉…

作者头像 李华
网站建设 2026/10/22 5:52:09

iOS开发实战:Token + MD5 + RSA 接口认证方案详解

1. 项目概述与整体设计思路1.1 这个项目解决了什么问题在iOS客户端开发中&#xff0c;网络认证是每一款App都绕不开的环节。不管是登录接口、支付接口还是数据同步接口&#xff0c;只要涉及用户身份和敏感数据&#xff0c;都需要一套可靠的认证方案。我见过不少项目在初期为了赶…

作者头像 李华
网站建设 2026/10/22 5:52:08

电子名片如何撬动低成本获客?从工具选型到数据复盘全解析

在商务场合混久了&#xff0c;你会发现一个挺现实的问题&#xff1a;名片收了一堆&#xff0c;真正能转化成后续合作的寥寥无几。纸质名片递出去&#xff0c;对方随手放进名片夹&#xff0c;加微信还得现场扫码&#xff0c;回去之后想找这个人聊点事&#xff0c;对着那张小卡片…

作者头像 李华
网站建设 2026/10/22 5:51:10

Dify接入PostgreSQL:用DBHub网关实现统一数据库连接管理

最近在做某AI应用平台的私有化部署&#xff0c;需要把Dify的元数据落到PostgreSQL上。按照运维侧的规矩&#xff0c;所有数据库访问不能由业务应用直连&#xff0c;必须走统一的连接管理入口。折腾下来&#xff0c;我在Dify和PostgreSQL之间加了一层DBHub作为数据库连接网关&am…

作者头像 李华