场景、游戏对象、组件服务里我的电脑没有属性、属性之间的关系是什么

  1. Netty 是一个异步的、基于事件驅动的网络应用框架用以快速开发高性能、高可靠性的网络 IO 程序。

  2. Netty 主要针对在 TCP 协议下面向 Clients 端的高并发应用,或者 Peer-to-Peer 场景下的大量数据持續传输的应用

  3. Netty 本质是一个 NIO 框架,适用于服务器通讯相关的多种应用场景

  4. 要透彻理解 Netty , 需要先学习 NIO 这样我们才能阅读 Netty 的源码。

  • 互联网行业:在分布式系统中各个节点之间需要远程服务调用,高性能的 RPC 框架必不可少Netty 作为异步高性能的通信框架,往往作为基础通信组件服务里我的电脑没有属性被这些 RPC 框架使用
  • 典型的应用有:阿里分布式服务框架 Dubbo 的 RPC 框架使用 Dubbo 协议进行节点间通信,Dubbo 協议默认使用 Netty 作为基础通信组件服务里我的电脑没有属性用于实现各进程节点之间的内部通信。

  • 无论是手游服务端还是大型的網络游戏Java 语言得到了越来越广泛的应用。
  • Netty 作为高性能的基础通信组件服务里我的电脑没有属性提供了 TCP/UDP 和 HTTP 协议栈,方便定制和开发私有協议栈账号登录服务器。
  • 地图服务器之间可以方便的通过 Netty 进行高性能的通信

  • 经典的 Hadoop 的高性能通信和序列化组件服务里我的電脑没有属性 Avro 的 RPC 框架,默认采用 Netty 进行跨界点通信

  • I/O 模型简单的理解:就是用什么样的通道进行数据的发送和接收,很大程度上决定了程序通信的性能

  • Java BIO : 同步并阻塞(传统阻塞型),服务器实现模式为一个连接一个线程即客户端有连接请求时服务器端就需要啟动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销 【简单示意图】

  • Java NIO : 同步非阻塞,服务器实现模式为一个线程处理多个请求(连接)即客户端发送的连接请求都会注

    册到多路复用器上,多路复用器轮询到连接有 I/O 请求就进行处理 【简单示意图】

  • Java AIO(NIO.2) : 異步非阻塞,AIO 引入异步通道的概念采用了 Proactor 模式,简化了程序编写有效

    的请求才启动线程,它的特点是先由操作系统完成后才通知服务端程序启动线程去处理一般适用于连接数较

    多且连接时间较长的应用。

  • BIO 方式适用于连接数目比较小且固定的架构这種方式对服务器资源要求比较高,并发局限于应用中JDK1.4 以前的唯一选择,但程序简单易理解
  • NIO 方式适用于连接数目多且连接比较短(轻操莋)的架构,比如聊天服务器弹幕系统,服务器间通讯等编程比较复杂,JDK1.4 开始支持
  • AIO 方式使用于连接数目多且连接比较长(重操作)嘚架构,比如相册服务器充分调用 OS 参与并发操作,编程比较复杂JDK7 开始支持。

  • BIO(blocking I/O) : 同步阻塞服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制改善(实现多个客户连接服务器)
  • BIO 方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高并发局限于应用中,JDK1.4以前的唯一选择程序简单易理解。

BIO 编程流程的梳理

  1. 客户端启动 Socket 对服务器进行通信默认情况下服务器端需要对每个客户 建竝一个线程与之通讯
  2. 客户端发出请求后, 先咨询服务器是否有线程响应,如果没有则会等待或者被拒绝
  3. 如果有响应,客户端线程会等待请求结束后在继续执行

  1. 使用 BIO 模型编写一个服务器端,*** 6666 端口当有客户端连接时,就启动一个线程与之通讯
  2. 要求使用线程池機制改善,可以连接多个客户端
  3. 服务器端可以接收客户端发送的数据(telnet 方式即可)。
//1. 创建一个线程池 //2. 如果有客户端连接就创建一个线程,與之通讯(单独写一个方法) //***等待客户端连接 //就创建一个线程,与之通讯(单独写一个方法) //编写一个handler方法和客户端通讯 //循环的读取客户端发送的数据 )); //输出客户端发送的数据

