Skip to content

Commit

Permalink
Add qdrant read vector store implementation
Browse files Browse the repository at this point in the history
PR #33 can't really be merged until we open-source and package up
vectorapi, so this commit adds a qdrant implementation and modifies
the provisioning file to use it (and OpenAI) by default, rather than
vectorapi.
  • Loading branch information
sd2k committed Sep 12, 2023
1 parent 190635f commit a68c495
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 20 deletions.
23 changes: 15 additions & 8 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,21 @@ services:
volumes:
- ./dist:/var/lib/grafana/plugins/grafana-llm-app
- ./provisioning:/etc/grafana/provisioning
vectorapi:
image: vectorapi:latest
environment:
PORT: 8889
ports:
- 8889:8889

qdrant:
image: qdrant/qdrant
volumes:
- sentence-transformers:/app/.sentence_transfomers
- qdrant-storage:/qdrant/storage

# vectorapi:
# image: vectorapi:latest
# environment:
# PORT: 8889
# ports:
# - 8889:8889
# volumes:
# - sentence-transformers:/app/.sentence_transfomers

volumes:
sentence-transformers:
# sentence-transformers:
qdrant-storage:
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ go 1.19
require (
github.com/grafana/grafana-plugin-sdk-go v0.174.0
github.com/launchdarkly/eventsource v1.7.1
github.com/qdrant/go-client v1.5.0
google.golang.org/grpc v1.57.0
)

