# Vector Databases

## Overview

Wisej.AI can seamlessly integrate with any vector database through the service implementation of the `IEmbeddingStorageService` interface. While you don't need to interact with this interface directly in your code, any Wisej.AI tools or methods that require a vector database will automatically retrieve the current implementation of `IEmbeddingStorageService`.

Specifically, both the `DocumentSearchTool` and the `SmartyHub.IngestDocumentAsync()` method utilize this service.

## Collections

An important concept in vector databases is "collections." Wisej.AI utilizes collections to organize embedded documents into logical groups, akin to how tables are used in databases. Additionally, the name of a document may include a virtual path, similar to a namespace, preceding the document's name.

For instance, to store two documents with the same name but in different "folders," you can use a naming convention like this:

```csharp
await this.smartHub1.IngestDocumentAsync(
    "C:\\Files\\2024\\AAPL-10K.pdf"), "10Ks\\2024\\AAPL-10K.pdf");
await this.smartHub1.IngestDocumentAsync(
    "C:\\Files\\2023\\AAPL-10K.pdf"), "10Ks\\2023\\AAPL-10K.pdf");
```

If the code does not specify a collection name, Wisej.AI defaults to using the name "default" (in lowercase). The example below illustrates how to store documents in different collections.

```csharp
await this.smartHub1.IngestDocumentAsync(
    "C:\\Files\\2024\\AAPL-10K.pdf"), "10Ks\\2024\\AAPL-10K.pdf", "Apple Docs");
await this.smartHub1.IngestDocumentAsync(
    "C:\\Files\\Logs\\ServiceLogs.txt"), "ServiceLogs.txt", "Logs");
```

## Metadata

