概述

  • 曝光过滤通常是在召回阶段做,具体的方法就是用 Bloom Filter

曝光过滤问题

  • 如果用户看过某个物品,则不再把该物品曝光给用户。原因是同一个物品重复曝光给用户会损害用户体验,但也不是所有推荐系统都有曝光过滤,像 youtube 这样的长视频就没有曝光过滤,看过的也可以再次推荐
  • 对于每个用户,记录已经曝光给他的物品(小红书只召回 1 个月以内的笔记,因此只需要记录每个用户最近 1 个月的曝光历史)
  • 对于每个召回的物品,判断它是否已经给该用户曝光过,排除掉曾经曝光过的物品
  • 一位用户看过 nnn 个物品,本次召回 rrr 个物品,如果爆力对比,需要 O(nr)O(nr)O(nr) 的时间。
  • 在小红书一个月 nnn 的曝光量级大概是几千,每次推荐召回量 rrr 的量级也是几千,暴力对比的计算量太大了,所以实践中不暴力对比,而是用 Bloom Fliter

Bloom Filter

  • Bloom Filter是一种数据结构,发表在 1970 年,以它的发明者命名
  • 推荐系统的曝光过滤基本上都是用 Bloom Fliter 做的
  • Bloom Fliter 判断要给物品ID是否已经在已曝光的物品集合中
  • 如果判断为 no,那么该物品一定不在集合中
  • 如果判断为 yes,那么该物品很可能在集合中(可能误伤,错误判断未曝光物品为已曝光,将其过滤掉)
  • 如果用 Bloom Fliter 过滤,肯定能干掉所有已经曝光的物品,但是可能会误伤
  • Bloom Fliter 把物品集合表征为一个 m 维二进制向量
  • 每个用户有一个曝光物品的集合,表征为一个向量,需要 m bit 的存储
  • Bloom fliter 有 k 个哈希函数,每个哈希函数把物品ID映射成介于 0 和 m-1 之间的整数

Bloom Filter (k=1)

  • 初始的时候向量是全 0 的
    在这里插入图片描述
  • 我们知道用户有哪些已经曝光过的物品,如下图哈希函数把第一个物品 ID1ID_1ID1 映射为 1,所以我们将二进制的第一位映射为 1
    在这里插入图片描述
  • 第二个物品 ID2ID_2ID2 映射为了 8,所以把位置 8 的二进制位改为 1
    在这里插入图片描述
  • 哈希函数把第三个物品 ID3ID_3ID3 映射为了位置 1,这个位置的元素已经是 1 了,不需要修改这个数值
    在这里插入图片描述
  • 哈希函数把第四个物品 ID4ID_4ID4 映射到了位置 5,我们也将其置为 1
    在这里插入图片描述
  • 哈希函数把第五第六个物品都映射到了位置 5,这个位置已经是 1 了,不需要修改这个数值,到此为止我们已经把 6 个物品表征为一个向量
    在这里插入图片描述
  • 用户发起推荐请求后曝光很多物品,这里用一个之前未曝光给用户的物品,他被映射到位置 2,这个位置是 0,所以 Bloom Filter 判断这个物品之间没有被曝光
  • 这个判断是正确的。如果 Bloom Filter 认为它没有被曝光,那么它肯定没被曝光,Bloom Filter 不会把已曝光的物品错判未未曝光
    在这里插入图片描述
  • 而下面又一个新来的物品已经曝光了,那么它就会被映射到之前它标记过的位置
    在这里插入图片描述
  • 对于又一个新的未曝光的物品,哈希函数把它映射到了位置 8,这个位置已经被标记为了 1,所以被认为已经曝光过了,此时错判
    在这里插入图片描述

Bloom Filter (k=3)

  • 初始全0,来了一个 ID1ID_1ID1 物品,此时有 3 个哈希函数,我们把它映射到了 3 个位置上,我们把 3 个位置都置为 1
    在这里插入图片描述
  • ID2ID_2ID2 也是一个已曝光的物品,我们还用 3 个哈希函数把它映射到 3 个位置上,把 3 个位置的都置为 1
    在这里插入图片描述
  • 现在有一个召回的物品 ID8ID_8ID8,用 3 个哈希函数把它映射到了 3 个不同的位置。假如这个物品已经曝光,那么 3 个位置肯定都是 1 了,但其中 1 个位置是 0,说明这个物品还未曝光
    在这里插入图片描述
  • 对于 ID4ID_4ID4 ,它已经被曝光,判断是正确的
    在这里插入图片描述
  • 对于未曝光的 ID9ID_9ID9 ,它映射的 3 个位置都为 1,被误判了
    在这里插入图片描述

