首页 > 其他分享 >个性化推荐系统-离线召回模型验证

个性化推荐系统-离线召回模型验证

时间:2024-08-28 09:24:06浏览次数:6  
标签:mediaid uid get 离线 cursor connection 召回 page 个性化

文章目录

背景

计划构建并优化一个覆盖前端与后端的个性化推荐系统中的离线召回模块。
此模块旨在通过高效的数据处理与分析,预先筛选出用户可能感兴趣的内容或商品,为后续的实时推荐流程提供丰富且精准的候选集。为了确保实施效果与性能,我们将设计最简前端界面以直观展示召回结果,同时构建后端服务来处理大量数据并响应前端请求。

在前端部分,将开发用户基本的交互界面,允许用户在不影响系统性能的前提下,轻松浏览和反馈召回结果,支持切换用户查询,从而辅助验证推荐算法的有效性与准确性。

后端方面,以验证模型以及算法为主,验证过程中不采用离线计算框架(
Spark、Hadoop、Hive),不设置缓存层。

具体参考
个性化推荐系统-离线召回模型框架

前端

使用vue开发

核心组件

<div class="title-with-margin">
      <h2>个性化推荐系统</h2>
    </div> 
    <!-- Top section with input and button -->
    <div class="input-and-button">
      <el-input v-model="uid" placeholder="请输入 UID(1-600)" clearable @keyup.enter="fetchUserData" />
      <el-button type="primary" @click="fetchUserData(currentPage.value)">推荐</el-button>
      <el-button type="primary" @click="gethistory(historycurrentPage.value)">历史行为</el-button>
    </div>

    <!-- Bottom section with pagination and list -->
    <el-table :data="userData" style="width: 100%; margin-top: 1rem;">
      <el-table-column prop="name" label="名称" width="220"> </el-table-column>
      <el-table-column prop="mediatype" label="类型" width="150"> </el-table-column>
      <el-table-column prop="catid" label="分类" width="100"> </el-table-column>    
       <el-table-column prop="abstract" label="简介" width="550" show-overflow-tooltip> </el-table-column>
       <!-- <el-table-column prop="content" label="内容" > </el-table-column> -->
       <el-table-column label="操作" width="150">
        <template #default="{ row }">
          <el-button size="small" type="text" @click="showreco(row)">操作</el-button>
        </template>
      </el-table-column>
    </el-table>

模拟操作

<el-dialog v-model="showDialog" title="模拟操作" width="60%">
      <div>
        <el-row :gutter="20">
        <el-col :span="6">
          <!-- icon="el-icon-thumb" -->
          <el-button :type="isLiked ? 'success' : 'primary'"  type="text" @click="onLike(currentMedia)">点赞 </el-button>
        </el-col>
        <el-col :span="6">
          <el-button :type="isPlay ? 'success' : 'primary'" type="text" @click="onView(currentMedia)">观看</el-button>
        </el-col>
        <el-col :span="6">
          <el-button :type="isColl ? 'success' : 'primary'" @click="onCollect(currentMedia)">收藏</el-button>
        </el-col>
        <el-col :span="6">
          <el-button :type="isShare ? 'success' : 'primary'" @click="onForward(currentMedia)">转发</el-button>
        </el-col>        
        </el-row>
      </div>    
       <div style="margin-top: 10px;">  
        <div >播放完整度</div>
        <div class="slider-demo-block">         
          <el-slider v-model="playrate" show-input @change="playhandleChange"/>
        </div>
       </div>       
      <h3>相关推荐</h3>
       <el-table :data="userData2" style="width: 100%; margin-top: 1rem;">
      <el-table-column prop="name" label="名称" width="200"> </el-table-column>
      <el-table-column prop="mediatype" label="类型" width="80"> </el-table-column>
      <el-table-column prop="catid" label="分类" width="120"> </el-table-column>
      <el-table-column prop="abstract" label="简介" width="300"> </el-table-column>       
      </el-table>
          <el-pagination
          background
          layout="prev, pager, next"
          :total="totalItems2"
          :page-size="pageSize"
          :current-page="currentPage2"
          @current-change="handleCurrentChange2"
          >
          </el-pagination>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="showDialog = false">关闭</el-button>
        </span>
      </template>
    </el-dialog>

用户历史行为

  <el-dialog v-model="historyshowDialog" title="用户历史操作记录" width="65%">           
     
      <el-table :data="historyuserData" style="width: 100%; margin-top: 1rem;">
      <el-table-column prop="name" label="名称" width="200"> </el-table-column>
      <el-table-column prop="mediatype" label="类型" width="80"> </el-table-column>
      <el-table-column prop="catid" label="分类" width="100"> </el-table-column>      
      <el-table-column prop="abstract" label="简介" width="300"> </el-table-column> 
      <el-table-column prop="score" label="评分" width="80"> </el-table-column>
      </el-table>
          <el-pagination
          background
          layout="prev, pager, next"
          :total="hisrorytotalItems"
          :page-size="pageSize"
          :current-page="historycurrentPage"
          @current-change="historyhandleCurrentChange"
          >
          </el-pagination>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="historyshowDialog = false">关闭</el-button>
        </span>
      </template>
    </el-dialog>