Vector databases typically manage text chunks along with their corresponding vectors, while any additional information is stored in a general `metadata` field. Wisej.AI automatically extracts specific values when converting documents using the [IDocumentConversionService](https://docs.wisej.com/ai/components/built-in-services/idocumentconversionservice). However, you can add additional custom fields by passing a [Metadata](#metadata) object to the [IngestDocument](https://docs.wisej.com/ai/components/api/smarthub#ingestdocumentasync-filepath-documentname-collectionname-metadata-overwrite) method.

The conversion service automatically adds several fields, depending on the document type: "Title," "Author," "Subject," "Pages," and "Description." For more details, refer to the [IDocumentConversionService](https://docs.wisej.com/ai/components/built-in-services/idocumentconversionservice) page. In addition to these fields, the `IngestDocument` method adds: "FilePath", "CreationDate", "ModifiedDate", "FileSize".

The following code demonstrates how to add custom metadata to an ingested document:

```csharp
var metadata = Metadata();
    metadata["ServiceName"] = "W3WP-1";
await this.smartHub1.IngestDocumentAsync(
    "C:\\Files\\Logs\\ServiceLogs.txt"), "ServiceLogs.txt", "Logs", true, metadata);
```

All metadata fields are made available to the AI as part of the RAG retrieval process when using [DocumentSearchTools](https://docs.wisej.com/ai/components/built-in-smarttools/documentsearchtools). If you use the[ IEmbeddingStorageService](https://docs.wisej.com/ai/components/built-in-services/iembeddingstorageservice) directly, you will find the metadata object as a property of the [EmbeddedDocument](https://docs.wisej.com/ai/components/api/embeddings/wisej.ai.embeddings.embeddeddocument) instance.

## Built-In

Unless you register a specific provider, Wisej.AI defaults to using the built-in `FileSystemEmbeddingStorageService`. This implementation saves vectors in the file system at the location specified by `FileSystemEmbeddingStorageService.StoragePath`. The default path is set to `"~\AI\Embeddings"`.

An easy alternative is the `MemoryEmbeddingStorageService`, which stores vectors in memory.

**However, both implementations are intended for development purposes only and should not be used in production environments.**

### Chroma DB

You can run Chroma either locally or on a virtual machine (VM) in a data center. The simplest way to run it is by using the Docker image. For installation instructions, please refer to [this link](https://www.trychroma.com/).

With Chroma, you don't need to pre-create the index. Wisej.AI will automatically create the index if it doesn't already exist.

Currently, there isn't a well-established UI for Chroma. However, you can try some available options on GitHub for free. One such option we have used is [fengzhichao/chromadb-admin](https://github.com/flanker/chromadb-admin). This tool only allows you to view the collections created by Wisej.AI. For any administrative functions, you'll need to use tools like `CURL` or `Postman`.&#x20;

<figure><img src="https://1941161015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFjp24h5m0lgli5swqzhO%2Fuploads%2F3HHS59YajLj47rMl5QND%2Fimage.png?alt=media&#x26;token=f3ddbe45-0eb0-4309-9125-6896325bcd25" alt=""><figcaption></figcaption></figure>

### Pinecone

When working with Pinecone, you need to create an index to be used with Wisej.AI through the Pinecone dashboard. When setting up a new index, you only need to define the vector size and the metric. Always use "cosine" as the metric. The vector size is determined by the embedding model you plan to use.

Embedding models are not interchangeable. Therefore, once you create an index, it can only be used with the embedding model for which it was initially configured. In Wisej.AI, the default embedding model is `text-embedding-3-small`, which requires a vector with 1,536 dimensions.

<figure><img src="https://1941161015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFjp24h5m0lgli5swqzhO%2Fuploads%2FCvFtx23gj4FsPNdDufpO%2Fimage.png?alt=media&#x26;token=e9d321d2-541a-42c9-89fa-32ee8f4c18da" alt=""><figcaption></figcaption></figure>

To use Pinecone with Wisej.AI, you can register the service as follows:

{% tabs %}
{% tab title="C#" %}

```csharp
internal static class Program
{
  static Program()
  {
    Application.Services
      .AddOrReplaceService<IEmbeddingStorageService>(
        new PineconeEmbeddingStorageService("<endpoint url>"));
  }
}
```

{% endtab %}

{% tab title="VB.NET" %}

```vbnet
Module Program
  Shared Sub New()
    Application.Services.AddOrReplaceService( _
      Of IEmbeddingStorageService)( _
        New PineconeEmbeddingStorageService("<endpoint url>"))
  End Sub
End Module
```

{% endtab %}
{% endtabs %}

The endpoint URL is the service index host address as shown by Pinecone.

<figure><img src="https://1941161015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFjp24h5m0lgli5swqzhO%2Fuploads%2FgyA8f5A5xi1kqKCM3jor%2Fimage.png?alt=media&#x26;token=2dc9b5a8-31cd-4825-81b2-ef204f53f402" alt=""><figcaption></figcaption></figure>

### Azure AI Search

When utilizing Azure AI Search with Wisej.AI, you must first create the index you'll be working with. Since Azure AI Search starts with a blank schema, you need to define all the necessary fields. Refer to the table and JSON file below for a comprehensive list of required fields.

<table><thead><tr><th width="67"></th><th width="179">Name</th><th>Type</th><th>Features</th></tr></thead><tbody><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="1f511">🔑</span></td><td> id</td><td>Edm.String</td><td>Retrievable, Filterable</td></tr><tr><td></td><td>master</td><td>Edm.Boolean</td><td>Retrievable, Filterable</td></tr><tr><td></td><td>documentName</td><td>Edm.String</td><td>Retrievable, Filterable</td></tr><tr><td><span data-gb-custom-inline data-tag="emoji" data-code="26a1">⚡</span></td><td>vector</td><td>Collection(Edm.Single)</td><td>Retrievable, Searchable</td></tr><tr><td></td><td>collectionName</td><td>Edm.String</td><td>Retrievable, Filterable</td></tr><tr><td></td><td>metadata</td><td>Edm.String</td><td>Retrievable, Filterable</td></tr><tr><td></td><td>chunk</td><td>Edm.String</td><td>Retrievable, Filterable</td></tr></tbody></table>

Download the JSON definition below to create the index.

{% file src="<https://1941161015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFjp24h5m0lgli5swqzhO%2Fuploads%2Flskvk4hfI6XuICuAHLt3%2FAzureAISearch.json?alt=media&token=5dd61745-7011-48bb-a64f-acc848a873f8>" %}

The field that requires particular attention is the `vector`, where embeddings are stored and searched. When defining this field, select `Collection(Edm.Single)` and ensure that both the Retrievable and Searchable options are enabled. Additionally, you must specify the Dimensions, which indicate the size of the array based on the embedding model used.

Embedding models are not interchangeable. Therefore, once you create an index, it can only be used with the embedding model for which it was initially configured. In Wisej.AI, the default embedding model is `text-embedding-3-small`, which requires a vector with 1,536 dimensions.

This is what a created index looks like:

<figure><img src="https://1941161015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFjp24h5m0lgli5swqzhO%2Fuploads%2F6tOtrMjjjiWX07MtnmuE%2Fimage.png?alt=media&#x26;token=0ff3b360-dcb4-4f6a-8cb3-81dc3910842a" alt=""><figcaption></figcaption></figure>

To use Azure AI Search with Wisej.AI, you can register the service as follows:

{% tabs %}
{% tab title="C#" %}

```csharp
internal static class Program
{
  static Program()
  {
    Application.Services
      .AddOrReplaceService<IEmbeddingStorageService>(
        new AzureAISearchEmbeddingStorageService("<endpoint url>"));
  }
}
```

{% endtab %}

{% tab title="VB.NET" %}

```vbnet
Module Program
  Shared Sub New()
    Application.Services.AddOrReplaceService( _
      Of IEmbeddingStorageService)( _
        New AzureAISearchEmbeddingStorageService("<endpoint url>"))
  End Sub
End Module
```

{% endtab %}
{% endtabs %}

The endpoint URL is the service endpoint concatenated with `/indexes/<index name>`. For example, our tests use \`<https://aisearchwisej.search.windows.net/indexes/><mark style="background-color:yellow;">wisejtest</mark>\`.

### Qdrant

Qdrant offers flexibility in its deployment options by allowing you to run it locally or utilize Qdrant Cloud. They provide a user-friendly Docker image for local installations and offer a cloud service option. The cloud service includes a free tier hosted on Amazon AWS or Google Cloud, making it accessible and convenient for a variety of use cases.

With Qdrant, you don't need to pre-create the collection. Wisej.AI will automatically create it, if it doesn't already exist.

Qdrant Cloud offers an intuitive control panel that allows users to inspect their collections and execute queries directly within the interface.

<figure><img src="https://1941161015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFjp24h5m0lgli5swqzhO%2Fuploads%2FHQZWwA5pJFvLVZLTHh7q%2Fimage.png?alt=media&#x26;token=91db0479-5a47-4c4e-9cf3-b9a5e21def2e" alt=""><figcaption></figcaption></figure>

## Custom Implementation

To utilize a different vector database with Wisej.AI, you have two options: you can use the database directly, or you can implement the [IEmbeddingStorageService](https://docs.wisej.com/ai/components/api/services/iembeddingstorageservice) interface and register your vector database connection as a Wisej.NET service. When you register your database this way, it will be seamlessly integrated and utilized by the `DocumentSearchTools` and the `SmartHub.IngestDocument()` implementations.

You can use any of the following implementations as a reference or starting point for integrating additional providers and developing your own custom `IEmbeddingStorageService` implementation. These examples demonstrate the recommended structure and key considerations when extending Wisej.AI with custom storage service integrations.

{% file src="<https://1941161015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFjp24h5m0lgli5swqzhO%2Fuploads%2Fm6ODnifs1aynDdZfeJfr%2FAzureAISearchEmbeddingStorageService.cs?alt=media&token=958090b3-cd0c-4961-a382-d7d39e49a221>" %}
Azure AI Search
{% endfile %}

{% file src="<https://1941161015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFjp24h5m0lgli5swqzhO%2Fuploads%2FB0s5E5FpOzWiRXwf0VEM%2FChromaEmbeddingStorageService.cs?alt=media&token=d9af278d-0b51-4dc7-a0fc-9edaade0623f>" %}
Chroma DB
{% endfile %}

{% file src="<https://1941161015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFjp24h5m0lgli5swqzhO%2Fuploads%2FTa16tuyTfV4rrjGoxvFY%2FPineconeEmbeddingStorageService.cs?alt=media&token=90d74b04-61f1-48be-a783-dcb35e935803>" %}
Pinecone
{% endfile %}

## Embedding Generation

The generation of embeddings for chunks of text is handled by the `IEmbeddingGenerationService`. However, you have the option to generate embeddings directly using any other system or by replacing the service.

It's crucial to understand that embeddings generated with one model are not compatible with those generated by another model. Consequently, if you store documents and embeddings using a specific model and later change the `IEmbeddingGenerationService` or the model itself, all previously stored embeddings will become unusable for queries with a different embedding model. This necessitates careful consideration when altering the embedding generation approach to ensure compatibility and continuity.

This is why Wisej.AI registers a single shared `IEmbeddingGenerationService` with a default implementation that uses the `OpenAIEndpoint` and the "text-embedding-3-small" model. We recommend installing a single service implementation at startup and consistently using the same one.

For instance, if you want to change the model used by the `OpenAIEndpoint` or utilize your own embedding server, refer to the following example:

{% tabs %}
{% tab title="C#" %}

```csharp
static class Program
{
    static Program()
    {
        Application.Services
            .AddOrReplaceService<IEmbeddingGenerationService>(
                new DefaultEmbeddingGenerationService(
                    new OpenAIEndpoint{ EmbeddingModel = "text-embedding-3-large" }));
        // Or   
        Application.Services
            .AddOrReplaceService<IEmbeddingGenerationService>(
                new HuggingFaceEmbeddingGenerationService("http://ollama.myserver.com:8090"));
    
        // Or
        Application.Services
            .AddOrReplaceService<IEmbeddingGenerationService>(
                new DefaultEmbeddingGenerationService(
                    new TogetherAIEndpoint()));
    }
}
```

{% endtab %}

{% tab title="VB.NET" %}

```vbnet
Module Program

    Sub New()
        Application.Services.AddOrReplaceService(Of IEmbeddingGenerationService)(
            New DefaultEmbeddingGenerationService(
                New OpenAIEndpoint With {.EmbeddingModel = "text-embedding-3-large"}))

        ' Or
        Application.Services.AddOrReplaceService(Of IEmbeddingGenerationService)(
            New HuggingFaceEmbeddingGenerationService("http://ollama.myserver.com:8090"))

        ' Or
        Application.Services.AddOrReplaceService(Of IEmbeddingGenerationService)(
            New DefaultEmbeddingGenerationService(
                New TogetherAIEndpoint()))   
    End Sub

End Module
```

{% endtab %}
{% endtabs %}

Regarding the `IEmbeddingStorageService`, Wisej.AI provides several built-in implementations for the `IEmbeddingGenerationService`. Additionally, you have the flexibility to create your own custom implementations to suit your specific requirements. The built-in services include:

<table><thead><tr><th width="360" valign="top">Name</th><th>Description</th></tr></thead><tbody><tr><td valign="top"><a href="../components/api/services/iembeddinggenerationservice/wisej.ai.services.defaultembeddinggenerationservice">DefaultEmbeddingGenerationService</a></td><td>This implementation utilizes the embedding endpoint of any <code>SmartEndpoint</code> that supports embedding functionality. By default, it is configured to use the <code>OpenAIEndpoint</code>. Please note, however, that not all AI providers offer embedding endpoints, so compatibility may vary depending on the provider you choose.</td></tr><tr><td valign="top"><a href="../components/api/services/iembeddinggenerationservice/wisej.ai.services.huggingfaceembeddinggenerationservice">HuggingFaceEmbeddingGenerationService</a></td><td>This implementation leverages the <a href="https://github.com/huggingface/text-embeddings-inference">HuggingFace Text Embedding Inference server</a> to generate embeddings. You can easily deploy this server locally by using the provided Docker container, allowing for flexible and scalable embedding generation within your own infrastructure.</td></tr></tbody></table>

Use the code below as a starting point to accelerate the development of your own custom service implementation. This example demonstrates the essential structure and key elements needed to create a new service that integrates seamlessly with the Wisej.AI framework.

{% file src="<https://1941161015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFjp24h5m0lgli5swqzhO%2Fuploads%2FXE6FN7j3MmjYMwlDlXYV%2FDefaultEmbeddingGenerationService.cs?alt=media&token=f79e5163-ffd2-46c8-96d3-eb57ea9b041a>" %}
Uses SmartEndpoints
{% endfile %}

{% file src="<https://1941161015-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFjp24h5m0lgli5swqzhO%2Fuploads%2Fsf9j26RUxwHoiDBkWhTZ%2FHuggingFaceEmbeddingGenerationService.cs?alt=media&token=ea7e6794-7569-4318-a1eb-57373604ff83>" %}
Uses HF Text Embedding Inference
{% endfile %}

Both implementations also demonstrate how to handle parallel requests. This approach allows your service to process multiple embedding requests concurrently.