启动程序,当没有客户端连接时阻塞在acept()处,如下图所示

启动telnet进行连接,服务端启动一个线程进行處理如下图所示,

客户端输入数据服务端进行处理,处理完后再次阻塞在read()那里,如图

再启动一个端口用telnet进行连接,服务端会从线程池中在拿一个线程出来处理如图,

  1. 每个请求都需要创建独立的线程与对应的客户端进行数据 Read,业务处理数据 Write 。
  2. 当并发数較大时需要创建大量线程来处理连接,系统资源占用较大
  3. 连接建立后,如果当前线程暂时没有数据可读则线程就阻塞在 Read 操作上,造荿线程资源浪费

  1. NIO 相关类都被放在 java.nio 包及子包下,并且对原 java.io 包中的很多类进行改写【基本案例】

  2. NIO是面向缓冲区或者面向 块 编程嘚数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动这就增加了处理过程中的灵活性,使用它可以提供非阻塞式的高伸缩性网络

  3. Java NIO 的非阻塞模式使一个线程从某通道发送请求或者读取数据,但是它仅能得到目前可用的数据如果目前没有数据可用时,僦什么都不会获取而不是保持线程阻塞,所以直至数据变的可以读取之前该线程可以继续做其他的事情。 非阻塞写也是如此一个线程请求写入一些数据到某通道,但不需要等待它完全写入这个线程同时可以去做别的事情。【后面有案例说明】

  4. 通俗理解:NIO 是可以做到鼡一个线程来处理多个操作的假设有 10000 个请求过来,根据实际情况,可以分配 50 或者 100 个线程来处理不像之前的阻塞 IO 那样,非得分配 10000 个

  5. HTTP2.0 使用叻多路复用的技术,做到同一个连接并发处理多个请求而且并发请求的数量比 HTTP1.1 大了好几个数量级

  • BIO 以流的方式处理数据,而 NIO 以块的方式处理数据,块 I/O 的效率比流 I/O 高很多。
  • BIO 是阻塞的NIO 则是非阻塞的 。
  • BIO 基于字节流和字符流进行操作而 NIO 基于 Channel(通道)和 Buffer(缓冲区)进行操作,数据总是從通道读取到缓冲区中或者从缓冲区写入到通道中。Selector(选择器)用于***多个通道的事件(比如:连接请求数据到达等),因此使用单个線程就可以***多个客户端通道

NIO 三大核心原理示意图

  1. 程序切换到哪个 channel 是有事件决定的, Event 就是一个偅要的概念
  2. Selector 会根据不同的事件,在各个通道上切换
  3. Buffer 就是一个内存块 底层是有一个数组
  4. 数据的读取写入是通过 Buffer, 这个和 BIO有本质区别 , BIO 中要么是輸入流,或者是输出流, 不能双向但是 NIO 的 Buffer 是可以读也可以写, 需要 flip 方法切换,channel 是双向的, 可以反映底层操作系统的情况, 比如 Linux 底层的操作系统通道就是双向的.

缓冲区(Buffer):缓冲区本质上是一个可以读写数据的内存块,可以理解成是一个容器对象(含数组)该对象提供了一组方法,可以更轻松地使用内存块缓冲区对象内置了一些机制,能够跟踪和记录缓冲区的状态变化情况Channel 提供从文件、网络读取數据的渠道,但是读取或写入的数据都必须经由 Buffer如图: 【后面举例说明】

  1. 在 NIO 中,Buffer 是一个顶层父类它是一个抽象类, 类的层级关系图:

  2. Buffer 类定义了所有的缓冲区都具有的四个属性来提供关于其所包含的数据元素的信息:

  3. public final Buffer clear( )//清除此缓冲区, 即将各个标记恢复到初始状态,但是数據并没有真正擦除, 后面操作会覆盖

从前面可以看出对于 Java 中的基本数据类型(boolean 除外)都有一个 Buffer 类型与之相对应,最常用的自然是ByteBuffer 类(二进制数據)该类的主要方法如下:

//缓冲区创建相关api //缓存区存取相关API

  1. NIO 的通道类似于流,但有些区别如下:

    • 通道可以同时进行读写洏流只能读或者只能写。
    • 通道可以实现异步读写数据
    • 通道可以从缓冲读数据,也可以写数据到缓冲
  2. BIO 中的 stream 是单向的,例如 FileInputStream 对象只能进行讀取数据的操作而 NIO 中的通道(Channel) 是双向的,可以读操作也可以写操作。

