IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> SparrowRecys——线上服务 -> 正文阅读

[系统运维]SparrowRecys——线上服务

一、线上服务主要内容

  • 把候选物品和离线处理好的特征载入到服务器
  • 将离线模型上线
  • 在线进行模型服务(model serving)
    如何做到负载均衡、缓存、推荐服务降级机制:

二、本项目选择服务器——Jetty服务器

Jetty服务器

public class RecSysServer {
    //主函数,创建推荐服务器并运行
    public static void main(String[] args) throws Exception {
        new RecSysServer().run();
    }
    //推荐服务器的默认服务端口6010
    private static final int DEFAULT_PORT = 6010;


    //运行推荐服务器的函数
    public void run() throws Exception{
        int port = DEFAULT_PORT;
        //绑定IP地址和端口,0.0.0.0代表本地运行
        InetSocketAddress inetAddress = new InetSocketAddress("0.0.0.0", port);
        //创建Jetty服务器
        Server server = new Server(inetAddress);
        //创建Jetty服务器的环境handler
        ServletContextHandler context = new ServletContextHandler();
        context.setContextPath("/");
        context.setWelcomeFiles(new String[] { "index.html" });


        //添加API,getMovie,获取电影相关数据
        context.addServlet(new ServletHolder(new MovieService()), "/getmovie");
        //添加API,getuser,获取用户相关数据
        context.addServlet(new ServletHolder(new UserService()), "/getuser");
        //添加API,getsimilarmovie,获取相似电影推荐
        context.addServlet(new ServletHolder(new SimilarMovieService()), "/getsimilarmovie");
        //添加API,getrecommendation,获取各类电影推荐
        context.addServlet(new ServletHolder(new RecommendationService()), "/getrecommendation");
        //设置Jetty的环境handler
        server.setHandler(context);


        //启动Jetty服务器
        server.start();
        server.join();
    }

三、存储模块redis

前言:类似Embedding特征是在离线环境下生成的,而推荐服务器是在线上环境中运行的。那离线特征数据是如何导入到线上让推荐服务器使用?
需要一个中介redis将embedding存入,线上模型推荐再将redis里的embedding取出。

  • 分级存储:把越频繁访问的数据放到越快的数据库甚至缓存里,把海量的全量数据放到廉价但是查询速度较慢的数据库中。
    在这里插入图片描述
    SparrowRecsys采取的分级存储策略:
  • 用户特征总数较大,难以全部存入服务器内存中,将其存入redis里。
  • 物品特征总数较小,将其存入服务器内存中。
  • HDFS(单机环境下以本机文件系统为例)存储每次处理的全量特征和训练得到的embedding。。
    在这里插入图片描述
    Redis基础知识:
  • Redis所有数据以key-value形式存储,key只能是字符串,value支持结构有string(字符串)、list(链表)、set(集合)、zset(有序集合) 和 hash(哈希)。
  • Redis的QPS峰值很高,还有数据易丢失,不应该把关键业务数据存储在Redis中。
  • Redis基本操作:set、get、keys,value的数据类型用到了string.
    将Embedding向量存入redis中:

if (saveToRedis) {
  //创建redis client
  val redisClient = new Jedis(redisEndpoint, redisPort)
  val params = SetParams.setParams()
  //设置ttl为24小时
  params.ex(60 * 60 * 24)
  //遍历存储embedding向量
  for (movieId <- model.getVectors.keys) {
    //key的形式为前缀+movieId,例如i2vEmb:361
    //value的形式是由Embedding向量生成的字符串,例如 "0.1693846 0.2964318 -0.13044095 0.37574086 0.55175656 0.03217995 1.327348 -0.81346786 0.45146862 0.49406642"
    redisClient.set(redisKeyPrefix + ":" + movieId, model.getVectors(movieId).mkString(" "), params)
  }
  //关闭客户端连接
  redisClient.close()
}

将embedding向量从redis取出:在服务器端,希望将服务器把所有物品Embedding向量阶段性缓存在服务器内部,用户embedding进行实时查询。
过程:先用keys把所有物品embedding向量前缀键找出,依次将embedding向量载入内存。


//创建redis client
Jedis redisClient = new Jedis(REDIS_END_POINT, REDIS_PORT);
//查询出所有以embKey为前缀的数据
Set<String> movieEmbKeys = redisClient.keys(embKey + "*");
int validEmbCount = 0;
//遍历查出的key
for (String movieEmbKey : movieEmbKeys){
    String movieId = movieEmbKey.split(":")[1];
    Movie m = getMovieById(Integer.parseInt(movieId));
    if (null == m) {
        continue;
    }
    //用redisClient的get方法查询出key对应的value,再set到内存中的movie结构中
    m.setEmb(parseEmbStr(redisClient.get(movieEmbKey)));
    validEmbCount++;
}
redisClient.close();

具体到为用户推荐过程中,利用接口查出用户embedding,与内存中embedding进行相似度计算,得到最终的推荐列表。

本项目存储embedding使用方式为分布式文件系统+Redis+服务器内存。
value除了设置为string格式还能有其他存储结构存储embedding向量数据?