误伤概率分析

  • 曝光物品集合大小为 nnn,二进制向量维度为 mmm,使用 kkk 个哈希函数
  • nnn 越大,向量中的 1 越多,误伤的概率越大(未曝光的 kkk 个位置恰好都是 1 的概率大)
  • mmm 越大,向量越长,越不容易发生哈希碰撞,需要的存储也越多
  • kkk 太大,太小都不好,kkk 有最优取值
    在这里插入图片描述
  • 设定可容忍的误伤概率为 δ\deltaδ ,那么最优参数为:
    在这里插入图片描述
  • 只需要 m = 10n bit,就可以把误伤概率降低到 1% 以下

曝光过滤的链路

  • 把曝光物品记录下来,反馈给召回阶段,用于过滤召回的物品
    在这里插入图片描述
  • app 的前端有埋点,所有曝光的物品都会被记录下来。这个落表的速度要足够快,否则可能会出问题
  • 用户推荐页面两次刷新间隔也就几分钟,快的话也就一二十秒,在下次刷新前就得把本次曝光的结果写道 Bloom Filter 上,否则下一刷很可能会出重复的物品。
  • 所以要用实时流处理,比如把曝光物品写入 Kafka 消息队列,用 Flink 做实时计算
    在这里插入图片描述
  • Flink 实时读取 Kafka 消息队列,计算曝光物品的哈希值,把结果写道 Bloom Fliter 的二进制向量上
  • 用这样的实时数据链路,在曝光发生的几秒后,这位用户的 Bloom Filter 就会被修改,就可以避免重复曝光
  • 但实时流这部分也是最容易出问题的,如果挂掉了或者延时特别大。那么上一刷才看过的物品又会出现
    在这里插入图片描述
  • 曝光过滤具体用在召回完成之后:召回服务器请求曝光过滤服务,曝光过滤服务把二进制向量发送给召回服务器,在召回服务器上用 Bloom Filter 计算召回的物品的哈希值,再和二进制向量做对比,把已经曝光的物品给过滤掉,发送剩余的物品给排序服务器

在这里插入图片描述

Bloom Filter 的缺点

  • Bloom 把物品的集合表示成一个二进制向量
  • 每往集合中添加一个物品,只需要把向量的 k 个位置的元素置为 1
  • Bloom Filter 只支持添加物品,不支持删除物品,从集合中移除物品,无法消除它对向量的影响。因为是共享的,所以要移除的话不能简单的把它的位置都改为 0,因为有可能别的物品也在这个位置有标记
  • 每天都需要从物品集合中移除年龄大于 1 个月的物品(超龄物品不可能被召回,没必要把它们记录在 Bloom Filter,降低 n 可以降低误伤率)
  • 想要删除一个物品,需要计算整个集合的二进制向量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88079.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88079.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/88079.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于STM32单片机的心率血氧监测系统设计(STM32代码编写+手机APP设计+PCB设计+Proteus仿真)

系列文章目录 文章目录 系列文章目录前言1 资料获取与演示视频1.1 资料介绍1.2 资料获取1.3 演示视频 2 系统框架3 硬件3.1 主控制器3.2 显示屏3.3 WIFI模块3.4心率血氧传感器 4 设计PCB4.1 安装下载立创EDA专业版4.2 画原理图4.4 使用嘉立创下单助手进行下单,打板。…

main(int argc,char **agrv)的含义

今天和大家讨论一个常见的但是不容易深入了解的知识点。那就是 main 函数声明中使用到的 argc 和 argv 的含义。通常我们写主函数的时候一般都是直接使用int main() 或者 void main() 来声明 main 函数。但是你知道吗?在c89/c99的语言标准中,main函数的声…

如何简单实现发版不影响客户使用?nginx负载

nginx负载发版不影响客户使用 1.需要二台服务器 2.二台服务器均是正式环境配置 3.服务器Nginx配置修改 发版顺序:先在服务器2发版,发布成功后,再改服务器Nginx配置,重新加载nginx;然后在服务器再发版,发布成…

qt笔记(1)——Qtablewidget使用

1.基础使用方法 (略) 2.坑和注意点 2.1 设置一个单元格的编辑属性 在代码中,想要修改一个单元格的编辑属性,需要对这个item的flags进行设置;注意对一个tablewidget的一个item成员进行设置后,进行一次编…

字符串的模糊匹配方法介绍

字符串的模糊匹配方法介绍 目录字符串的模糊匹配方法介绍一、编辑距离(Levenshtein Distance)复杂度分析二、Jaro-Winkler 距离复杂度分析三、最长公共子序列(LCS)复杂度分析四、模糊搜索(Fuzzy Search)复杂…

ActiveMQ在Spring Boot中的详细使用指南

📋 目录 🚀 ActiveMQ简介 什么是ActiveMQ? 核心概念 🏗️ 基础架构组件 📝 重要概念解释 ActiveMQ vs 其他消息中间件 🔧 环境搭建 1. ActiveMQ服务端安装 Docker方式(推荐初学者) 手动安装方式 2. 验证安装 访问Web管理界面 连接参数 测试连接 �…