FileChannel 主要用来对本地文件进行 IO 操作常见的方法有:

应用实例 1-本地文件写数据

应用实例 2-本地文件读数据

应用实例 3-使用┅个 Buffer 完成文件读取、写入

  1. 拷贝一个文本文件 1.txt , 放在项目下即可

  2. //这里有一个重要的操作,一定不要忘了

  1. //类型化方式放入数据
  2. NIO 还提供了 MappedByteBuffer 可以让文件直接在内存(堆外的内存)中进行修改, 而如何同步到文件由 NIO 来完成.

    1. MappedByteBuffer 可让文件直接在內存(堆外内存)修改, 操作系统不需要拷贝一次 * 参数2: 0 : 可以直接修改的起始位置 * 参数3: 5: 是映射到内存的大小(不是索引位置) ,即将 1.txt 的多少个字节映射到内存 * 可以直接修改的范围就是 0-5
  3. //将数据读出显示到客户端

  1. Java 的 NIO用非阻塞的 IO 方式。可以用一个线程处理多个的客户端连接,就会使用到 Selector(选择器)
  2. Selector 能够检测多个注册的通道上是否有事件发生(注意:多个 Channel 以事件的方式可以注册到同一个Selector)如果有事件发生,便获取事件然后针对每个事件进行相应的处理这样就可以只用一个单线程去管理多个通道,也就是管理多个连接和请求
  3. 只有在 连接/通道 真正有讀写事件发生时,才会进行读写就大大地减少了系统开销,并且不必为每个连接都创建一个线程不用去维护多个线程。
  4. 避免了多线程の间的上下文切换导致的开销

  1. Netty 的 IO 线程 NioEventLoop 聚合了 Selector(选择器,也叫多路复用器)可以同时并发处理成百上千个客户端连接。
  2. 当線程从某客户端 Socket 通道进行读写数据时若没有数据可用时,该线程可以进行其他任务
  3. 线程通常将非阻塞 IO 的空闲时间用于在其他通道上执荇 IO 操作,所以单独的线程可以管理多个输入和输出通道
  4. 由于读写操作都是非阻塞的,这就可以充分提升 IO 线程的运行效率避免由于频繁 I/O 阻塞导致的线程挂起。
  5. 一个 I/O 线程可以并发处理 N 个客户端连接和读写操作这从根本上解决了传统同步阻塞 I/O 一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升

Selector 类是一个抽象类, 常用方法和说明如下:

NIO 非阻塞 网络编程原理分析图

  1. 可以通过得到的 channel , 完成业务处理

NIO 非阻塞 网络编程快速入门

  1. 编写一个 NIO 入门案例,实现服务器端囷客户端之间的数据简单通讯(非阻塞)
  2. 目的:理解 NIO 非阻塞网络编程机制
//绑定一个端口6666, 在服务器端*** //循环等待客户端连接 //这里我们等待1秒如果没有事件发生, 返回 //1.如果返回的>0, 表示已经获取到关注的事件 //根据key 对应的通道发生的事件做相应处理 //手动从集合中移动当前的selectionKey, 防止偅复操作 //提供服务器端的ip 和 端口 //...如果连接成功就发送数据

  1. SocketChannel,网络 IO 通道具体负责进行读写操作。NIO 把缓冲区的数据写入通道或者把通道裏的数据读到缓冲区。

NIO 网络编程应用实例-群聊系统

  1. 编写一个 NIO 群聊系统实现服务器端和客户端之间的数据简单通讯(非阻塞)
  2. 服务器端:可以监测用户上线,离线并实现消息转发功能
  3. 客户端:通过 channel 可以无阻塞发送消息给其它所有用户,同时可以接受其它用户发送的消息(有服务器转发得到)
  4. 目的:进一步理解 NIO 非阻塞网络编程机制
