惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
IT之家
IT之家
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Security Archives - TechRepublic
Security Archives - TechRepublic
P
Proofpoint News Feed
C
CERT Recently Published Vulnerability Notes
阮一峰的网络日志
阮一峰的网络日志
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
P
Palo Alto Networks Blog
Know Your Adversary
Know Your Adversary
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Cisco Talos Blog
Cisco Talos Blog
L
Lohrmann on Cybersecurity
AWS News Blog
AWS News Blog
J
Java Code Geeks
博客园_首页
Scott Helme
Scott Helme
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
T
The Exploit Database - CXSecurity.com
Security Latest
Security Latest
V
Visual Studio Blog
Cloudbric
Cloudbric
Jina AI
Jina AI
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
A
Arctic Wolf
C
Cybersecurity and Infrastructure Security Agency CISA
S
SegmentFault 最新的问题
The Last Watchdog
The Last Watchdog
SecWiki News
SecWiki News
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
W
WeLiveSecurity
K
Kaspersky official blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Hacker News: Ask HN
Hacker News: Ask HN
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
宝玉的分享
宝玉的分享
Hugging Face - Blog
Hugging Face - Blog
量子位
Google Online Security Blog
Google Online Security Blog
博客园 - Franky
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 三生石上(FineUI控件)
Recent Commits to openclaw:main
Recent Commits to openclaw:main

See you soon

试试将文章版本化管理吧 | See you soon 使用 Quadlet 将 Podman 中的 Postgres 当作 systemd 服务运行 | See you soon 大他者,那个无时无刻都在盯着你的东西 | See you soon Laws of Software Engineering,软件工程定律 | See you soon 浅记多因素身份认证 | See you soon Linux 内核中的度量单位 | See you soon 重置 GPG 智能密钥 | See you soon 向 NAS 引入 samba | See you soon 无法重复键入的 Fcitx5 | See you soon ZFS 降级事故 | See you soon 记被 XanMod Kernel 和 AppArmor 联合坑的一次踩坑 | See you soon agent 的 skill 与 toolcall | See you soon 记一次服务器被挂恶意挖矿二进制 | See you soon 活着的 Arc | See you soon 令 acme.sh 使用 Cloudflare 的 DNS API 签发与续签证书 | See you soon 于 Tokio 中卸载 CPU Bound 任务 | See you soon 如我所见,梦破碎的时候 | See you soon 74LS 家族手册 | See you soon JDK Projects 备忘录 | See you soon 关于历史 | See you soon 用 curl 下载 OnePlus 的 ROM | See you soon 实用命令切片 | See you soon 再见,Oh My Zsh。 | See you soon 你不应该复用 strings.Builder | See you soon 博客的明日 | See you soon 被 AppArmor 击杀的 Dockge | See you soon AI 时代的自我 | See you soon 支持删除的布隆过滤器 | See you soon 基于栈的虚拟机与基于寄存器的虚拟机 | See you soon RVA23 包含了什么 | See you soon Rust 的边界检查是否已经有很大的进步 | See you soon 使用 Rust 编写操作系统:Barebones | See you soon 使用 Rust 编写操作系统:引言 | See you soon 编译器笔记:rope | See you soon 编译器笔记:CST | See you soon Paradoxical 札记 | See you soon 更加现代的 PaperMC Minecraft 插件设计指南 | See you soon 简单的 CFG 语法分析方法 | See you soon 简单地使用 Caddy 实现 CORS 配置 | See you soon 让 OpenCV 可以被静态链接 | See you soon 图片搜索笔笺 | See you soon 电路板设计笔记-保护 | See you soon 使用 Rust 实现 SnowflakeId | See you soon 农夫乐事 FaQ 启示 | See you soon 使用 Rust 实现拓展系统札记 | See you soon 遗传学定律的代码实现 | See you soon EN:The Journey of Rust and Procps | See you soon ZH:Rust 与 Procps 之旅 | See you soon 使用 debootstrap 与 schroot 构建一个纯净环境 | See you soon GPG添加新的用户信息 | See you soon GSoC2024 笔记:使用 Rust 重新实现 procps | See you soon JWT 小册 | See you soon 使用密钥登录 SSH | See you soon Guava:Cache | See you soon 编译器笔记:增量编译 | See you soon Gradle秘境:添加一个类似modCompileOnly的依赖块 | See you soon Minecraft:原始经济系统设计简述 | See you soon TinyRemapper笔记 | See you soon MicroOS:进阶 | See you soon MicroOS:起步 | See you soon Swapfile 指北 | See you soon GPG 物理密钥的安装与密钥的迁移 | See you soon 用GPG签名告诉大家这就是我的提交 | See you soon DFS:深度优先搜索 | See you soon 文章翻译:从init.vim到init.lua | See you soon 目录遍历攻击 | See you soon 如何挂载.img文件,以及如何使用QEMU模拟arm64环境 | See you soon 在树莓派上编译 OpenCV | See you soon 关于卸载BlueStacks后遇到的问题 | See you soon
简单的相似去重算法(基于向量) | See you soon
Krysztal Huang · 2025-05-12 · via See you soon

