为了提升用户阅读体验,信息流产品是如何避免给用户推荐重复内容的?

记得去年某个时候,某一款内容资讯产品的Feeds流持续1天刷到重复的内容,从产品角度讲,这无形中浪费了很多推荐位资源,若换成广告位则是直接的收入损失。当时特意看了一下,文章的ID(url)是一样的,基本可以确定是推荐系统排重那里出了问题。对于ID不一样、但相似度极高的文章,同样也不能推荐给用户。今天咱们就深入讲一下,作为一款成熟的信息流产品,是如何避免给用户推荐重复或者相似度极高的内容的。

信息流产品的系统构成

我们先简单看一下信息流产品分成哪几个子系统,分别需要在哪些子系统做重复检测,下图是一个信息流产品的主要构成图:

内容引入: 这个环节负责文章的引入,对于一款内容资讯产品来说,文章是多多益善,不仅年轻人需要内容资讯,年长者也同样需要,文章来源多样化可以保证各年龄人群的覆盖,这个环节不用考虑文章是否重复。

内容处理: 这个环节会进行重复文章的检测与处理,对于达到一定相似度的多篇文章(包括图文、视频),按照一定策略只保留其中一篇。

内容分发: 对于内容领域,现在基本采用的都是App工厂模式,通俗来讲就是群战,每款App进行目标人群或者内容的细分,比如漫画App、短视频App,短视频又分PGC视频、UGC视频等。虽然内容触达渠道有多个,但是内容处理系统最好全局唯一,这样能增强对内容的处理能力。内容分发和内容处理逻辑上是两个独立的子系统,实际实现的时候可能会放在一起,因为内容处理的时候也会考虑内容最终在哪个渠道触达用户。

内容推荐: 按照用户的兴趣进行推荐,所谓千人千面,已经推荐给用户(曝光)的文章,内容推荐系统需要记录下来,用户再次刷的时候需要剔除掉。

从上面几点看,需要 内容处理系统 内容推荐系统 通力合作,从而保证用户不会刷到重复(或者相似度很高)的文章。 下面就分别讲一下这两个子系统具体是如何实现的。

内容推荐系统中的去重逻辑
推荐系统主要由数据层、召回层、排序层构成,如下图所示:

  1. 数据层:包括数据的生成和存储,C侧用户的行为数据(曝光、点击、阅读时长、负反馈、评论、Biu、分享、收藏、点赞、文章的分类、Tag等) 通过埋点 上报到后台构成用户的行为数据,结合用户的基础属性(性别、年龄、地域等)构成用户整体的User Profile。

  2. 召回层:以用户的历史兴趣、实时行为为基础,结合多样性、新颖性、相关性、热点事件等维度,产生该用户的推荐候选集,若候选集过大,会进行一次粗排,过滤掉分数较低的候选文章。推荐系统会维护一个推荐池,大概90万篇图文、2700万篇视频,并对文章设置推荐有效期( 图文3天,视频90天),超过期限的文章会从推荐池中剔除 。所有Feeds流里面刷出来的文章都是从推荐池里面获取的, 这是一个关键点,要想保证用户不刷到重复的内容,只要记录用户近3天(视频是90天)曝光过的文章即可,不需要保存用户历史所有的曝光文章。 在这一层,会去查询用户的曝光文章列表,并从候选集中剔除。

  3. 排序层:在粗排基础上进行精排,进一步缩小推荐候选集,并结合各种算法排序(比如点击率预估)返回给用户最多10条内容。

刚才提到,推荐系统会在召回层剔除掉用户历史曝光文章列表,从而避免用户刷到重复内容,现在具体分析一下实施的可行性:

  1. 文章的Key采用了多段的构成,长度是27个字节(在文章 浅析信息流产品内容中心的存储 里面有提到),用到这里仍然太长,需要进行一次Hash得到4个字节的uint32_t。

  2. 假设普通用户每天5刷(每刷10个内容),每天只需要记录50篇文章的ID(平均应该没有这么多的,重度用户超过这个数字),3天合计600字节(视频需要保存90天的曝光记录,合计18KB)。

  3. 以Feeds流拉取QPS 6万/s 、用户量1亿计算,推荐系统的排重服务和用户曝光列表KV系统之间的带宽以及KV存储资源占用量,图文为274Mb/s、56GB ,视频为8Gb/s、1.7TB。

  4. 为了提升用户的阅读体验,特别是考虑到宝贵的推荐位资源,这些存储和带宽的投入是值得的。