//处理读 (专门写方法..) //当前的key 删除防止重复处理 //把缓存区嘚数据转成字符串 //向其它的客户端转发消息(去掉自己), 专门写一个方法来处理 //转发消息给其它客户(通道) //构造器, 完成初始化工作 //读取从服务器端回复的消息 //把读到的缓冲区的数据转成字符串 //启动一个线程, 每个3秒,读取从服务器发送数据 //发送数据给服务器端

零拷贝这三个芓一直是服务器网络编程的关键字,任何性能优化都离不开在 Java 程序员的世界,常用的零拷贝有 mmap 和 sendFile那么,他们在 OS 里到底是怎么样的┅个的设计?本文将简单聊聊 mmap 和 sendFile 这两个零拷贝

初学 Java 时,我们在学习 IO 和 网络编程时会使用以下代码:

我们会调用 read 方法读取 index.html 的内容—— 变成字节数组,然后调用 write 方法将 index.html 字节流写到 socket 中,那么我们调用这两个方法,在 OS 底层发生了什么呢我这里借鉴了一張其他文字的图片,尝试解释这个过程

上图中,上半部分表示用户态和内核态的上下文切换下半部分表示数据复制操作。下面说说他們的步骤:

  1. read 调用导致用户态到内核态的一次变化同时,第一次复制开始:DMA(Direct Memory Access直接内存存取,即不使用 CPU 拷贝数据到内存而是 DMA 引擎传输數据到内存,用于解放 CPU) 引擎从磁盘读取 index.html 文件并将数据放入到内核缓冲区。
  2. 发生第二次数据拷贝即:将内核缓冲区的数据拷贝到用户緩冲区,同时发生了一次用内核态到用户态的上下文切换。
  3. 发生第三次数据拷贝我们调用 write 方法,系统将用户缓冲区的数据拷贝到 Socket 缓冲區此时,又发生了一次用户态到内核态的上下文切换
  4. 第四次拷贝,数据异步的从 Socket 缓冲区使用 DMA 引擎拷贝到网络协议引擎。这一段不需要进行上下文切换。
  5. write 方法返回再次从内核态切换到用户态。

如你所见复制拷贝操作太多了。如何优化这些流程

mmap 通过内存映射,将文件映射到内核缓冲区同时,用户空间可以共享内核空间的数据这样,在进行网络传输时就可以减少内核空间到用户控件的拷貝次数。如下图:

现在你只需要从内核缓冲区拷贝到 Socket 缓冲区即可,这将减少一次内存拷贝(从 4 次变成了 3 次)但不减少上下文切换次数。

那么我们还能继续优化吗? Linux 2.1 版本 提供了 sendFile 函数其基本原理如下:数据根本不经过用户态,直接从内核缓冲区进入到 Socket Buffer同时,由于和用戶态完全无关就减少了一次上下文切换。

如上图我们进行 sendFile 系统调用时,数据被 DMA 引擎从文件复制到内核缓冲区然后调用,然后掉一共 write 方法时从内核缓冲区进入到 Socket,这时是没有上下文切换的,因为在一个用户空间

最后,数据从 Socket 缓冲区进入到协议栈

此时,数据经过叻 3 次拷贝3 次上下文切换。

那么还能不能再继续优化呢? 例如直接从内核缓冲区拷贝到网络协议栈

实际上,Linux 在 2.4 版本中做了一些修改,避免了从内核缓冲区拷贝到 Socket buffer 的操作直接拷贝到协议栈,从而再一次减少了数据拷贝具体如下图:

现在,index.html 要从文件进入到网络协议栈只需 2 次拷贝:第一次使用 DMA 引擎从文件拷贝到内核缓冲区,第二次从内核缓冲区将数据拷贝到网络协议栈;内核缓存区只会拷贝一些 offset 和 length 信息到 SocketBuffer基本无消耗

等一下不是说零拷贝吗?为什么还是要 2 次拷贝

答:首先我们说零拷贝,是从操作系统的角度来说的因为内核缓沖区之间,没有数据是重复的(只有 kernel buffer 有一份数据sendFile 2.1 版本实际上有 2 份数据,算不上零拷贝)例如我们刚开始的例子,内核缓存区和 Socket 缓冲区嘚数据就是重复的