简单的相似去重算法(基于向量)

在工作的时候遇到一个对图片进行去重的需求,简单记录一下

算法

当前提供两种算法,两种算法都依赖于向量数据库。并且由于架构设计,现在两种算法在执行时几乎只需要向量数据库

层级递进

这种算法可以在每次产生新数据时对新数据进行处理,如果新数据里已经出现过之前就已经被查找到的相似图片那么该数据就会被剔除

func (d *Deduplicator) _algorithmV0(trainedUuid string, fuzz float32) {

if d.searchedUuids.Contains(trainedUuid) {

return

}

if res, err := d.vdb.SearchByNearOjWithDistance(trainedUuid, fuzz); err != nil {

logrus.Errorf("while try to fetching result of `%s`: %s", trainedUuid, err)

} else if len(res) > 1 {

currentResult := x.NewList[ProcessedID]()

for _, file := range res {

partial, exist := d.fileIdMapping[file.FileId]

if exist && !d.searchedUuids.Contains(partial.UUID) {

currentResult.Append(ProcessedID{ID: file.FileId, Distance: file.Additional.Distance, Time: partial.TakeTime})

}

d.searchedUuids.Add(partial.UUID)

}

if currentResult.Len() > 1 {

tmp := d.postproc(currentResult)

d.result.Append(tmp)

}

}

}

后处理

在完成结果获取后我们还需要一次过滤操作,我们令该操作为 filter

filter 函数接受一个 float64 类型的参数,根据这个参数过滤掉不需要的值只保留需要的值

全量关联合并

这种算法实现起来就非常简单,相当于把上一种算法的去重步骤给放到提取结果的时候。

但这个算法会对每组都进行查找,假设有三十万个向量数据则会查找三十万次

func (d *Deduplicator) _algorithmV1(trainedUuid string, fuzz float32) {

if res, err := d.vdb.SearchByNearOjWithDistance(trainedUuid, fuzz); err != nil {

logrus.Errorf("while try to fetching result of `%s`: %s", trainedUuid, err)

} else {

currentResult := x.NewList[ProcessedID]()

for _, file := range res {

partial, exist := d.fileIdMapping[file.FileId]

if exist {

currentResult.Append(ProcessedID{ID: file.FileId, Distance: file.Additional.Distance, Time: partial.TakeTime})

}

d.searchedUuids.Add(partial.UUID)

}

if currentResult.Len() > 1 {

d.result.Append(d.postproc(currentResult))

}

}

}

合并

我们令以上算法得到的结果为 res ,并且新引入一个函数 merging

令我们最终得到的结果为 y,相比于层级递进算法我们可以更加动态的计算结果

func merging(input [][]ProcessedID) [][]ProcessedID {

walked := mapset.NewSet[uint]()

result := make([][]ProcessedID, 0)

for _, group := range input {

tmp := slices.DeleteFunc(group, func(id ProcessedID) bool { return walked.Contains(id.ID) })

result = append(result, tmp)

for _, t := range tmp {

walked.Add(t.ID)

}

}

return result

}

这样做,和层级递进最大的区别就在于全量运算,并且在获取结果的时候进行关联合并

后处理

全量关联合并的后处理和层级递进的后处理步骤一致

算法缺陷

层级递进算法的问题

旧算法的复杂度为 到 , 计算量比较小速度快但是缺点也非常明显

  • 计算结果只能在向量空间里一次性使用,假如在二维向量空间里则圆缩小后无法从缩小前和缩小后之间的区域重新规划出集合,也就是存在并查集问题
  • 因为上述原因,去重的结果只在单次有效

全量关联合并算法的问题

该算法的主要问题在于计算缓慢,对于正常用户环境的三十万条向量数据在懒猫微服上计算需要十分钟

但我们可以选择将其作为后台运行的任务并且将其计算结果作为缓存来处理,这样就能扬长避短了