Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,33 +66,40 @@ import ballerinax/ai.weaviate;

```ballerina
ai:VectorStore vectorStore = check new weaviate:VectorStore(
serviceUrl = "add-weaviate-service-url",
config = {
className: "add-collection-name"
},
auth = {
token: "add-access-token"
}
serviceUrl = "add-weaviate-service-url",
config = {
collectionName: "add-collection-name"
},
auth = {
token: "add-access-token"
}
);
```

### Step 3: Add vectors

```ballerina
ai:Error? result = vectorStore.add(
[
{
id: uuid:createRandomUuid(),
embedding: [1.0, 2.0, 3.0],
chunk: {
'type: "text",
content: "This is a chunk"
}
}
]
[
{
id: uuid:createRandomUuid(),
embedding: [1.0, 2.0, 3.0],
chunk: {
'type: "text",
content: "This is a chunk"
}
}
]
);
```

## Examples

The Ballerina Weaviate vector store module provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-ai.weaviate/tree/main/examples).

1. [Book Recommendation System](https://github.com/ballerina-platform/module-ballerinax-ai.weaviate/tree/main/examples/book-recommendation-system)
This example shows how to use Weaviate vector store APIs to implement a book recommendation system that stores book embeddings and queries them to find similar books based on vector similarity and metadata filtering.

## Issues and projects

Issues and Projects tabs are disabled for this repository as this is part of the Ballerina Library. To report bugs, request new features, start new discussions, view project boards, etc., go to the [Ballerina Library parent repository](https://github.com/ballerina-platform/ballerina-standard-library).
Expand Down
9 changes: 8 additions & 1 deletion ballerina/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import ballerinax/ai.weaviate;
ai:VectorStore vectorStore = check new weaviate:VectorStore(
serviceUrl = "add-weaviate-service-url",
config = {
className: "add-collection-name"
collectionName: "add-collection-name"
},
auth = {
token: "add-access-token"
Expand All @@ -87,3 +87,10 @@ ai:Error? result = vectorStore.add(
]
);
```

## Examples

The Ballerina Weaviate vector store module provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-ai.weaviate/tree/main/examples).

1. [Book Recommendation System](https://github.com/ballerina-platform/module-ballerinax-ai.weaviate/tree/main/examples/book-recommendation-system)
This example shows how to use Weaviate vector store APIs to implement a book recommendation system that stores book embeddings and queries them to find similar books based on vector similarity and metadata filtering.
76 changes: 0 additions & 76 deletions ballerina/tests/mock_weaviate_service.bal

This file was deleted.

2 changes: 0 additions & 2 deletions ballerina/types.bal
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@
#
# + collectionName - The name of the collection to use
# + chunkFieldName - The name of the field to contain the chunk details
# + topK - The number of top similar vectors to return in queries
public type Configuration record {|
string collectionName;
string chunkFieldName?;
int topK = 10;
|};

type QueryResult record {
Expand Down
55 changes: 35 additions & 20 deletions ballerina/vector_store.bal
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ public isolated class VectorStore {
}
self.weaviateClient = weaviateClient;
self.config = config.cloneReadOnly();
self.topK = self.config.topK;
lock {
string? chunkFieldName = self.config.cloneReadOnly().chunkFieldName;
self.chunkFieldName = chunkFieldName is () ? "content" : chunkFieldName;
Expand All @@ -66,41 +65,48 @@ public isolated class VectorStore {
weaviate:Object[] objects = [];
foreach ai:VectorEntry entry in entries.cloneReadOnly() {
ai:Embedding embedding = entry.embedding;
weaviate:PropertySchema properties = entry.chunk.metadata !is () ?
check entry.chunk.metadata.cloneWithType() : {};
properties[self.chunkFieldName] = entry.chunk.content;
properties["type"] = entry.chunk.'type;

if embedding is ai:Vector {
objects.push({
'class: self.config.collectionName,
id: entry.id,
vector: embedding,
properties: {
"type": entry.chunk.'type,
[self.chunkFieldName]: entry.chunk.content
}
properties
});
}
// TODO: Add support for sparse and hybrid embeddings
// Weaviate does not support custom sparse or hybrid embeddings directly
// Need to convert them to dense vectors before adding to Weaviate
}
weaviate:ObjectsGetResponse[]|error result = self.weaviateClient->/batch/objects.post({
weaviate:ObjectsGetResponse[] _ = check self.weaviateClient->/batch/objects.post({
objects
});
if result is error {
return error("Failed to add vector entries", result);
}
} on fail error err {
return error("Failed to query vector store", err);
}
}

# Deletes a vector entry from the Weaviate vector store.
#
# + id - The ID of the vector entry to delete
# + ids - ID/s of the vector entries to delete
# + return - An `ai:Error` if the deletion fails, otherwise returns `()`
public isolated function delete(string id) returns ai:Error? {
public isolated function delete(string|string[] ids) returns ai:Error? {
lock {
string path = self.config.collectionName;
http:Response|error result = self.weaviateClient->/objects/[path]/[id].delete();
if result is error {
return error("Failed to query vector store", result);
if ids is string[] {
foreach string id in ids.cloneReadOnly() {
ai:Error? result = deleteById(id, path, self.weaviateClient);
if result is error {
return result;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This leads to an inconsistent stage.
Some are deleted and some are not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used a transaction block as suggested

Fixed in 4c2b6cd

}
}
return;
}
return deleteById(ids, path, self.weaviateClient);
}
}

Expand All @@ -122,10 +128,12 @@ public isolated class VectorStore {
string gqlQuery = string `{
Get {
${self.config.collectionName}(
limit: ${self.topK}
${query.topK > -1 ? string `limit: ${query.topK}` : string ``}
${filterSection}
nearVector: {
vector: ${query.embedding.toJsonString()}
${query.embedding !is () ?
string `nearVector: {
vector: ${query.embedding.toJsonString()}
}` : string ``
}
) {
content
Expand Down Expand Up @@ -165,13 +173,20 @@ public isolated class VectorStore {
},
similarityScore: element._additional.certainty
});
} on fail error err {
return error("Failed to parse vector store query", err);
}
}
finalMatches = matches.cloneReadOnly();
} on fail error err {
return error("Failed to query vector store", err);
}
return finalMatches;
}
}