  • redis keys命令不能用在生产环境中,如果数量过大效率十分低,导致redis长时间堵塞在keys上。
  • Redis value 可以用pb格式存储, 存储上节省空间. 解析起来相比string, cpu的效率也应该会更高

四、召回层

推荐物品规模庞大时,如何快速又准确筛选掉不相关物品,从而节约排序时所消耗的资源。
召回层策略有:

  • 单策略召回:制定一条规则或一个简单模型快速召回可能相关物品
  • 多路召回:采用不同的策略、特征或简单模型,分别召回一部分候选集,然后把候选集混合在一起供后序排序模型使用策略。
  • 基于embedding召回

public static List<Movie> retrievalCandidatesByEmbedding(User user){
    if (null == user){
        return null;
    }
    //获取用户embedding向量
    double[] userEmbedding = DataManager.getInstance().getUserEmbedding(user.getUserId(), "item2vec");
    if (null == userEmbedding){
        return null;
    }
    //获取所有影片候选集(这里取评分排名前10000的影片作为全部候选集)
    List<Movie> allCandidates = DataManager.getInstance().getMovies(10000, "rating");
    HashMap<Movie,Double> movieScoreMap = new HashMap<>();
    //逐一获取电影embedding,并计算与用户embedding的相似度
    for (Movie candidate : allCandidates){
        double[] itemEmbedding = DataManager.getInstance().getItemEmbedding(candidate.getMovieId(), "item2vec");
        double similarity = calculateEmbeddingSimilarity(userEmbedding, itemEmbedding);
        movieScoreMap.put(candidate, similarity);
    }
   
    List<Map.Entry<Movie,Double>> movieScoreList = new ArrayList<>(movieScoreMap.entrySet());
    //按照用户-电影embedding相似度进行候选电影集排序
    movieScoreList.sort(Map.Entry.comparingByValue());


    //生成并返回最终的候选集
    List<Movie> candidates = new ArrayList<>();
    for (Map.Entry<Movie,Double> movieScoreEntry : movieScoreList){
        candidates.add(movieScoreEntry.getKey());
    }
    return candidates.subList(0, Math.min(candidates.size(), size));
}

embedding召回过程:

  • 获取用户embedding
  • 获取影片候选集:选取10000部热门电影作为候选集,并获取物品(电影)embedding,计算用户embedding和物品embedding之间相似度。
  • 根据相似度排序,返回规定大小的候选集。

其中第二步是最耗时的,有办法可以解决吗?
使用局部敏感哈希搜索embedding最近邻:embedding向量

五、离线模型部署到线上

方法主要有:

  • 预存推荐结果和embedding结果
  • 预训练embedding+轻量级线上模型:
  • PMML模型
  • Tensorflow Serving

1.预存推荐结果和embedding结果

预存推荐结果:在离线环境下生成对每个用户的推荐结果,再将结果预存到Redis中,再线上环境取出预存数据直接推荐给用户。
优点:线下平台和线上平台完全解耦,线上服务过程没有复杂计算,推荐线上延迟极低
缺点:存储用户和物品的组合推荐结果,用户数量、物品数量规模过大发生组合爆炸,线上数据库无力支撑。
这种推荐方式适合冷启动和热门榜单。
预存embedding结果
离线训练好embedding,在线上通过相似度运算得到最终推荐结果。本项目通过Item2vec生成物品embedding,再存入Redis中,这就是预存embedding结果的应用。
然而预存embedding结果是在线下计算embedding,这样的方式缺少线上场景特征的引入,表达能力受限。

2.预训练embedding+轻量级线上模型

用深度网络离线训练embedding存入内存数据库,在线上实现逻辑回归或浅层神经网络轻量级模型拟合优化目标。
线上部分从Redis拿到离线生成embedding向量,跟其他特征embedding向量组合在一起,扔到标准的多层神经网络进行预估。不是end-end模型。

3.PMML模型

end-end,不能够支持所有复杂模型

4.Tensorflow Serving

离线使用Tensorflow的Keras接口完成模型构建和训练,再利用 TensorFlow Serving 载入模型,用 Docker 作为服务容器,然后在 Jetty 推荐服务器中发出 HTTP 请求到 TensorFlow Serving,获得模型推断结果,最后推荐服务器利用这一结果完成推荐排序。
基于Docker 的Tensorflow Serving,

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-02-28 16:03:51  更:2022-02-28 16:04:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 4:40:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码