require (
Expand Down Expand Up @@ -80,7 +82,6 @@ require (
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230731193218-e0aa005b6bdf // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230731193218-e0aa005b6bdf // indirect
google.golang.org/grpc v1.57.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/qdrant/go-client v1.5.0 h1:JxIp4oTFqZqsX7K5LZbfr2fCgfiT/mRsFaxJ1qCpdVM=
github.com/qdrant/go-client v1.5.0/go.mod h1:680gkxNAsVtre0Z8hAQmtPzJtz1xFAyCu2TUxULtnoE=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
Expand Down
6 changes: 5 additions & 1 deletion pkg/plugin/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ func NewApp(appSettings backend.AppInstanceSettings) (instancemgmt.Instance, err

// Dispose here tells plugin SDK that plugin wants to clean up resources when a new instance
// created.
func (a *App) Dispose() {}
func (a *App) Dispose() {
if a.vectorService != nil {
a.vectorService.Cancel()
}
}

// CheckHealth handles health checks sent from Grafana to the plugin.
func (a *App) CheckHealth(_ context.Context, _ *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
Expand Down
11 changes: 10 additions & 1 deletion pkg/plugin/vector/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ import (

type Service interface {
Search(ctx context.Context, collection string, query string, limit uint64) ([]store.SearchResult, error)
Cancel()
}

type vectorService struct {
embedder embed.Embedder
store store.ReadVectorStore
collections map[string]store.Collection
cancel context.CancelFunc
}

func NewService(embedSettings embed.Settings, storeSettings store.Settings) (Service, error) {
Expand All @@ -32,7 +34,7 @@ func NewService(embedSettings embed.Settings, storeSettings store.Settings) (Ser
return nil, nil
}
log.DefaultLogger.Info("Creating vector store")
st, err := store.NewReadVectorStore(storeSettings)
st, cancel, err := store.NewReadVectorStore(storeSettings)
if err != nil {
return nil, fmt.Errorf("new vector store: %w", err)
}
Expand All @@ -48,6 +50,7 @@ func NewService(embedSettings embed.Settings, storeSettings store.Settings) (Ser
embedder: em,
store: st,
collections: collections,
cancel: cancel,
}, nil
}

Expand Down Expand Up @@ -89,3 +92,9 @@ func (v vectorService) Search(ctx context.Context, collection string, query stri

return results, nil
}

func (v vectorService) Cancel() {
if v.cancel != nil {
v.cancel()
}
}
78 changes: 78 additions & 0 deletions pkg/plugin/vector/store/qdrant.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package store

import (
"context"

"github.com/grafana/grafana-plugin-sdk-go/backend/log"
qdrant "github.com/qdrant/go-client/qdrant"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)

type qdrantSettings struct {
Address string
}

type qdrantStore struct {
conn *grpc.ClientConn
collectionsClient qdrant.CollectionsClient
pointsClient qdrant.PointsClient
}

func newQdrantStore(s qdrantSettings) (ReadVectorStore, func(), error) {
conn, err := grpc.DialContext(context.Background(), s.Address, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, nil, err
}
cancel := func() {
defer func() {
if err := conn.Close(); err != nil {
log.DefaultLogger.Warn("failed to close connection", "err", err)
}
}()
}
return &qdrantStore{
conn: conn,
collectionsClient: qdrant.NewCollectionsClient(conn),
pointsClient: qdrant.NewPointsClient(conn),
}, cancel, nil
}

func (q *qdrantStore) Collections(ctx context.Context) ([]string, error) {
collections, err := q.collectionsClient.List(ctx, &qdrant.ListCollectionsRequest{})
if err != nil {
return nil, err
}
names := make([]string, 0, len(collections.Collections))
for _, c := range collections.Collections {
names = append(names, c.Name)
}
return names, nil
}

func (q *qdrantStore) Search(ctx context.Context, collection string, vector []float32, limit uint64) ([]SearchResult, error) {
result, err := q.pointsClient.Search(ctx, &qdrant.SearchPoints{
CollectionName: collection,
Vector: vector,
Limit: limit,
// Include all payloads in the search result
WithVectors: &qdrant.WithVectorsSelector{SelectorOptions: &qdrant.WithVectorsSelector_Enable{Enable: false}},
WithPayload: &qdrant.WithPayloadSelector{SelectorOptions: &qdrant.WithPayloadSelector_Enable{Enable: true}},
})
if err != nil {
return nil, err
}
results := make([]SearchResult, 0, len(result.GetResult()))
for _, v := range result.GetResult() {
payload := make(map[string]any, len(v.Payload))
for k, v := range v.Payload {
payload[k] = v
}
// TODO: handle non-strings, in case they get there
results = append(results, SearchResult{
Score: float64(v.Score),
Payload: payload,
})
}
return results, nil
}
12 changes: 9 additions & 3 deletions pkg/plugin/vector/store/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
type VectorStoreType string

const (
VectorStoreTypeQdrant VectorStoreType = "qdrant"
VectorStoreTypeGrafanaVectorAPI VectorStoreType = "grafana/vectorapi"
)

Expand Down Expand Up @@ -46,16 +47,21 @@ type Settings struct {

GrafanaVectorAPI grafanaVectorAPISettings `json:"grafanaVectorAPI"`

Qdrant qdrantSettings `json:"qdrant"`

Collections []Collection `json:"collections"`
}

func NewReadVectorStore(s Settings) (ReadVectorStore, error) {
func NewReadVectorStore(s Settings) (ReadVectorStore, context.CancelFunc, error) {
switch VectorStoreType(s.Type) {
case VectorStoreTypeGrafanaVectorAPI:
log.DefaultLogger.Debug("Creating Grafana Vector API store")
return newGrafanaVectorAPI(s.GrafanaVectorAPI), nil
return newGrafanaVectorAPI(s.GrafanaVectorAPI), func() {}, nil
case VectorStoreTypeQdrant:
log.DefaultLogger.Debug("Creating Qdrant store")
return newQdrantStore(s.Qdrant)
}
return nil, nil
return nil, nil, nil
}

func NewVectorStore(s Settings) (VectorStore, error) {
Expand Down
12 changes: 6 additions & 6 deletions provisioning/plugins/grafana-llm-app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ apps:
embeddings:
type: openai
openai:
url: http://vectorapi:8889
apiKey: $OPENAI_API_KEY
vectorStore:
type: grafana/vectorapi
grafanaVectorAPI:
url: http://vectorapi:8889
type: qdrant
qdrant:
address: qdrant:6334
collections:
- name: grafana:core:dashboards
model: BAAI/bge-base-en
dimension: 768
model: text-embedding-ada-002
dimension: 1536

secureJsonData:
openAIKey: $OPENAI_API_KEY

0 comments on commit a68c495

Please sign in to comment.