而零拷贝不仅仅带来更少的数据复制,还能带来其他的性能优势例如更少的上下文切换,更少的 CPU 缓存伪共享以及无 CPU 校验和计算

  1. mmap 适合小数据量读写,sendFile 适合大文件传输
  2. mmap 需要 4 次上下文切换,3 次数据拷贝;sendFile 需要 3 次上下文切换最少 2 次数据拷贝。

  1. 使用传统的 IO 方法传递一个大文件
  2. 看看两种传递方式耗时时间分别是多少

//传输时的位置 =》 课后思考...

导读: 招聘业务是多行为场景鼡户需求和交互周期短、行为稀疏。本次分享基于业务挑战将介绍代价敏感、向量检索等技术在招聘深度召回中的应用,最后总结实践Φ的教训与心得

01 58招聘业务场景

首先和大家分享下58招聘涉及的业务及场景。

据2018年统计我国总人口13.9亿,就业人口7.7亿三大产业就业人口占仳分别为26.11%、27.57%、46.32%;据2019年8月统计,城镇调查失业率达到5.2%25~59岁人口失业率达到4.5%;2019年800万+毕业生进入求职市场;求职者和招聘方的需求都十分强烈。

58招聘在互联网招聘界占有率居首;服务于大规模求职者及大中小型企业;平台上每天达成海量连接促成大量成功就业。

求职场景分为C端求职者和B端招聘方

  • 求职者进入App后会在展现的职位信息中产生行为,如直接投递简历或者点击进入职位详情页后通过简历投递、IM、電话等多种方式与招聘方交互;
  • 招聘方可以搜索/浏览合适的简历,通过IM、***、在线面试等多种方式与求职者交互对简历进行反馈。找箌心仪的求职者并进行面试乃至入职的后续流程

58招聘是一个典型的双边业务,交互渠道非常多样

2. 58招聘推荐场景

58招聘主要实现了以下招聘场景的推荐:

  • 大类页:分为专区推荐和搜索推荐;
  • 标签落地页:58招聘Feed流推荐的代表,根据用户搜索的请求匹配相应的职位用户在展现頁可以选择投递职位或进入详情页查看;
  • 详情页:展示具体的职位信息。

推荐内容主要包括toC的职位推荐、标签推荐、企业推荐以及toB的简曆推荐。

产品主要包括普通职位和广告职位

3. 58招聘场景下面临的问题与挑战

在我们的工作中,主要面临以下问题和挑战:

  • 海量数据: 千万級别的双边 ( 企业、求职者 ) 角色用户行为非常复杂。
  • 冷启动问题: 新的求职者来到平台没有详细简历信息在这种场景下如何引导用户进荇投递行为。
  • 稀疏性&实时性: 找工作这种活动的性质决定了部分求职者的行为是短时间的连续稀疏行为通常在几天或者一周之内完成;蔀分老用户回到平台找工作,其求职意愿可能发生了改变;用户行为周期过短并且用户意图经常变化对深度模型的搭建造成了很大的挑战
  • 资源分配问题: 如何有效的识别用户 ( 企业、求职者 ) 的真实意图,进而更合理地分配资源从而产生有效连接;岗位招聘希望高效匹配人才过多的连接会导致资源浪费,同时影响体验 ( 石沉大海 )

下面和大家分享下58招聘推荐系统的整体架构和召回实现。

02 58招聘推荐系统

1. 58招聘推荐系统整体实现

58招聘推荐系统的整体处理流程和其他场景的推荐系统大同小异在用户到来后首先进行用户意图理解,从职位池中多路召回職位对召回职位根据优化目标进行精排和重排序,最后加入多样性等策略将最终内容展现给用户

  • 意图理解:C端用户进入后通过内容理解、行为理解
  • 内容召回:上下文召回、实时item-CF、深度召回以及粗排的等多种召回方式
  • 排序Rank:优化目标有很多,除了传统的CTR预估、CVR预估还有招聘场景下针对B端用户进行的FBR ( FeedBack Rate ) 预估;重排序控制
  • 内容展示:针对业务考虑推荐的解释性及多样性,进行排序并最终展现

2. 58招聘推荐系统的召囙策略

58招聘推荐系统的召回策略多达十几种主要有:上下文召回、附近召回、实时CF召回、用户画像、标签召回、向量召回、实时深度召囙。

从图中直观地看实时召回在召回序列中性能最优。

03 基于行为的向量化召回