二元一次方程

前言 最近刚学二元一次方程,想写一篇专栏熟悉一下本文写给初一的同学看,学过的就划了吧二元一次方程 两个未知数最高项次数为 111 次为整式方程二元一次方程的解不唯一,但是二元一次方程可以用一个未知数来表达另一个未知数eg:eg:eg: xy1x y…

AI编程的未来是智能体原生开发?

目录 前言 一、从“串行”到“并行”:什么是智能体原生开发? 1.1 传统模式(串行思维) 1.2 智能体原生模式(并行思维) 二、程序员的新角色:从代码手艺人到系统思想家 三、软件开发的终局&a…

【牛客刷题】小红的与运算

文章目录 一、题目介绍1.1 题目描述1.2 输入描述1.3 输出描述1.4 示例二、 解题思路2.1 核心算法设计2.2 性能优化关键2.3 算法流程图三、解法实现3.1 解法一:基础实现3.1.1 初级版本分析3.2 解法二:优化版本(推荐)3.2.1 优化版本分析四、总结与拓展4.1 关键优化技术4.2 算…

spring中 方法上@Transation实现原理

Spring中Transactional注解方法实现原理Spring的Transactional注解在方法级别实现事务管理的原理主要基于动态代理和拦截器机制,以下是其核心实现流程:1. 代理创建阶段当Spring容器启动时,会为带有Transactional注解的类创建代理对象&#xf…

qt-C++语法笔记之Stretch与Spacer的关系分析

qt-C语法笔记之Stretch与Spacer的关系分析 code review! 文章目录qt-C语法笔记之Stretch与Spacer的关系分析1. Stretch(拉伸因子)2. Horizontal Spacer 和 Vertical Spacer3. Stretch 和 Spacer 的关系4. 实际应用中的选择5. 注意事项6. 代码与 Qt Desig…

Qwen3技术综述

1. 引入 2025年5月,qwen推出了旗舰模型(flagship model)Qwen3-235B-A22B。并以Apache 2.0版权发布(可自由商业使用,修改代码和商用要包含原始版权)。本文对其技术报告中提到的数据处理技术与模型结构进行综…

[特殊字符] Excel 读取收件人 + Outlook 批量发送带附件邮件 —— Python 自动化实战

许多公司定期需要将不同部门或客户的报告发送给指定人员。手动操作容易出错、耗时且繁琐。今天这篇文章教你如何利用 Python 实现: 🧩 从 Excel 中读取“收件人 抄送人 附件文件路径”; 📤 使用 win32com.client 调用 Outlook …

多模态大语言模型arxiv论文略读(152)

VidComposition: Can MLLMs Analyze Compositions in Compiled Videos? ➡️ 论文标题:VidComposition: Can MLLMs Analyze Compositions in Compiled Videos? ➡️ 论文作者:Yunlong Tang, Junjia Guo, Hang Hua, Susan Liang, Mingqian Feng, Xinya…

基于AR和SLAM技术的商场智能导视系统技术原理详解

本文面对室内定位算法工程师、智慧商场系统开发者、对VR/AR应用开发感兴趣的技术人员,解决如何通过SLAMAR技术破解大型商场室内导航的空间认知壁垒,实现沉浸式导览,本文提供完整技术方案与代码实现。 如需获取商场智能导视系统解决方案请前往…

Debezium日常分享系列之:认识Debezium Operator

Debezium日常分享系列之:认识Debezium Operator什么是Debezium OperatorDebezium Operator 的工作原理Debezium Operator 的优点Debezium Operator 使用场景Debezium Operator 的关键组件部署Debezium OperatorDebezium Operator 的使用什么是Debezium Operator De…

POSIX信号量,环形队列

是一种进程间或线程间同步机制,用于控制多个线程/进程对共享资源的访问,避免并发冲突。可以看作是一个计数器,通过对计数器的操作(PV操作)实现同步P操作(原子性):--,将信…

Python Day6

浙大疏锦行 Python Day6 内容: 描述性统计(可视化分析)单特征可视化(连续、离散)特征与标签可视化特征与特征可视化 代码: # TODO: 描述性统计 import pandas as pd import numpy as np import seaborn…

ESP32与树莓派C++、Rust开发实战

C++语言在ESP32、树莓派实例 以下是关于C++语言在ESP32、树莓派等硬件设备上的开发实例汇总,涵盖常见应用场景和代码示例。 ESP32开发实例 LED控制(GPIO操作) 使用ESP32的GPIO控制LED灯,示例代码基于Arduino框架: #include <Arduino.h> const int ledPin = 2; …

Jedis 原生之道:Redis 命令 Java 实现指南(一)

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;Redis &#x1f4da;本系列文章为个人学习笔…