软件包hnsw在GO中实现了层次可导航的小世界图形。您可以阅读有关它们在这里工作的方式。从本质上讲,它们允许使用具有高维矢量数据的快速近似近似的邻居搜索。
可以将此软件包视为您喜欢的矢量数据库(例如Pinecone,Weaviate)的内存替代方案。它仅实施基本操作:
| 手术 | 复杂 | 描述 |
|---|---|---|
| 插入 | 将向量插入图表 | |
| 删除 | 从图中删除向量 | |
| 搜索 | 搜索矢量的最近邻居 | |
| 抬头 | 通过ID检索向量 |
笔记
复杂性是大约
go get github.com/coder/hnsw@main
g := hnsw . NewGraph [ int ]()
g . Add (
hnsw . MakeNode ( 1 , [] float32 { 1 , 1 , 1 }),
hnsw . MakeNode ( 2 , [] float32 { 1 , - 1 , 0.999 }),
hnsw . MakeNode ( 3 , [] float32 { 1 , 0 , - 0.5 }),
)
neighbors := g . Search (
[] float32 { 0.5 , 0.5 , 0.5 },
1 ,
)
fmt . Printf ( "best friend: %v n " , neighbors [ 0 ]. Vec )
// Output: best friend: [1 1 1] 尽管所有图形操作都是内存的,但hnsw提供了从持久存储中加载/保存的设施。
对于io.Reader / io.Writer接口,请使用Graph.Export和Graph.Import 。
如果您将单个文件作为后端,则HNSW提供了方便的SavedGraph类型:
path := "some.graph"
g1 , err := LoadSavedGraph [ int ]( path )
if err != nil {
panic ( err )
}
// Insert some vectors
for i := 0 ; i < 128 ; i ++ {
g1 . Add ( hnsw . MakeNode ( i , [] float32 { float32 ( i )}))
}
// Save to disk
err = g1 . Save ()
if err != nil {
panic ( err )
}
// Later...
// g2 is a copy of g1
g2 , err := LoadSavedGraph [ int ]( path )
if err != nil {
panic ( err )
}查看更多:
我们为图形使用快速的二进制编码,因此您可以期望以磁盘速度节省/加载。在我的M3 MacBook上,我得到了这些基准结果:
goos: darwin
goarch: arm64
pkg: github.com/coder/hnsw
BenchmarkGraph_Import-16 4029 259927 ns/op 796.85 MB/s 496022 B/op 3212 allocs/op
BenchmarkGraph_Export-16 7042 168028 ns/op 1232.49 MB/s 239886 B/op 2388 allocs/op
PASS
ok github.com/coder/hnsw 2.624s
保存/加载具有256个维的100个向量的图时。
总的来说,您可以对图表的性能产生最大的效果是降低数据的维度。在1536个维度(OpenAI默认值)处,默认参数下的查询过程的70%用于距离函数。
如果您在缓慢 /潜伏期中挣扎,请考虑:
而且,如果您在过多的内存使用方面苦苦挣扎,请考虑:
Graph.M (每个节点可以拥有的最大邻居数)Graph.Ml (级别生成参数) 图表的内存开销看起来像:
在哪里:
您可以推断出:
在具有256个维的图的示例中,
内存增长主要是线性的。