const get_history_api = async (page = historycurrentPage.value) => {
  console.log(historycurrentPage.value,page)
  try {
    const response = await axios.get('http://127.0.0.1:5000/useraction', {
      params: {
        page:  parseInt(page),
        pageSize: pageSize.value,
        uid: uid.value
      }
    });
    console.log(response.data.data)   
    historyuserData.value = response.data.data;
    hisrorytotalItems.value = response.data.total;
  } catch (error) {
    console.error('Error fetching data:', error);
  }
};

后端

导入依赖

from flask import Flask, request, jsonify
import pymysql
from flask_cors import CORS

启动服务

app = Flask(__name__)
CORS(app)
app.config['JSON_AS_ASCII'] = False

## db_config 数据库配置文件 参考之前的样例
def get_db_connection():
    return pymysql.connect(**db_config)

if __name__ == '__main__':    
    app.run(host='127.0.0.1', port=5000,debug=True)

根据uid获取推荐列表

解析参数,判断uid是否为0,分别进行不同处理

@app.route('/medialist', methods=['GET'])
def get_users():
    page = int(request.args.get('page', 1))
    per_page = int(request.args.get('pageSize', 10))
    try:
        uid = int(request.args.get('uid', '0'))
    except ValueError:
        uid = 0
    print("uid",uid)
    offset = (page - 1) * per_page
    res = "0" if page > 0 else "-1"
    total=300
    connection = get_db_connection()
    if(uid<=0):
        try:
            with connection.cursor() as cursor:
                sql = "SELECT mediaid,name,CONCAT(catid,subcatid,tag) AS catid,mediatype,abstract FROM mediainfo ORDER BY RAND() LIMIT %s OFFSET %s"
                #cursor.execute(sql, (per_page, offset))
                #results = cursor.fetchall()
                #users = [{'id': row[0], 'name': row[1]} for row in results]           
                cursor.execute(sql, (per_page, offset))
                results = cursor.fetchall()            
                resdata = { "res": res,"total": total,"data":results}
                return jsonify(resdata), 200
        finally:
            connection.close()
    else:
        total=100
        try:
            with connection.cursor() as cursor:
                sql = "SELECT  m.mediaid, m.name,CONCAT(m.catid,m.subcatid,m.tag) AS catid,m.mediatype,m.abstract FROM  uid_reco ur JOIN  mediainfo m ON ur.mediaid = m.mediaid WHERE  ur.uid = %s LIMIT %s OFFSET %s"
                #cursor.execute(sql, (per_page, offset))
                #results = cursor.fetchall()
                #users = [{'id': row[0], 'name': row[1]} for row in results]           
                cursor.execute(sql, (uid,per_page, offset))
                results = cursor.fetchall()            
                resdata = { "res": res,"total": total,"data":results}
                return jsonify(resdata), 200
        finally:
            connection.close()


相关推荐

内容相似度计算参考
相似度计算

@app.route('/relatereco', methods=['GET'])
def get_relate_reco():
    page = int(request.args.get('page', 1))
    per_page = int(request.args.get('pageSize', 10))
    try:
        mediaid = int(request.args.get('mediaid', '0'))
    except ValueError:
        mediaid = 0
    print("relatereco - mediaid",mediaid)
    offset = (page - 1) * per_page
    res = "0" if page > 0 else "-1"
    
    connection = get_db_connection()
    total=100
    try:
        with connection.cursor() as cursor:
            sql = "SELECT m.mediaid,m.name, CONCAT(m.catid, m.subcatid, m.tag) AS catid,  m.mediatype,  m.abstract FROM  media_similarity ms   JOIN mediainfo m   ON ms.mediaid_2 = m.mediaid WHERE ms.mediaid_1 = %s  LIMIT %s OFFSET %s"
            cursor.execute(sql, (mediaid,per_page, offset))
            results = cursor.fetchall()            
            resdata = { "res": res,"total": total,"data":results}
            return jsonify(resdata), 200
    finally:
        connection.close()

用户历史记录

app.route('/useraction', methods=['GET'])
def get_user_action():
    page = int(request.args.get('page', 1))
    per_page = int(request.args.get('pageSize', 10))
    try:
        uid = int(request.args.get('uid', '0'))
    except ValueError:
        uid = 0
    print("relatereco - mediaid",uid)
    offset = (page - 1) * per_page
    res = "0" if page > 0 else "-1"
    total=100
    connection = get_db_connection()   
    try:
        with connection.cursor() as cursor:
            sql = "SELECT m.mediaid,m.name,CONCAT(m.catid, m.subcatid, m.tag) AS catid,  m.mediatype,  m.abstract,u.score FROM  user_rate u  JOIN mediainfo m   ON u.mediaid= m.mediaid WHERE u.uid = %s  LIMIT %s OFFSET %s"
            cursor.execute(sql, (uid,per_page, offset))
            results = cursor.fetchall()            
            resdata = { "res": res,"total": total,"data":results}
            return jsonify(resdata), 200
    finally:
        connection.close()

