Files
spring-ai/vector-stores/spring-ai-weaviate/README.md
Christian Tzolov faee5fef6f Add support for Weaviate Vector Store
- Add Weaviate Vector Store implementation.
 - Implement a converter of portable Filter.Expressions into native, Weaviate GraphQL Were expressions.
 - Support for Weaviater schema auto-registration of filtarable metadata fields.
 - Add auto-configration, spring properties and tests.
 - WeaviateVectorStore ITs.
 - Add README.md

 Resolves #100
2023-11-21 18:16:34 -05:00

7.3 KiB

Weaviate VectorStore

This readme will walk you through setting up the Weaviate VectorStore to store document embeddings and perform similarity searches.

What is Weaviate?

Weaviate is an open-source vector database. It allows you to store data objects and vector embeddings from your favorite ML-models, and scale seamlessly into billions of data objects. It gives you the tools to store document embeddings, content and metadata and to search through those embeddings including metadata filtering.

Prerequisites

  1. EmbeddingClient instance to compute the document embeddings. Several options are available:

    • Transformers Embedding - computes the embedding in your, local environment. Follow the Transformers Embedding instructions.
    • OpenAI Embedding - uses the OpenAI embedding endpoint. You need to create an account at OpenAI Signup and generate the api-key token at API Keys.
    • You can also use the Azure OpenAI Embedding or the PostgresML Embedding Client.
  2. Weaviate cluster. You can a cluster, locally, in a Docker container (Local Weaviate) or create a Weaviate Cloud Service. For later you need to create an weaviate account spin a cluster and get your access api-key from the dashboard details.

On startup the WeaviateVectorStore creates the required SpringAiWeaviate object schema (if such is not already provisioned).

Dependencies

Add these dependencies to your project:

  1. Embedding Client boot starter, required for calculating embeddings.

    • Transformers Embedding (Local)

      <dependency>
         <groupId>org.springframework.experimental.ai</groupId>
         <artifactId>spring-ai-transformers-embedding-spring-boot-starter</artifactId>
         <version>0.7.1-SNAPSHOT</version>
      </dependency>
      

      follow the transformers-embedding instructions.

    • or OpenAI (Cloud)

      <dependency>
         <groupId>org.springframework.experimental.ai</groupId>
         <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
         <version>0.7.1-SNAPSHOT</version>
      </dependency>
      

      you'll need to provide your OpenAI API Key. Set it as an environment variable like so:

      export SPRING_AI_OPENAI_API_KEY='Your_OpenAI_API_Key'
      
  2. Weaviate VectorStore.

    <dependency>
       <groupId>org.springframework.experimental.ai</groupId>
       <artifactId>spring-ai-weaviate-store</artifactId>
       <version>0.7.1-SNAPSHOT</version>
    </dependency>
    

Usage

Create a WeaviateVectorStore instance connected to local Weaviate cluster:

   @Bean
   public VectorStore vectorStore(EmbeddingClient embeddingClient) {
      WeaviateVectorStoreConfig config = WeaviateVectorStoreConfig.builder()
         .withScheme("http")
         .withHost("localhost:8080")
         // Define the metadata fields to be used
         // in the similarity search filters.
         .withFilterableMetadataFields(List.of(
            MetadataField.text("country"),
            MetadataField.number("year"),
            MetadataField.bool("active")))
         // Consistency level can be: ONE, QUORUM or ALL.
         .withConsistencyLevel(ConsistentLevel.ONE)
         .build();

      return new WeaviateVectorStore(config, embeddingClient);
   }

Note

You must list explicitly all metadata field names and types (BOOLEAN, TEXT or NUMBER) for any metadata key used in filter expression. The withFilterableMetadataKeys above registers filterable metadata fields: country of type TEXT, year of type NUMBER and active of type BOOLEAN.

If the filterable metadata fields is expanded with new entires, you have to (re)upload/update the documents with this metadata.

You can use the following, Weaviate system metadata fields without explicit definition: id, _creationTimeUnix and _lastUpdateTimeUnix.

Then yn your main code, create some documents

List<Document> documents = List.of(
   new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("country", "UK", "active", true, "year", 2020)),
   new Document("The World is Big and Salvation Lurks Around the Corner", Map.of()),
   new Document("You walk forward facing the past and you turn back toward the future.", Map.of("country", "NL", "active", false, "year", 2023)));

Add the documents to your vector store:

vectorStore.add(List.of(document));

And finally, retrieve documents similar to a query:

List<Document> results = vectorStore.similaritySearch(
      SearchRequest
         .query("Spring")
         .withTopK(5));

If all goes well, you should retrieve the document containing the text "Spring AI rocks!!".

Metadata filtering

You can leverage the generic, portable metadata filters with WeaviateVectorStore as well.

For example you can use either the text expression language:

vectorStore.similaritySearch(
   SearchRequest
      .query("The World")
      .withTopK(TOP_K)
      .withSimilarityThreshold(SIMILARITY_THRESHOLD)
      .withFilterExpression("country in ['UK', 'NL'] && year >= 2020"));

or programmatically using the expression DSL:

FilterExpressionBuilder b = Filter.builder();

vectorStore.similaritySearch(
    SearchRequest
      .query("The World")
      .withTopK(TOP_K)
      .withSimilarityThreshold(SIMILARITY_THRESHOLD)
      .withFilterExpression(b.and(
         b.in("country", "UK", "NL"),
         b.gte("year", 2020)).build()));

The, portable, filter expressions get automatically converted into the proprietary Weaviate where filters. For example the following, portable, filter expression

country in ['UK', 'NL'] && year >= 2020

is converted into Weaviate, GraphQL, where filter expression:

operator:And
   operands:
      [{
         operator:Or
         operands:
            [{
               path:["meta_country"]
               operator:Equal
               valueText:"UK"
            },
            {
               path:["meta_country"]
               operator:Equal
               valueText:"NL"
            }]
      },
      {
         path:["meta_year"]
         operator:GreaterThanEqual
         valueNumber:2020
      }]

Appendix A: Run Weaviate cluster in docker container

Start Weaviate in a docker container:

docker run -it --rm --name weaviate -e AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true -e PERSISTENCE_DATA_PATH=/var/lib/weaviate -e QUERY_DEFAULTS_LIMIT=25 -e DEFAULT_VECTORIZER_MODULE=none -e CLUSTER_HOSTNAME=node1 -p 8080:8080 semitechnologies/weaviate:1.22.4

Starts a Weaviate cluster at http://localhost:8080/v1 with scheme=http, host=localhost:8080 and apiKey="". Then follow the usage instructions.