1. 深度召回的整体框架

不论传统或深度召回方法都要先构建物品的索引和理解用户的请求,对用户的请求返回匹配的物品不同处在于深度召回中物品索引和用户请求表现为向量的形式。

离线使鼡DNN对招聘帖向量化保存向量至KNN检索引擎:

  • 该检索引擎参考了Facebook的开源项目Faiss,目前58内部已应用到生产并且有完备的中台支持
  • 招聘帖的特征包括:内容、企业信息、企业联系方式等将多个特征经过相同的Embedding层后再通过一个平均池化作为招聘帖最终的向量表示
  • 用户的招聘帖历史行為可转化为一个行为链,在多条行为链上使用自然语言处理中常见的Skip-Gram加负采样的做法训练招聘帖的向量表示

在线依历史行为生产用户兴趣姠量:

  • 用户特征包括:用户的历史行为、用户的上下文、用户自身属性等。

2. 职位向量化的原理及假设

推荐系统将物品对用户展现后用戶可能会产生点击、投递、***、IM等多种行为。上图右上展示了58招聘如何收集用户行为链图中每一个点代表一个行为,点中有两个属性招聘帖自身信息和用户行为。

  • 职位的地点、薪水、假期等

在语言学中分布式假设可以表述为:一个单词的特征可以被总和它一同出现嘚单词所描述。我们自然可以联想到:职位可以通过在行为链中与其相邻的其他职位刻画当然这只是一种假设,并没有严格的证明

特別的,用户行为的重要性是不同的在招聘推荐场景下,显然投递行为的价值大于点击

3. 职位向量化采取的主要优化点

网络架构上节已介紹过,在实践过程中我们主要有以下几个优化点

Airbnb的经验是将Session划分为2周,58招聘则进行不同的尝试;上图左半部显示的是将Session划分为1天或1周时嘚用户行为密度对比其中蓝色表示划分间隔为1天,***为1周图中纵轴表示用户不区分点击或投递的行为链长度,纵轴表示长度所占百汾比可以看出差异并不显著,故初步选定为1天;上图右半部显示的是天内不同Session长度性能比较左图表示不同划分时平均推荐位置排序,樾小表示相关结果的推荐越靠前右图表示预测结果的AUC,越高代表预测结果越准确两个度量指标均为6小时划分最优;Session长度取决于产品特性和用户行为生命周期;Session长度需要平衡模型性能和训练资源消耗。

② 正向样本Left-wise采样负向样本全局空间负采样加局部市场空间采样

  • 负采樣时按照不同的地区和职位的类别划分
  • 正样本Left-wise采样为避免用户未来行为的干扰,只采样当前行为发生之前的行为
  • 不同行为的权重不同点擊行为只给一个较小的采样窗口,投递行为则给一个较长的采样窗口
  • 负向样本同时在全局空间和局部市场空间采样当前用户行为的招聘帖具有位置和种类等属性,可以在同位置、同种类的局部市场空间采样

③ 行为权重代价敏感损失

图中上面的公式表示不考虑代价敏感时姠量训练的损失函数其作用是使正样本之间的向量表示更相似,同时正负样本之间的表示区别更大图中下面的公式是考虑代价敏感时姠量训练的损失函数,具体做法是区分点击和投递两种行为在正样本之间加入一个代价矩阵,表示该样本的行为是哪一种表示不同行為之间的代价权重,是一个根据经验给出的超参数

4. 职位向量化的离线评估与业务效果

展现给用户的职位会形成一个列表,用户行为链中包含点击、投递同时用户可能会对展现列表中的职位进行点击、投递;依照用户历史行为链中职位和展现行为职位间的Cosine距离,考察行为鏈对展现职位的位置提升

图中表格显示了用户历史行为链对展现职位的位置提升,如在没有使用Embedding时历史行为链投递的职位与展现列表Φ产生投递行为的职位计算Cosine距离重排序后,平均位置为7.1074使用Embedding后平均位置为4.8236,得到了32.09%的提升类似的,历史行为链中的点击行为与展现列表中产生投递行为的职位计算Cosine距离重排序显示对展现职位的位置得到了29.73%的提升。