从上面分析可以得出,文章开始的案例应该是曝光的文章ID没有及时落入我的已曝光文章列表所致。

内容处理系统中去重逻辑

内容推荐系统只能对相同ID的文章进行排重,无法判断不同ID的文章是否重复,除非有人告诉他文章之间的重复或者相似关系,而这是内容处理系统的职责,内容处理系统会识别海量文章之间的重复或者相似关系,并将相似关系链告诉推荐系统,有了这个信息后,推荐系统可以做相似文章打散。

内容形态包括图文、视频等,两者展现形式差异较大,重复检测的思路和手段差异很大,下面分别进行阐述。在讲解之前先做一下术语约定,两篇文章重复是指内容完全一样或者内容相似度达到一定的阈值:若内容完全一样,一般是内容引入侧出了Bug、同一篇文章反复入了多次,或者是不同来源包含了同一篇文章(例如,一个作者在不同平台发表了同样的文章);若内容只是相似,这里会存在“仁者见仁、智者见智”的局面,一个人认为两篇文章只是轻微相似,另一个人会认为两篇文章的相似已经到了重复的标准。

图文的重复检测手段

图文的重复检测维度包括标题、封面、正文三个方面,针对不同维度有不同的算法:

  1. 编辑距离, 因算法原因,新进文章和海量存量文章比较的耗时非常大,可以通过时间分片以及 存量文章 限制在15天之内 来解决单篇文章比较耗时的问题

  2. 海明距离, 通过抽屉原理可以极大减少比较次数。64位Simhash分成四段(距离小于等于3则认为相似),每段16个bit位,若文章相似,则必有一段是完全相同的,若文章不相似,则没有一段是相同的。假设有20亿文章存量文章(2年存量文章),并且文章Simhash的0/1分布均匀,在相似的场景,比较次数从20亿次减少到3万次,在不相似的场景下,比较次数从20亿减少到4次。在实际情况下,文章Simhash的0/1分布并不均匀,某些段下的文章数目特别大,达到100万(平均应该是3万左右),这会导致落在这个段的文章的相似比较耗时较大。在具体实现的时候,会对存量文章按月进行存放,首先和时间较近的文章进行比较,若仍然很多,则需要做截断处理。其次,会采用空间换时间的方法,将64位Simhash分成5段、两两组合( 仍然 以使用抽屉原理 ),共产生10种情况,通过这种方式减少落入同一组合的文章量,在不相似的情况,分成4段的场景只需要比较4次,分成5段的场景则需要比较10次。

  3. 孪生网络, 通常和海明距离算法配合使用,先通过海明距离进行召回,在海明距离认为相似的情况下,则通过孪生神经网络进行二次确认,若海明距离认为不相似则无需再二次确认。由于神经网络模型较耗费CPU和内存,我们部署了大概1000台4核8GB的云服务器。在训练孪生神经网络的时候,我们可以相对容易的构造大批量正样本(重复)、负样本(不重复),对每篇文章最多取1800个字,通过jieba分词生成最多900个词(不足补0),每个词通过word2vec得到200维向量,将一篇文章转成200*900*1的矩阵,两篇文章(各自是200*900*1的尺寸)作为孪生神经网络的输入,经过 共享权值的两个CNN网络、并拉平后得到两个特征向量,Concat一起形成一个大的向量,经过几个全连接层(Relu,Dropout,最后一个全连接层的unit数为2)后通过Softmax得到一个相似、不相似的二分类,整体流程参见下图:

  4. BERT向量, Google已经帮忙预训练好了,结合内容中心文章样本进行微调。对于两篇文章,分别计算出各自的BERT向量,然后计算两个向量的距离,根据业务需要卡一个阈值来决定两篇文章是否重复(相似)。若让新进文章和历史存量文章都两两比较一遍BERT向量的距离,则会和编辑距离一样,存在算力太大无法覆盖较长时间跨度的文章。我们采用Facebook开源的Faiss,将存量文章的BERT向量导入Faiss库并进行训练,新进文章和Faiss库中的向量进行比较,可以很快得到TopN的距离相近的向量。