用户行为数据上报

def handle_user_action():
    # 解析请求体中的 JSON 数据
    data = request.get_json()
    
    # 获取 uid, mediaid, score
    uid = data.get('uid')
    mediaid = data.get('mediaid')
    score = data.get('score')
    
    if not (uid and mediaid and score):
        return jsonify({'error': 'Missing required fields'}), 400
    connection = get_db_connection()   
    try:
        with connection.cursor() as cursor:
            sql = "insert user_rate (uid,mediaid,score)values(%s,%s,%s)"
            cursor.execute(sql, (uid,mediaid, score))
            results = cursor.fetchall()            
            resdata = { "res": results}
            return jsonify(resdata), 200
    finally:
        connection.close()
        return jsonify({'error': 'DB connection fields'}), 400

标签:mediaid,uid,get,离线,cursor,connection,召回,page,个性化
From: https://blog.csdn.net/zhangdonghuirjdd/article/details/141609347

相关文章

  • 超赞!PaddleOCR在国产麒麟系统中的离线绿色部署
    一、背景在信创(信息技术应用创新)背景下,OCR(OpticalCharacterRecognition,光学字符识别)技术的需求日益增长,主要体现在以下几个方面:首先,随着国家信创战略的推进,自主可控和信息安全成为关键议题。OCR技术作为信息技术的重要组成部分,其国产化、自主可控的需求日益迫切。这要求OCR技......
  • 【黑深化-悟空】离线完整免安装版+全能修改器2款补丁
    3DM风灵月影大神已经为这款游戏推出了首款35项修改器,轻松通关!基础无敌模式,还是希望拥有无限生命、法力和气力,无线棍势,无限七十二变……总计35项  修改器功能一览:-数字键1-无敌模式/无视伤害判定-数字键2-无限生命-数字键3-无限法力-数字键4-无限气力......
  • java在项目中实现个性化定制的数据可视化图表———静态,动态获取数据
    一、Echarts介绍ECharts是一款基于JavaScript的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。ECharts最初由百度团队开源,并于2018年初捐赠给Apache基金会,成为ASF孵化级项目。2021年1月26日晚,Apache基金会官方宣布ECharts项目正式毕业。1月28日,EChar......
  • 推荐算法实战五-召回(下)
    一、FM的召回功能(一)打压热门物料FM主要应用于U2I召回场景,正样本采用与用户正向交互过的样本。负样本来源于两个途径,一个是随机采样,一个是曝光但未点击的负向物料。由于热门物料曝光率高,因此正负样本中热门物料参与度都不小,为了确保推荐结果的多样性,对正负样本分别采取不同的......
  • UE5蓝图 离线实时语音转文字插件 教程 c/c++插件 毫秒级响应 比http更节约资源
    UE5蓝图实现离线实时语音转文字插件教程如何用UE5蓝图实现离线实时语音转文字,实时接收麦克风音频并且快速的转换成文字。那么我来分享一下ez2txt这个插件。bilibili使用教程效果展示:蓝图:只要启动麦克风就可以了,其他的繁琐步骤插件都封装好了。参数说明Rule1_m......
  • 个人博客导航如何创建更有个性化?
    个人博客导航如何创建更有个性化?创建个性化博客导航是一个既实用又能体现个人风格的过程。以下是一些步骤和建议,帮助你完成这一过程:一、确定导航需求和内容明确目的:首先,你需要明确博客导航的主要目的是什么,比如是为了方便读者查找特定内容、展示你的博客结构,还是为......
  • FlashFace——高保真度个性化人脸生成技术
    人工智能咨询培训老师叶梓转载标明出处在图像生成领域,AI技术的每一次突破都可能带来革命性的应用变革。在这样的背景下,来自香港大学和阿里巴巴集团的研究团队提出了一种名为FlashFace的新技术,旨在通过提供少量参考人脸图片和文本提示,实现个性化的人脸生成。FlashFace技术能够......
  • 基于python+flask框架的网课个性化推荐系统的设计与实现(开题+程序+论文) 计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,网络教育已成为现代教育体系中的重要组成部分。尤其在疫情期间,网课以其便捷性、灵活性和资源丰富的特点,受到了广......
  • 个性化音乐推荐系统 项目编号:14982(案例分享) +V:可免费领取源代码
    摘  要    在数字化音乐时代,用户面临着海量的音乐选择,如何从中筛选出符合个人口味的音乐成为了一个重要的问题。传统的音乐推荐方式,如基于热门榜单、新歌推荐等,虽然能在一定程度上满足用户的需求,但往往缺乏个性化和精准度。因此,开发一个个性化音乐推荐系统显得尤......
  • 黑神话悟空离线完整版+修改器
    作为一款单机游戏,《黑神话:悟空》不包含联网要素,完全依赖玩家的操作技巧和策略。游戏的设计中融入了成熟的挑战机制,对于老手玩家来说,丰富的技能组合和策略玩法让战斗更具深度和趣味。而对于新手玩家来说,虽然游戏缺少“难度选项”,并且更偏向ACT(动作游戏)的一侧,但这并不意味......