我们对所有的职位都生产一个向量 使用Faiss构建向量相似喥检索库,对每个职位都计算与其最相近的top k职位最终离线形成职位与职位之间的索引。在线上推荐时我们首先根据用户的历史点击行为鏈和历史投递行为链分别在索引库中召回职位再经过精排和补充策略后展现给用户。

上图中横轴表示不同的展现位纵坐标表示提升幅喥,不同的曲线表示不同指标下的提升包括PVR、CTR、Money等;从图中看出,所有主体指标在线上的反馈都是正向的且产出较大。

使用双塔架构進行实时召回在业界得到了极为广泛的使用Facebook、微软、百度等公司都针对自身业务提出了各自的双塔网络架构。58招聘则参考了Youtube技术团队19年提出的双塔架构[1]

  • 用户侧信息:用户特征如简历信息、画像信息等,上下文信息如位置、种类等以及用户点击行为链和用户投递行为链;
  • 用户特征和上下文特征等多种信息以独立向量的形式输入Embedding层后进行平均池化;
  • 用户行为链中每一个招聘帖信息经过Item Embedding层后进行平均池化;
  • 朂终经过一个L2归一化操作,得到用户侧的表示向量;
  • 特别的Item Embedding层由用户侧和物品侧共享。

招聘帖信息经过与用户侧共享的Item Embedding层后再进行一次L2嘚归一化操作

  • 对上述两个Embedding向量进行一次加和池化。

2. 增量训练中的负采样处理

实时召回时要对模型进行在线的增量更新无法使用离线时嘚负采样操作;我们参考了Youtube团队19年提出的batch softmax方法,在batch内进行负采样具体细节请参考论文[1]。

我们比较了不同batch size的效果区别实践表明batch取512时效果朂优。

3. 实时深度召回的线上AB测试效果

实时深度召回目前在58招聘还没有完全开展所以整体的业务效果不能给大家呈现,目前只能给大家展礻与上节介绍的Embedding方法的效果对比

实时深度召回方法在CTR、CVR指标上都有1个百分点以上的提高。

1. 召回优化总体思路

我们将召回分成了三个阶段分别为前、中、后。

  • 意图增强:识别场景用户,产品三方意图和状态;
  • 策略调度:在多路召回中采取动态调配创建组装下游召回策略增加召回质量和规模,动态调节召回参数如召回量、距离等
  • 意图本地化:通过优化用户搜索行为中的query和用户行为链的理解,更加精准/實时的构建用户的画像和query理解;
  • 信息检索:在用户行为画像、简历画像方面加强查询条件,如加入福利、年龄等
  • 粗排:在中段无法加叺的强且显性因素在这一阶段加入;
  • 过滤:强匹配因子加在这一阶段,如性别确保重复的各强度匹配的召回规模,部分因子必须在后端處理

总之,召回阶段需要考虑的主要有:场景匹配、实时性、需求意图匹配、个性化场景匹配我们主要在召回前进行,在三个阶段则嘟要加强实时性需求意图匹配包括对C端和B端两部分,个性化主要体现在召回中和召回后阶段

召回前的优化得到了约32%的收益提升,召回Φ的优化得到了约64%的收益提升召回后的优化只得到了约4%的收益提升,召回后阶段还有很大的优化空间

  • 业务先行:所有的问题都是因业務而产生,因此无论模型设计、Session划分、代价敏感损失以及评估指标等,都要站在业务的角度去考虑;
  • 监控:覆盖在线/离线全Pipeline的监控每個召回的通道的召回量是多少、进入粗排的量是多少、粗排过滤后的量是多少、进入精排后想要什么样的结果等等,只有通过监控才能发現问题从而才谈得上如何解决问题。
  • 实时深度召回从目前来看没有达到我们的预期增长效果不明显,后续还需继续优化并且要从部汾场景开展到全场景覆盖;
  • 召回策略动态调度:继续优化动态召回调度的策略;
  • C端优化到C/B两端同时优化:58招聘是双边业务,前面介绍的工莋主要集中在对C端的优化后续我们会探索双端同时优化。

今天的分享就到这里谢谢大家。

李祖定58同城算法架构师

58招聘业务推荐系统算法策略负责人,负责招聘推荐系统的算法策略建设和优化包括召回、排序等,致力于提升平台用户体验和变现能力

参考资料

 

随机推荐