最近算法后台更化成了go语言的,整理了一些关于向量数据库的接口函数,有需要的可以借鉴,目前已经整理的是我在开发客服系统一用到的,为用到的暂时没有写。
官方更多 API:https://api.qdrant.tech/api-reference
使用 http 端口号是 3334,使用包需要 3335
案例代码:https://github.com/qdrant/go-client/blob/master/examples/main.go
1. getClient
func getClient() *qdrant.Client {
// 创建客户端
client, err := qdrant.NewClient(&qdrant.Config{
Host: "192.168.0.91", // Can be omitted, default is "localhost"
Port: 56334, // Can be omitted, default is 6334
APIKey: "axUut0X8Mws7DBND1MWvYO7G",
// APIKey: "<API_KEY>",
// UseTLS: true,
// PoolSize: 3,
// KeepAliveTime: 10,
// KeepAliveTimeout: 2,
// TLSConfig: &tls.Config{...},
// GrpcOptions: []grpc.DialOption{},
})
if err != nil {
panic(err)
}
// defer client.Close()
return client
}
2. createCollection
func createCollection(client *qdrant.Client, ctx context.Context, collectionName string) {
// 创建集合
defaultSegmentNumber := uint64(2)
err := client.CreateCollection(ctx, &qdrant.CreateCollection{
CollectionName: collectionName,
VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
Size: uint64(4),
Distance: qdrant.Distance_Dot,
}),
OptimizersConfig: &qdrant.OptimizersConfigDiff{
DefaultSegmentNumber: &defaultSegmentNumber,
},
})
if err != nil {
panic(fmt.Errorf("could not create collection: %w", err))
}
log.Println("Collection", collectionName, "created")
}
3. listCollection
func listCollection(client *qdrant.Client, ctx context.Context) {
// 列出所有集合
collections, err := client.ListCollections(ctx)
if err != nil {
panic(fmt.Errorf("could not list collections: %w", err))
}
log.Printf("List of collections: %s", collections)
}
4. upsertData
func upsertData(client *qdrant.Client, ctx context.Context, collectionName string) {
waitUpsert := true
upsertPoints := []*qdrant.PointStruct{
{
Id: qdrant.NewIDNum(1),
Vectors: qdrant.NewVectors(0.05, 0.61, 0.76, 0.74),
Payload: qdrant.NewValueMap(map[string]any{
"city": "Berlin",
"country": "Germany",
"count": 1000000,
"square": 12.5,
}),
},
{
Id: qdrant.NewIDNum(2),
Vectors: qdrant.NewVectors(0.19, 0.81, 0.75, 0.11),
Payload: qdrant.NewValueMap(map[string]any{
"city": "Berlin",
"country": "London",
}),
},
{
Id: qdrant.NewIDNum(3),
Vectors: qdrant.NewVectors(0.36, 0.55, 0.47, 0.94),
Payload: qdrant.NewValueMap(map[string]any{
"city": []any{"Berlin", "London"},
}),
},
{
Id: qdrant.NewID("58384991-3295-4e21-b711-fd3b94fa73e3"),
Vectors: qdrant.NewVectors(0.35, 0.08, 0.11, 0.44),
Payload: qdrant.NewValueMap(map[string]any{
"bool": true,
"list": []any{true, 1, "string"},
"count": 1000000,
"square": 12.5,
}),
},
}
_, err := client.Upsert(ctx, &qdrant.UpsertPoints{
CollectionName: collectionName,
Wait: &waitUpsert,
Points: upsertPoints,
})
if err != nil {
panic(fmt.Errorf("could not upsert points: %w", err))
}
log.Println("Upsert", len(upsertPoints), "points")
}
5. queryData
func queryData(client *qdrant.Client, ctx context.Context, collectionName string) {
searchedPoints, err := client.Query(ctx, &qdrant.QueryPoints{
CollectionName: collectionName,
Query: qdrant.NewQuery(0.2, 0.1, 0.9, 0.7),
WithPayload: qdrant.NewWithPayloadInclude("city"),
})
if err != nil {
panic(fmt.Errorf("could not search points: %w", err))
}
// log.Printf("Found points: %s", searchedPoints)
fmt.Printf("结构: %+v\n", searchedPoints)
for i, group := range searchedPoints {
fmt.Println(i, group)
}
}
6. queryFilterData
func queryFilterData(client *qdrant.Client, ctx context.Context, collectionName string) {
valueVector := []float32{0.2, 0.1, 0.9, 0.7}
filteredPoints, err := client.Query(ctx, &qdrant.QueryPoints{
CollectionName: collectionName,
Query: qdrant.NewQuery(valueVector...),
Filter: &qdrant.Filter{
Should: []*qdrant.Condition{
qdrant.NewMatchKeyword("city", "Berlin"),
},
},
})
if err != nil {
panic(fmt.Errorf("could not search points: %w", err))
}
// log.Printf("Found points: %s", filteredPoints)
fmt.Printf("结构: %+v\n", filteredPoints)
for i, group := range filteredPoints {
fmt.Println(i, group)
}
func queryFilterData2(client *qdrant.Client, ctx context.Context, collectionName string) {
valueVector := []float32{0.2, 0.1, 0.9, 0.7}
filteredPoints, err := client.Query(ctx, &qdrant.QueryPoints{
CollectionName: collectionName,
Query: qdrant.NewQueryDense(valueVector),
Filter: &qdrant.Filter{
Should: []*qdrant.Condition{
qdrant.NewMatchKeyword("city", "Berlin"),
},
},
})
if err != nil {
panic(fmt.Errorf("could not search points: %w", err))
}
// log.Printf("Found points: %s", filteredPoints)
fmt.Printf("结构: %+v\n", filteredPoints)
for i, group := range filteredPoints {
fmt.Println(i, group)
}
}
7. queryByID
func queryByID(client *qdrant.Client, ctx context.Context, collectionName string) {
// 获取根据ID查询单点
point, err := client.Get(ctx, &qdrant.GetPoints{
CollectionName: collectionName,
Ids: []*qdrant.PointId{
qdrant.NewIDNum(1),
},
WithPayload: qdrant.NewWithPayload(true),
WithVectors: qdrant.NewWithVectors(false),
})
if err != nil {
panic(fmt.Errorf("could not get point: %w", err))
}
fmt.Printf("结构: %+v\n", point)
}
func queryByIDS(client *qdrant.Client, ctx context.Context, collectionName string) {
// 获取根据ID查询多点
points, err := client.Get(ctx, &qdrant.GetPoints{
CollectionName: collectionName,
Ids: []*qdrant.PointId{
qdrant.NewIDNum(1), qdrant.NewIDNum(2), qdrant.NewIDNum(3),
},
WithPayload: qdrant.NewWithPayload(true),
WithVectors: qdrant.NewWithVectors(false),
})
if err != nil {
panic(fmt.Errorf("could not get points: %w", err))
}
fmt.Printf("结构: %+v\n", points)
}
8. deleteByIdOrFilter
func deleteByIdOrFilter(client *qdrant.Client, ctx context.Context, collectionName string) {
// 删除根据ID删除单点
_, err := client.Delete(context.Background(), &qdrant.DeletePoints{
CollectionName: collectionName,
Points: qdrant.NewPointsSelectorIDs([]*qdrant.PointId{
qdrant.NewIDNum(1),
}),
})
if err != nil {
panic(fmt.Errorf("could not delete points: %w", err))
}
// _, err = client.Delete(ctx, &qdrant.DeletePoints{
// CollectionName: collectionName,
// Points: qdrant.NewPointsSelectorFilter(&qdrant.Filter{
// Must: []*qdrant.Condition{
// qdrant.NewMatch("color", "red"),
// },
// }),
// })
// if err != nil {
// panic(err)
// }
}
9. createMultiSpaceCollection
func createMultiSpaceCollection(client *qdrant.Client, ctx context.Context, coll string) error {
_, err := client.CreateCollection(ctx, &qdrant.CreateCollection{
CollectionName: coll,
VectorsConfig: qdrant.NewVectorsConfigMap(map[string]*qdrant.VectorParams{
"image": {
Size: 512,
Distance: qdrant.Distance_Cosine,
},
"text": {
Size: 768,
Distance: qdrant.Distance_Cosine,
},
}),
})
return err
}
10. insertMultiSpaceData
func insertMultiSpaceData(client *qdrant.Client, ctx context.Context, coll string) error {
// 第一条:两个命名空间都有向量
pt1 := &qdrant.PointStruct{
Id: qdrant.NewIDNum(1),
Vectors: qdrant.NewVectorsMap(map[string]*qdrant.Vector{
"image": qdrant.NewVector(makeVector(512)...), // 512 维
"text": qdrant.NewVector(makeVector(768)...), // 768 维
}),
Payload: qdrant.NewValueMap(map[string]interface{}{
"desc": "both vectors",
}),
}
// 第二条:只有 text 向量
pt2 := &qdrant.PointStruct{
Id: qdrant.NewIDNum(2),
Vectors: qdrant.NewVectorsMap(map[string]*qdrant.Vector{
"text": qdrant.NewVector(makeVector(768)...),
}),
Payload: qdrant.NewValueMap(map[string]interface{}{
"desc": "text only",
}),
}
_, err := client.Upsert(ctx, &qdrant.UpsertPoints{
CollectionName: coll,
Points: []*qdrant.PointStruct{pt1, pt2},
})
return err
}
// 快速生成指定维度的假向量
func makeVector(dim int) []float32 {
v := make([]float32, dim)
for i := 0; i < dim; i++ {
v[i] = float32(i%10) * 0.1 // 0.0, 0.1, 0.2 ...
}
return v
}
11. searchByText
func searchByText(client *qdrant.Client, ctx context.Context, coll string) error {
resp, err := client.Search(ctx, &qdrant.SearchPoints{
CollectionName: coll,
Vector: qdrant.NewSearchVector(makeVector(768)...), // 768 维
VectorName: qdrant.PtrOf("text"), // 指定命名空间
Limit: qdrant.PtrOf(uint64(2)),
WithPayload: qdrant.NewWithPayload(true),
WithVectors: qdrant.NewWithVectors([]string{"text"}), // 只返回 text 向量
})
if err != nil {
return err
}
fmt.Println("=== search by text ===")
for _, r := range resp {
fmt.Printf("id=%v score=%.3f payload=%v text=%v\n",
r.Id, r.Score, r.Payload, r.Vectors["text"])
}
return nil
}
12. searchByImage
func searchByImage(client *qdrant.Client, ctx context.Context, coll string) error {
resp, err := client.Search(ctx, &qdrant.SearchPoints{
CollectionName: coll,
Vector: qdrant.NewSearchVector(makeVector(512)...), // 512 维
VectorName: qdrant.PtrOf("image"), // 指定命名空间
Limit: qdrant.PtrOf(uint64(2)),
WithPayload: qdrant.NewWithPayload(true),
WithVectors: qdrant.NewWithVectors([]string{"image", "text"}), // 返回两个空间
})
if err != nil {
return nil
}
fmt.Println("=== search by image ===")
for _, r := range resp {
fmt.Printf("id=%v score=%.3f payload=%v image=%v text=%v\n",
r.Id, r.Score, r.Payload, r.Vectors["image"], r.Vectors["text"])
}
return nil
}
13. countData
func countData(client *qdrant.Client, ctx context.Context, collectionName string) {
// count, err := client.Count(ctx, &qdrant.CountPoints{
// CollectionName: collectionName,
// Filter: &qdrant.Filter{
// Must: []*qdrant.Condition{
// qdrant.NewMatch("color", "red"),
// },
// },
// })
count, err := client.Count(ctx, &qdrant.CountPoints{
CollectionName: collectionName,
})
if err != nil {
panic(err)
}
fmt.Println("Count:", count)
}
14. main
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/qdrant/go-client/qdrant"
)
func main() {
collectionName := "go_test_db"
fmt.Print(collectionName)
client := getClient()
// Get a context for a minute
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
// Execute health check
healthCheckResult, err := client.HealthCheck(ctx)
if err != nil {
panic(fmt.Errorf("could not get health: %w", err))
}
log.Printf("Qdrant version: %s", healthCheckResult.GetVersion())
// createCollection(client, ctx, collectionName)
// listCollection(client, ctx)
// upsertData(client, ctx, collectionName)
// queryData(client, ctx, collectionName)
// queryFilterData(client, ctx, collectionName)
// queryFilterData2(client, ctx, collectionName)
deleteCollection(client, ctx, collectionName)
}