isolated function deleteById(string id, string path, weaviate:Client weaviateClient) returns ai:Error? {
lock {
http:Response|error result = weaviateClient->/objects/[path]/[id].delete();
if result is error {
return error("Failed to query vector store", result);
}
}
}
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def moduleVersion = project.version.replace("-SNAPSHOT", "")

task build {
dependsOn(':ai.weaviate-ballerina:build')
dependsOn(':ai.weaviate-examples:build')
}

release {
Expand Down
52 changes: 52 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
## Examples

The Ballerina Weaviate vector store module provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-ai.weaviate/tree/main/examples).

1. [Book Recommendation System](https://github.com/ballerina-platform/module-ballerinax-ai.weaviate/tree/main/examples/book-recommendation-system)
This example shows how to use Weaviate vector store APIs to implement a book recommendation system that stores book embeddings and queries them to find similar books based on vector similarity and metadata filtering.

## Prerequisites

1. Follow the [instructions](https://github.com/ballerina-platform/module-ballerinax-ai.weaviate#set-up-guide) to set up the Weaviate cluster and obtain API credentials.

2. For each example, create a `Config.toml` file with your Weaviate service URL, collection name, and API token. Here's an example of how your `Config.toml` file should look:

```toml
serviceUrl = "<Your Weaviate Service URL>"
collectionName = "<Your Collection Name>"
token = "<Your API Token>"
```

## Running an Example

Execute the following commands to build an example from the source:

* To build an example:

```bash
bal build
```

* To run an example:

```bash
bal run
```

## Building the Examples with the Local Module

**Warning**: Due to the absence of support for reading local repositories for single Ballerina files, the Bala of the module is manually written to the central repository as a workaround. Consequently, the bash script may modify your local Ballerina repositories.

Execute the following commands to build all the examples against the changes you have made to the module locally:

* To build all the examples:

```bash
./build.sh build
```

* To run all the examples:

```bash
./build.sh run
```
1 change: 1 addition & 0 deletions examples/book-recommendation-system/.github/README.md
8 changes: 8 additions & 0 deletions examples/book-recommendation-system/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
org = "wso2"
name = "book_recommendation_system"
version = "0.1.0"
distribution = "2201.12.0"

[build-options]
observabilityIncluded = true
Loading
Loading