视频的重复检测手段

视频的重复检测维度包括标题和内容,标题的重复检测方法和图文类似,这里不再做详细阐述。视频内容包括视频流、音频流、字幕脚本,我们将视频流转换成图片进行重复检测,在视频流认为重复的情况下再通过音频流指纹进行二次确认( 通过FFmpeg可获得视频的音频流,然后提取基于MFCC的音频特征向量来辅助视频重复检测)。

对视频进行抽帧,最理想的情况是按照视频fps进行抽取,这样能完全无损的将视频流转成图片集合,我的一篇微信公众号文章( 简单聊聊视频基本概念以及在信息流内容中心的处理 )有提到,视频从某种程度上可以看做图片的集合。 以如下视频为例 ,其平均帧率fps是23.976,时长是150秒,通过如下命令进行抽帧大约可获得3596张图片。

#视频通过如下链接可下载,https://4ksamples.com/puppies-bath-in-4k/

ffmpeg -i PUPPIES_BATH_IN_4K_Original_H.264_AAC.mp4 -f image2 -vf fps=fps=1/0.04 puppies_%d.png

两个视频按照最长公共子序列算法(不要求连续,时间复杂度是O(m+n),m、n分别是两个视频的抽帧图片数量)获得相似的图片数量,假设其为comFrms, 两个视频 抽帧图片数量 较少的为minFrms , 若comFrms / minFrms 大于某一阈值,则认为视频重复。以上面视频为例,对于新进的一个视频,需要进行近7000次比较(图片经过HashNET深度学习算法转换后的向量或者dHash值)才能得出是否和某一个视频重复。为了平衡准确率和工程成本,我们采用最多抽100帧+额外关键帧的方法,上面那个视频总共会产生130张图片。这里稍微解释一下 关键帧的概念,关键帧是时间线上标记转换开始或者结束的位置,它包含定义转换应在何处开始或者停止的特殊信息,中间帧(关键帧之间的帧)随着时间的推移在这些定义之间进行插值,以创建运动的错觉。对于其他帧而言,可以只存储和关键帧的差异从而实现视频文件的压缩存储。

#通过如下命令可以获得关键帧,对同一长度的视频内容,分辨率越高抽关键帧越多,上面提到的4K视频共抽取到113张关键帧,转成1280*720P的视频后只有32张。

ffmpeg -i PUPPIES_BATH_IN_4K_Original_H.264_AAC.mp4 -vf "select=eq(pict_type\,I)" -vsync vfr thumb%04d.jpg

视频去重周期一般是90天,以每天30万视频计算,则需要和存量2700万视频进行比较,若一一遍历比较,则需要比较70亿次((130 + 130) * 2700万),基本是一个无法承受的数字。这里采用和图文类似的思路,先将存量视频的所有抽帧图片向量(以及所属的视频ID)存起来, 通过召回可以过滤掉大部分视频 ,只和召回回来的视频进行比较,这个量会比较小。根据图片的向量计算方式,有两种召回方式:

  1. 计算图片的dHash,将64位bit向量分成4段,通过抽屉原理,若两张图片相似,则必有一段是相同的,这样可以过滤掉大部分不相干视频,减少比较量。

  2. 通过神经网络HashNet将图片转成1024维向量,先将存量视频的抽帧图片向量存到Faiss里面(需要训练),对于新来的视频,遍历其每一张抽帧图片,从Faiss里面提取向量距离最近的TopN向量信息(包含关联的视频ID),从而可以拿到可能相似的视频列表,然后再一一比较,通过这种方式可以极大减少比较量。

总结

以上是整个信息流路径对文章内容重复的检测处理,推荐环节主要是工程,内容处理环节包括工程和算法两个方面。由于需要和海量存量文章进行比较,工程挑战非常大,同时文章的内容重复判断和每个人的主观感受有关系,重复检测算法需要不断打磨,既包括无监督的算法(Simhash,dHash,编辑距离,海明距离)、也包括有监督的算法(BERT向量、HashNet、孪生网络)。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章