专栏名称: 程序员的那些事
最有影响力的程序员自媒体,关注程序员相关话题:IT技术、IT职场、在线课程、学习资源等。
目录
相关文章推荐
OSC开源社区  ·  苹果用Swift重写每天数十亿次请求的Jav ... ·  昨天  
蚂蚁技术AntTech  ·  推动数据价值的安全释放,第二届“隐语杯”数据 ... ·  23 小时前  
老刘说NLP  ·  48个流行开源ML数据集及KG三元组抽取工具 ... ·  3 天前  
极客之家  ·  一款开源强大的酒店客户管理系统 ·  2 天前  
51好读  ›  专栏  ›  程序员的那些事

Redis 之父亲证:人类程序员仍力压 LLM!网友锐评:那是你没见过平庸码农被 AI 吊打的样子

程序员的那些事  · 公众号  · 程序员  · 2025-05-30 15:09

正文

请到「今天看啥」查看全文


但有一个关键问题:为了让 HNSW 能够快速保存到 Redis 的 RDB 中并重新加载,我对图结构进行了序列化,而不是 [元素-向量] 对,否则我需要将数据重新插入 HNSW,这速度会慢上 100 倍!

因此,我将节点之间的连接以整数形式存储,然后再将其解析为指针,这是个巧妙的技巧,效果很好。

但如果将这种存储方式与图结构的随机损坏结合起来,再加上我对 HNSW 的改造要求节点之间必须存在双向连接(我自行实现了一个具备许多实用功能的 HNSW 版本,双向连接是实现其中许多功能的必要条件),就可能出现以下情况:

  1. 我们加载了损坏的数据,其中显示 A 连接到 B,但 B 不再连接到 A(节点 ID 损坏)。
  2. 我们删除节点 B:由于双向连接被破坏,系统不会清除 A 到 B 的连接。
  3. 随后我们扫描图结构,当访问到 B 时会尝试访问 A:这就会导致“使用已释放内存”的错误:-D 😃 😐

因此,在加载数据后,我需要检查每条连接是否都是双向的。但在常规情况下,这需要 O(N²) 的时间复杂度——对于每个节点,我们需要扫描所有层级,在每个层级中扫描该节点的所有邻居,并通过扫描对应层级的连接来检查对方是否也指向该节点。这显然不够高效。


人类与 LLM 的较量

首先,我实现了常规方法,想看看模糊测试器是否无法再发现漏洞。结果确实有效,但加载一个包含 2000 万向量的大型向量集时,时间从 45 秒增加到了 90 秒左右。这太糟糕了。于是我打开 Gemini 2.5 PRO 对话界面,询问 LLM :“我们能怎么做?有没有更快的方法?”

Gemini 能想到的最佳方案是:对邻居连接的指针进行排序,这样就可以使用二分查找。好吧,我当然知道这个方法,但不确定在 16/32 个指针的数组中,这到底会更快还是更慢。于是我追问:“还有其他办法吗?”得到的回答是没有更好的解决方案了。

于是我提出:“你看,当我们在层级 X 中看到 A 连接 B 时,将其存储在哈希表 A:B:X 中(但我们始终对 A 和 B 进行排序,确保 A>B,这样无论方向如何,连接都能统一处理)。当再次看到该连接时,就将其清除。实际上,我们在将连接中的 ID 解析为指针时已经在扫描整个结构了,如果最后哈希表不为空,就说明存在非双向连接,这个方法如何?”

Gemini 称这是个好主意,但提到了 snprintf() 函数生成键的开销和哈希计算时间等问题。不过我指出,根本不需要 snprintf(),我们可以直接将指针 memcpy() 到固定大小的键中。Gemini 认可了这种可行性,随后我又有了新想法……







请到「今天看啥」查看全文