Move documentation that was in README.md into Antora.
* Add minimal ETL pipeline docs Fixes #137
This commit is contained in:
@@ -1,53 +0,0 @@
|
||||
# How to configure PDF Reader
|
||||
|
||||
|
||||
## PagePdfDocumentReader
|
||||
|
||||
``` java
|
||||
PagePdfDocumentReader pdfReader = new PagePdfDocumentReader(
|
||||
"file:document-readers/pdf-reader/src/test/resources/sample.pdf",
|
||||
PdfDocumentReaderConfig.builder()
|
||||
.withPageTopMargin(0)
|
||||
.withPageBottomMargin(0)
|
||||
.withPageExtractedTextFormatter(PageExtractedTextFormatter.builder()
|
||||
.withNumberOfTopTextLinesToDelete(0)
|
||||
.withNumberOfBottomTextLinesToDelete(3)
|
||||
.withNumberOfTopPagesToSkipBeforeDelete(0)
|
||||
.build())
|
||||
.withPagesPerDocument(1)
|
||||
.build());
|
||||
|
||||
var documents = pdfReader.get();
|
||||
|
||||
PdfTestUtils.writeToFile("document-readers/pdf-reader/target/sample.txt", documents, false);
|
||||
```
|
||||
|
||||
```java
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
ParagraphPdfDocumentReader pdfReader = new ParagraphPdfDocumentReader(
|
||||
"file:document-readers/pdf-reader/src/test/resources/sample2.pdf",
|
||||
PdfDocumentReaderConfig.builder()
|
||||
// .withPageBottomMargin(15)
|
||||
// .withReversedParagraphPosition(true)
|
||||
// .withTextLeftAlignment(true)
|
||||
.build());
|
||||
// ParagraphPdfDocumentReader pdfReader = new ParagraphPdfDocumentReader(
|
||||
// "file:document-readers/pdf-reader/src/test/resources/spring-framework.pdf",
|
||||
// PdfDocumentReaderConfig.builder()
|
||||
// .withPageBottomMargin(15)
|
||||
// .withReversedParagraphPosition(true)
|
||||
// // .withTextLeftAlignment(true)
|
||||
// .build());
|
||||
|
||||
// PdfDocumentReader pdfReader = new
|
||||
// PdfDocumentReader("file:document-readers/pdf-reader/src/test/resources/uber-k-10.pdf",
|
||||
// PdfDocumentReaderConfig.builder().withPageTopMargin(80).withPageBottomMargin(60).build());
|
||||
|
||||
var documents = pdfReader.get();
|
||||
|
||||
writeToFile("document-readers/pdf-reader/target/sample2.txt", documents, true);
|
||||
System.out.println(documents.size());
|
||||
|
||||
}
|
||||
```
|
||||
@@ -3,10 +3,19 @@
|
||||
* xref:getting-started.adoc[Getting Started]
|
||||
* xref:api/index.adoc[]
|
||||
** xref:api/aiclient.adoc[]
|
||||
*** xref:api/clients/huggingface.adoc[]
|
||||
** xref:api/prompt.adoc[]
|
||||
** xref:api/output-parser.adoc[]
|
||||
** xref:api/etl-pipeline.adoc[]
|
||||
** xref:api/embeddings.adoc[]
|
||||
*** xref:api/embeddings/onnx.adoc[]
|
||||
** xref:api/vectordbs.adoc[]
|
||||
*** xref:api/vectordbs/azure.adoc[]
|
||||
*** xref:api/vectordbs/chroma.adoc[]
|
||||
*** xref:api/vectordbs/milvus.adoc[]
|
||||
*** xref:api/vectordbs/neo4j.adoc[]
|
||||
*** xref:api/vectordbs/pgvector.adoc[]
|
||||
*** xref:api/vectordbs/weaviate.adoc[]
|
||||
** xref:api/testing.adoc[]
|
||||
* Appendices
|
||||
** xref:glossary.adoc[]
|
||||
|
||||
@@ -1,45 +1,48 @@
|
||||
# HuggingFace Inference Endpoints with Spring AI
|
||||
= HuggingFace
|
||||
|
||||
HuggingFace Inference Endpoints allow you to deploy and serve machine learning models in the cloud, making them accessible via an API. Further details on HuggingFace Inference Endpoints can be found [here](https://huggingface.co/docs/inference-endpoints/index).
|
||||
HuggingFace Inference Endpoints allow you to deploy and serve machine learning models in the cloud, making them accessible via an API. Further details on HuggingFace Inference Endpoints can be found link:https://huggingface.co/docs/inference-endpoints/index[here].
|
||||
|
||||
## Prerequisites
|
||||
== Prerequisites
|
||||
|
||||
Add the `spring-ai-huggingface` dependency:
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-huggingface</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
----
|
||||
|
||||
You should get your HuggingFace API key and set it as an environment variable
|
||||
|
||||
```shell
|
||||
[source,shell]
|
||||
----
|
||||
export HUGGINGFACE_API_KEY=your_api_key_here
|
||||
```
|
||||
----
|
||||
|
||||
Note, there is not yet a Spring Boot Starter for this client implementation.
|
||||
|
||||
Obtain the endpoint URL of the Inference Endpoint.
|
||||
You can find this on the Inference Endpoint's UI [here](https://ui.endpoints.huggingface.co/).
|
||||
You can find this on the Inference Endpoint's UI link:https://ui.endpoints.huggingface.co/[here].
|
||||
|
||||
== Making a call to the model
|
||||
|
||||
## Making a call to the model
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
HuggingfaceAiClient client = new HuggingfaceAiClient(apiKey, basePath);
|
||||
Prompt prompt = new Prompt("Your text here...");
|
||||
AiResponse response = client.generate(prompt);
|
||||
System.out.println(response.getGeneration().getText());
|
||||
```
|
||||
----
|
||||
|
||||
## Example
|
||||
== Example
|
||||
|
||||
Using the example found [here](https://www.promptingguide.ai/models/mistral-7b)
|
||||
Using the example found link:https://www.promptingguide.ai/models/mistral-7b[here]
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
String mistral7bInstruct = """
|
||||
[INST] You are a helpful code assistant. Your task is to generate a valid JSON object based on the given information:
|
||||
name: John
|
||||
@@ -50,17 +53,15 @@ String mistral7bInstruct = """
|
||||
Prompt prompt = new Prompt(mistral7bInstruct);
|
||||
AiResponse aiResponse = huggingfaceAiClient.generate(prompt);
|
||||
System.out.println(response.getGeneration().getText());
|
||||
```
|
||||
|
||||
----
|
||||
Will produce the output
|
||||
|
||||
````
|
||||
```json
|
||||
[source,json]
|
||||
----
|
||||
{
|
||||
"name": "John",
|
||||
"lastname": "Smith",
|
||||
"address": "#1 Samuel St."
|
||||
}
|
||||
```
|
||||
````
|
||||
Note the response itself is in Markdown format.
|
||||
----
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
# Ollama
|
||||
= Ollama
|
||||
|
||||
Ollama lets you get up and running with large language models locally.
|
||||
|
||||
Refer to the official [README](https://github.com/jmorganca/ollama) to get started.
|
||||
Refer to the official link:https://github.com/jmorganca/ollama[README] to get started.
|
||||
|
||||
Note, installing `ollama run llama2` will download a 4GB docker image.
|
||||
|
||||
You can run the disabled test in `OllamaClientTests.java` to kick the tires.
|
||||
|
||||
## How to use
|
||||
== How to use
|
||||
|
||||
Add the `spring-ai-ollama` dependency to your project's pom:
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-ollama</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
----
|
||||
|
||||
then create an client and use generate response:
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
var ollamaClient = new OllamaClient("http://127.0.0.1:11434", "llama2",
|
||||
ollamaResult -> {
|
||||
if (ollamaResult.getDone()) {
|
||||
@@ -31,26 +33,29 @@ var ollamaClient = new OllamaClient("http://127.0.0.1:11434", "llama2",
|
||||
});
|
||||
|
||||
AiResponse aiResponse = ollamaClient.generate(new Prompt("Hello"));
|
||||
```
|
||||
----
|
||||
|
||||
### Spring Boot Starter
|
||||
=== Spring Boot Starter
|
||||
|
||||
For convenience you can opt for the Ollama Boot starter.
|
||||
For this add the following dependency:
|
||||
For convenience, you can opt for the Ollama Boot starter.
|
||||
For this, add the following dependency:
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
----
|
||||
|
||||
and use the `spring.ai.ollama.*` properties to configure it if you want to use something other than the default values.
|
||||
|
||||
The complete list of supported properties are:
|
||||
|
||||
| Property | Description | Default |
|
||||
| -------- | ----- | ----- |
|
||||
| spring.ai.ollama.base-url | Base URL where Ollama API server is running. | `http://localhost:11434` |
|
||||
| spring.ai.ollama.model | Language model to use. | `llama2` |
|
||||
[cols="3,5,3"]
|
||||
|====
|
||||
| Property | Description | Default
|
||||
| spring.ai.ollama.base-url | Base URL where Ollama API server is running. | `http://localhost:11434`
|
||||
| spring.ai.ollama.model | Language model to use. | `llama2`
|
||||
|====
|
||||
@@ -1,3 +1,57 @@
|
||||
= Embeddings
|
||||
[[EmbeddingClient]]
|
||||
= EmbeddingClient
|
||||
|
||||
The `EmbeddingClient` interface is designed for straightforward integration with embedding models in AI and machine learning.
|
||||
Its primary function is to convert text into numerical vectors, commonly referred to as embeddings.
|
||||
These embeddings are crucial for various tasks such as semantic analysis and text classification.
|
||||
|
||||
The design of the EmbeddingClient interface centers around two primary goals:
|
||||
|
||||
* *Portability*: This interface ensures easy adaptability across various embedding models.
|
||||
It allows developers to switch between different embedding techniques or models with minimal code changes.
|
||||
This design aligns with Spring's philophy of modularity and interchangeability.
|
||||
|
||||
* *Simplicity*: EmbeddingClient simplifies the process of converting text to embeddings.
|
||||
By providing straightforward methods like `embed(String text)` and `embed(Document document)`, it takes the complexity out of dealing with raw text data and embedding algorithms. This design choice makes it easier for developers, especially those new to AI, to utilize embeddings in their applications without delving deep into the underlying mechanics.
|
||||
|
||||
== API Overview
|
||||
|
||||
This section provides a guide to the `EmbeddingClient` interface and associated classes.
|
||||
|
||||
=== EmbeddingClient
|
||||
Here is the `EmbeddingClient` interface definition:
|
||||
|
||||
java
|
||||
Copy code
|
||||
public interface EmbeddingClient {
|
||||
|
||||
List<Double> embed(String text);
|
||||
|
||||
List<Double> embed(Document document);
|
||||
|
||||
List<List<Double>> embed(List<String> texts);
|
||||
|
||||
EmbeddingResponse embedForResponse(List<String> texts);
|
||||
|
||||
default int dimensions() {
|
||||
return embed("Test String").size();
|
||||
}
|
||||
|
||||
}
|
||||
The embed methods offer various options for converting text into embeddings, accommodating single strings, structured Document objects, or batches of text.
|
||||
The returned values are lists of doubles, representing the embeddings in a numerical vector format.
|
||||
|
||||
The `embedForResponse` method provides a more comprehensive output, potentially including additional information about the embeddings.
|
||||
|
||||
The dimensions method is a handy tool for developers to quickly ascertain the size of the embedding vectors, which is important for understanding the embedding space and for subsequent processing steps.
|
||||
|
||||
|
||||
== Available Implementations
|
||||
|
||||
The `EmbeddingClient` interface has the following available implementations:
|
||||
|
||||
* OpenAI: Using the https://github.com/TheoKanning/openai-java[Theo Kanning client library].
|
||||
* Azure OpenAI: Using https://learn.microsoft.com/en-us/java/api/overview/azure/ai-openai-readme?view=azure-java-preview[Microsoft's OpenAI client library].
|
||||
* PostgresML: https://postgresml.org/docs/[PostgresML is a complete MLOps platform built on PostgreSQL]
|
||||
* Sentence embedding with local ONNX models: The https://djl.ai/[Deep Java Library] and the Microsoft https://onnxruntime.ai/docs/get-started/with-java.html[ONNX Java Runtime] libraries are applied to run the ONNX models and compute the embeddings in Java.
|
||||
|
||||
TBD
|
||||
@@ -1,59 +1,63 @@
|
||||
# Local Transformers Embedding Client
|
||||
= ONNX
|
||||
|
||||
The `TransformersEmbeddingClient` is a `EmbeddingClient` implementation that computes, locally, [sentence embeddings](https://www.sbert.net/examples/applications/computing-embeddings/README.html#sentence-embeddings-with-transformers) using a selected [sentence transformer](https://www.sbert.net/).
|
||||
The `TransformersEmbeddingClient` is an `EmbeddingClient` implementation that computes, locally, https://www.sbert.net/examples/applications/computing-embeddings/README.html#sentence-embeddings-with-transformers[sentence embeddings] using a selected https://www.sbert.net/[sentence transformer].
|
||||
|
||||
It uses [pre-trained](https://www.sbert.net/docs/pretrained_models.html) transformer models, serialized into the [Open Neural Network Exchange (ONNX)](https://onnx.ai/) format.
|
||||
It uses https://www.sbert.net/docs/pretrained_models.html[pre-trained] transformer models, serialized into the https://onnx.ai/[Open Neural Network Exchange (ONNX)] format.
|
||||
|
||||
The [Deep Java Library](https://djl.ai/) and the Microsoft [ONNX Java Runtime](https://onnxruntime.ai/docs/get-started/with-java.html) libraries are applied to run the ONNX models and compute the embeddings in Java.
|
||||
The https://djl.ai/[Deep Java Library] and the Microsoft https://onnxruntime.ai/docs/get-started/with-java.html[ONNX Java Runtime] libraries are applied to run the ONNX models and compute the embeddings in Java.
|
||||
|
||||
## Serialize the Tokenizer and the Transformer Model
|
||||
== Serialize the Tokenizer and the Transformer Model
|
||||
|
||||
To run things in Java, we need to serialize the Tokenizer and the Transformer Model into ONNX format.
|
||||
|
||||
### Serialize with optimum-cli
|
||||
=== Serialize with optimum-cli
|
||||
|
||||
One, quick, way to achieve this, is to use the [optimum-cli](https://huggingface.co/docs/optimum/exporters/onnx/usage_guides/export_a_model#exporting-a-model-to-onnx-using-the-cli) command line tool.
|
||||
One, quick, way to achieve this, is to use the https://huggingface.co/docs/optimum/exporters/onnx/usage_guides/export_a_model#exporting-a-model-to-onnx-using-the-cli[optimum-cli] command line tool.
|
||||
|
||||
Following snippet prepares a python virtual environment, installs the required packages and serializes (e.g. exports) specified model using `optimum-cli` :
|
||||
|
||||
```bash
|
||||
[source,bash]
|
||||
----
|
||||
python3 -m venv venv
|
||||
source ./venv/bin/activate
|
||||
(venv) pip install --upgrade pip
|
||||
(venv) pip install optimum onnx onnxruntime
|
||||
(venv) optimum-cli export onnx --model sentence-transformers/all-MiniLM-L6-v2 onnx-output-folder
|
||||
```
|
||||
----
|
||||
|
||||
The snippet exports the [sentence-transformers/all-MiniLM-L6-v2](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2) transformer into the `onnx-output-folder` folder. Later includes the `tokenizer.json` and `model.onnx` files used by the embedding client.
|
||||
The snippet exports the https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2[sentence-transformers/all-MiniLM-L6-v2] transformer into the `onnx-output-folder` folder. Later includes the `tokenizer.json` and `model.onnx` files used by the embedding client.
|
||||
|
||||
In place of the all-MiniLM-L6-v2 you can pick any huggingface transformer identifier or provide direct file path.
|
||||
|
||||
## Using the ONNX models
|
||||
== Using the ONNX models
|
||||
|
||||
Add the `transformers-embedding` project to your maven dependencies:
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>transformers-embedding</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
----
|
||||
|
||||
then create a new `TransformersEmbeddingClient` instance and use the `setTokenizerResource(tokenizerJsonUri)` and `setModelResource(modelOnnxUri)` methods to set the URIs of the exported `tokenizer.json` and `model.onnx` files. (`classpath:`, `file:` or `https:` URI schemas are supported).
|
||||
|
||||
If the model is not explicitly set, `TransformersEmbeddingClient` defaults to [sentence-transformers/all-MiniLM-L6-v2](https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2):
|
||||
If the model is not explicitly set, `TransformersEmbeddingClient` defaults to https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2[sentence-transformers/all-MiniLM-L6-v2]:
|
||||
|
||||
| | |
|
||||
| -------- | ------- |
|
||||
| Dimensions |384 |
|
||||
| Avg. performance | 58.80 |
|
||||
| Speed | 14200 sentences/sec |
|
||||
| Size | 80MB |
|
||||
[cols="2*"]
|
||||
|===
|
||||
| Dimensions | 384
|
||||
| Avg. performance | 58.80
|
||||
| Speed | 14200 sentences/sec
|
||||
| Size | 80MB
|
||||
|===
|
||||
|
||||
Following snippet illustrates how to use the `TransformersEmbeddingClient` manually:
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
TransformersEmbeddingClient embeddingClient = new TransformersEmbeddingClient();
|
||||
|
||||
// (optional) defaults to classpath:/onnx/all-MiniLM-L6-v2/tokenizer.json
|
||||
@@ -74,7 +78,7 @@ embeddingClient.afterPropertiesSet();
|
||||
|
||||
List<List<Double>> embeddings = embeddingClient.embed(List.of("Hello world", "World is big"));
|
||||
|
||||
```
|
||||
----
|
||||
|
||||
Note that when created manually you have to call the `afterPropertiesSet()` after setting the properties and before using the client.
|
||||
|
||||
@@ -86,49 +90,52 @@ The default cache folder is `${java.io.tmpdir}/spring-ai-onnx-model`.
|
||||
It is more convenient (and preferred) to create the TransformersEmbeddingClient as a `Bean`.
|
||||
Then you don't have to call the `afterPropertiesSet()` manually.
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public EmbeddingClient embeddingClient() {
|
||||
return new TransformersEmbeddingClient();
|
||||
}
|
||||
```
|
||||
----
|
||||
|
||||
## Transformers Embedding Spring Boot Starter.
|
||||
== Transformers Embedding Spring Boot Starter.
|
||||
|
||||
You can bootstrap and auto-wire the `TransformersEmbeddingClient` with following boot starer:
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-transformers-embedding-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
----
|
||||
|
||||
and use the `spring.ai.embedding.transformer.*` properties to configure it.
|
||||
|
||||
For example add this to your application.properties to configure with the [intfloat/e5-small-v2](https://huggingface.co/intfloat/e5-small-v2) text embedding model:
|
||||
For example add this to your application.properties to configure with the https://huggingface.co/intfloat/e5-small-v2[intfloat/e5-small-v2] text embedding model:
|
||||
|
||||
```
|
||||
----
|
||||
spring.ai.embedding.transformer.onnx.modelUri=https://huggingface.co/intfloat/e5-small-v2/resolve/main/model.onnx
|
||||
spring.ai.embedding.transformer.tokenizer.uri=https://huggingface.co/intfloat/e5-small-v2/raw/main/tokenizer.json
|
||||
```
|
||||
----
|
||||
|
||||
The complete list of supported properties are:
|
||||
|
||||
| Property | Description | Default |
|
||||
| -------- | ------- | ------- |
|
||||
| spring.ai.embedding.transformer.tokenizer.uri | URI of a pre-trained HuggingFaceTokenizer created by the ONNX engine (e.g. tokenizer.json). | onnx/all-MiniLM-L6-v2/tokenizer.json |
|
||||
| spring.ai.embedding.transformer.tokenizer.options | HuggingFaceTokenizer options such as '`addSpecialTokens`', '`modelMaxLength`', '`truncation`', '`padding`', '`maxLength`', '`stride`' and '`padToMultipleOf`'. Leave empty to fallback to the defaults. | empty |
|
||||
| spring.ai.embedding.transformer.cache.enabled | Enable remote Resource caching. | true |
|
||||
| spring.ai.embedding.transformer.cache.directory | Directory path to cache remote resources, such as the ONNX models | ${java.io.tmpdir}/spring-ai-onnx-model |
|
||||
| spring.ai.embedding.transformer.onnx.modelUri | Existing, pre-trained ONNX model. | onnx/all-MiniLM-L6-v2/model.onnx |
|
||||
| spring.ai.embedding.transformer.onnx.gpuDeviceId | The GPU device ID to execute on. Only applicable if >= 0. Ignored otherwise. | -1 |
|
||||
| spring.ai.embedding.transformer.metadataMode | Specifies what parts of the Documents content and metadata will be used for computing the embeddings. | NONE |
|
||||
|
||||
[cols="3*"]
|
||||
|===
|
||||
| Property | Description | Default
|
||||
| spring.ai.embedding.transformer.tokenizer.uri | URI of a pre-trained HuggingFaceTokenizer created by the ONNX engine (e.g. tokenizer.json). | onnx/all-MiniLM-L6-v2/tokenizer.json
|
||||
| spring.ai.embedding.transformer.tokenizer.options | HuggingFaceTokenizer options such as '`addSpecialTokens`', '`modelMaxLength`', '`truncation`', '`padding`', '`maxLength`', '`stride`', '`padToMultipleOf`'. Leave empty to fallback to the defaults. | empty
|
||||
| spring.ai.embedding.transformer.cache.enabled | Enable remote Resource caching. | true
|
||||
| spring.ai.embedding.transformer.cache.directory | Directory path to cache remote resources, such as the ONNX models | ${java.io.tmpdir}/spring-ai-onnx-model
|
||||
| spring.ai.embedding.transformer.onnx.modelUri | Existing, pre-trained ONNX model. | onnx/all-MiniLM-L6-v2/model.onnx
|
||||
| spring.ai.embedding.transformer.onnx.gpuDeviceId | The GPU device ID to execute on. Only applicable if >= 0. Ignored otherwise. | -1
|
||||
| spring.ai.embedding.transformer.metadataMode | Specifies what parts of the Documents content and metadata will be used for computing the embeddings. | NONE
|
||||
|===
|
||||
|
||||
Note: if you see error like: `Caused by: ai.onnxruntime.OrtException: Supplied array is ragged,..` then you need to enable the tokenizer padding in boot starter's `application.properties`:
|
||||
|
||||
```
|
||||
----
|
||||
spring.ai.embedding.transformer.tokenizer.options.padding=true
|
||||
```
|
||||
----
|
||||
@@ -1,3 +1,150 @@
|
||||
= Document Readers
|
||||
= ETL Pipeline
|
||||
|
||||
TBD
|
||||
The Extraction, Transformation, and Loading (ETL) framework serves as the backbone of data processing within the Retrieval-Augmented Generation (RAG) use case.
|
||||
|
||||
The ETL pipeline orchestrates the flow from raw data sources to a structured vector store, ensuring data is in the optimal format for retrieval by the AI model.
|
||||
|
||||
The RAG use-case is designed to augment the capabilities of generative models by retrieving relevant information from a body of data to enhancing the quality and relevance of the generated output.
|
||||
|
||||
|
||||
== API Overview
|
||||
|
||||
=== DocumentReader
|
||||
|
||||
```java
|
||||
public interface DocumentReader extends Supplier<List<Document>> {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
=== DocumentTransformer
|
||||
|
||||
```java
|
||||
public interface DocumentTransformer extends Function<List<Document>, List<Document>> {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
=== DocumentWriter
|
||||
|
||||
```java
|
||||
public interface DocumentWriter extends Consumer<List<Document>> {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
=== Available Implementations
|
||||
|
||||
==== DocumentReader Interface
|
||||
|
||||
*Supplier<List<Document>>*::
|
||||
+ Provides a source of documents from diverse origins.
|
||||
|
||||
*JsonReader*::
|
||||
+ Parses documents in JSON format.
|
||||
|
||||
*TextReader*::
|
||||
+ Processes plain text documents.
|
||||
|
||||
*Document*::
|
||||
+ Represents the core data structure manipulated throughout the pipeline.
|
||||
|
||||
|
||||
=== DocumentTransformer Interface
|
||||
|
||||
*Function<List<Document>, List<Document>>*::
|
||||
+ Transforms a batch of documents as part of the processing workflow.
|
||||
|
||||
*TextSplitter*::
|
||||
+ Divides documents to fit the AI model's context window.
|
||||
|
||||
*TokenTextSplitter*::
|
||||
+ Splits documents while preserving token-level integrity.
|
||||
|
||||
*ContentFormatTransformer*::
|
||||
+ Ensures uniform content formats across all documents.
|
||||
|
||||
*KeywordMetadataEnricher*::
|
||||
+ Augments documents with essential keyword metadata.
|
||||
|
||||
*SummaryMetadataEnricher*::
|
||||
+ Enriches documents with summarization metadata for enhanced retrieval.
|
||||
|
||||
=== DocumentWriter Interface
|
||||
|
||||
*Consumer<List<Document>>*::
|
||||
+ Manages the final stage of the ETL process, preparing documents for storage.
|
||||
|
||||
*VectorStore*::
|
||||
+ The abstracted interface for vector database interactions.
|
||||
|
||||
*MilvusVectorStore*::
|
||||
+ An implementation for the Milvus vector database.
|
||||
|
||||
*PgVectorStore*::
|
||||
+ Provides vector storage capabilities using PostgreSQL.
|
||||
|
||||
*SimplePersistentVectorStore*::
|
||||
+ A straightforward approach to persistent vector storage.
|
||||
|
||||
*InMemoryVectorStore*::
|
||||
+ Enables rapid access with in-memory storage solutions.
|
||||
|
||||
*Neo4jVectorStore*::
|
||||
+ Leverages the Neo4j graph database for vector storage.
|
||||
|
||||
== Using PDF Reader
|
||||
|
||||
|
||||
== Using PagePdfDocumentReader
|
||||
|
||||
[source,java]
|
||||
----
|
||||
PagePdfDocumentReader pdfReader = new PagePdfDocumentReader(
|
||||
"file:document-readers/pdf-reader/src/test/resources/sample.pdf",
|
||||
PdfDocumentReaderConfig.builder()
|
||||
.withPageTopMargin(0)
|
||||
.withPageBottomMargin(0)
|
||||
.withPageExtractedTextFormatter(PageExtractedTextFormatter.builder()
|
||||
.withNumberOfTopTextLinesToDelete(0)
|
||||
.withNumberOfBottomTextLinesToDelete(3)
|
||||
.withNumberOfTopPagesToSkipBeforeDelete(0)
|
||||
.build())
|
||||
.withPagesPerDocument(1)
|
||||
.build());
|
||||
|
||||
var documents = pdfReader.get();
|
||||
|
||||
PdfTestUtils.writeToFile("document-readers/pdf-reader/target/sample.txt", documents, false);
|
||||
----
|
||||
|
||||
[source,java]
|
||||
----
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
ParagraphPdfDocumentReader pdfReader = new ParagraphPdfDocumentReader(
|
||||
"file:document-readers/pdf-reader/src/test/resources/sample2.pdf",
|
||||
PdfDocumentReaderConfig.builder()
|
||||
// .withPageBottomMargin(15)
|
||||
// .withReversedParagraphPosition(true)
|
||||
// .withTextLeftAlignment(true)
|
||||
.build());
|
||||
// ParagraphPdfDocumentReader pdfReader = new ParagraphPdfDocumentReader(
|
||||
// "file:document-readers/pdf-reader/src/test/resources/spring-framework.pdf",
|
||||
// PdfDocumentReaderConfig.builder()
|
||||
// .withPageBottomMargin(15)
|
||||
// .withReversedParagraphPosition(true)
|
||||
// // .withTextLeftAlignment(true)
|
||||
// .build());
|
||||
|
||||
// PdfDocumentReader pdfReader = new
|
||||
// PdfDocumentReader("file:document-readers/pdf-reader/src/test/resources/uber-k-10.pdf",
|
||||
// PdfDocumentReaderConfig.builder().withPageTopMargin(80).withPageBottomMargin(60).build());
|
||||
|
||||
var documents = pdfReader.get();
|
||||
|
||||
writeToFile("document-readers/pdf-reader/target/sample2.txt", documents, true);
|
||||
System.out.println(documents.size());
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
@@ -1,3 +1,123 @@
|
||||
[[OutputParser]]
|
||||
|
||||
= Output Parsers
|
||||
|
||||
TBD
|
||||
The `OutputParser` interface allows you to obtain structured output, for example ampping the output to a Java class or an array of values from the String based ouput of AI Models.
|
||||
|
||||
You can think of it in terms similar to Spring JDBC's concept of a `RowMapper` or `ResultSetExtractor`.
|
||||
Developers want to quickly turn results from an AI model into data types that can be passed to other functions and methods in their application.
|
||||
The `OutputParser` helps achieve that goal.
|
||||
|
||||
== API Overview
|
||||
|
||||
This section provides a guide to the `OutputParser` interface.
|
||||
|
||||
=== OutputParser
|
||||
|
||||
Here is the `OutputParser` interface definition
|
||||
|
||||
```java
|
||||
public interface OutputParser<T> extends Parser<T>, FormatProvider {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
It combines the `Parser<T>` interface
|
||||
|
||||
```java
|
||||
@FunctionalInterface
|
||||
public interface Parser<T> {
|
||||
T parse(String text);
|
||||
}
|
||||
```
|
||||
|
||||
and the `FormatProvider` interface
|
||||
|
||||
```java
|
||||
public interface FormatProvider {
|
||||
|
||||
String getFormat();
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
The `Parser` interface parses text strings to produce instances of the type T.
|
||||
|
||||
The `FormatProvider` provides text instructions for the AI Model to format the output so that it an be parsed into the type T by the `Parser`.
|
||||
These text instructions are most often appended to the end of the user input to the AI Model.
|
||||
|
||||
|
||||
== Available Implementations
|
||||
|
||||
The `OutputParser` interface has the following available implementations.
|
||||
|
||||
|
||||
* `BeanOutputParser`: Specifies the JSON schema for Java class and uses `DRAFT_2020_12` of the JSON schema specification as OpenAI has indicated this would give the best results.
|
||||
The JSON output of the AI Model is then deserialized to a Java object, aka `JavaBean`.
|
||||
* MapOutputParser: Similar to BeanOutputParser but the JSON payload is deserialized into a `java.util.Map<String, Object> instance.
|
||||
* `ListOutputParser`: Specifies the output to be a comma delimited list.
|
||||
|
||||
|
||||
There has been considerable effort in recent OpenAI models to improve the model's ability to return JSON by simply specifying 'return in JSON', but not all models support such direct support for returning structured data.
|
||||
|
||||
|
||||
== Example Usage
|
||||
|
||||
You can run a fully working example that demonstrates the use of `BeanOutputParser` as part of the https://github.com/Azure-Samples/spring-ai-azure-workshop[Spring AI Azure Workshop].
|
||||
Part of this workshop code is reproduced below.
|
||||
|
||||
The use case for the example is to as the AI Model to generate the filography for an actor.
|
||||
|
||||
The User prompt used is
|
||||
|
||||
```
|
||||
String userMessage = """
|
||||
Generate the filmography for the actor {actor}.
|
||||
{format}
|
||||
""";
|
||||
```
|
||||
|
||||
The class `ActorsFilms` shown below
|
||||
|
||||
```java
|
||||
public class ActorsFilms {
|
||||
|
||||
private String actor;
|
||||
|
||||
private List<String> movies;
|
||||
|
||||
// getters and toString omitted
|
||||
}
|
||||
```
|
||||
|
||||
Here is a controller class that shows these classes in use
|
||||
|
||||
|
||||
```java
|
||||
@GetMapping("/ai/output")
|
||||
public ActorsFilms generate(@RequestParam(value = "actor", defaultValue = "Jeff Bridges") String actor) {
|
||||
var outputParser = new BeanOutputParser<>(ActorsFilms.class);
|
||||
|
||||
String userMessage =
|
||||
"""
|
||||
Generate the filmography for the actor {actor}.
|
||||
{format}
|
||||
""";
|
||||
|
||||
PromptTemplate promptTemplate = new PromptTemplate(userMessage, Map.of("actor", actor, "format", outputParser.getFormat() ));
|
||||
Prompt prompt = promptTemplate.create();
|
||||
Generation generation = aiClient.generate(prompt).getGeneration();
|
||||
|
||||
ActorsFilms actorsFilms = outputParser.parse(generation.getText());
|
||||
return actorsFilms;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
= Evaluation Testing
|
||||
|
||||
TBD
|
||||
@@ -99,6 +99,8 @@ More implementations may be supported in future releases.
|
||||
|
||||
If you have a vector database that needs to be supported by Spring AI, open an issue on GitHub or, even better, submit a pull request with an implementation.
|
||||
|
||||
Information on each of the Vector Store implementations can be found in the subsections of this chapter.
|
||||
|
||||
== Example Usage
|
||||
|
||||
To compute the embeddings for a vector database, you need to pick an embedding model that matches the higher-level AI model being used.
|
||||
@@ -202,6 +204,7 @@ Consider the following example:
|
||||
Expression exp = b.and(b.eq("genre", "drama"), b.gte("year", 2020)).build();
|
||||
----
|
||||
|
||||
|
||||
== Understanding Vectors
|
||||
|
||||
Vectors have dimensionality and a direction.
|
||||
@@ -299,3 +302,4 @@ stem:[similarity(vec{A},vec{B}) = \cos(\theta) = \frac{ \sum_{i=1}^{n} {A_i B_i
|
||||
****
|
||||
|
||||
This is the key formula used in the simple implementation of a vector store and can be found in the `InMemoryVectorStore` implementation.
|
||||
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
= Azure AI Service
|
||||
|
||||
This section will walk you through setting up the AzureVectorStore to store document embeddings and perform similarity searches using the Azure AI Search Service.
|
||||
|
||||
link:https://azure.microsoft.com/en-us/products/ai-services/cognitive-search[Azure AI Search] is a versatile cloud-hosted cloud information retrieval system that is part of Microsoft's larger AI platform. Among other features, it allows users to query information using vector-based storage and retrieval.
|
||||
|
||||
== Prerequisites
|
||||
|
||||
1. Azure Subscription: You will need an link:https://azure.microsoft.com/en-us/free/[Azure subscription] to use any Azure service.
|
||||
2. Azure AI Search Service: Create an link:https://portal.azure.com/#create/Microsoft.Search[AI Search service]. Once the service is created, obtain the admin apiKey from the `Keys` section under `Settings` and retrieve the endpoint from the `Url` field under the `Overview` section.
|
||||
3. (Optional) Azure OpenAI Service: Create an Azure link:https://portal.azure.com/#create/Microsoft.AIServicesOpenAI[OpenAI service]. **NOTE:** You may have to fill out a separate form to gain access to Azure Open AI services. Once the service is created, obtain the endpoint and apiKey from the `Keys and Endpoint` section under `Resource Management`.
|
||||
|
||||
== Configuration
|
||||
|
||||
On startup, the AzureVectorStore will attempt to create a new index within your AI Search service instance. Alternatively, you can create the index manually as explained in <<appendix-a, Appendix A>>.
|
||||
|
||||
To set up an AzureVectorStore, you will need the settings retrieved from the prerequisites above along with your index name:
|
||||
|
||||
* Azure AI Search Endpoint
|
||||
* Azure AI Search Key
|
||||
* (optional) Azure OpenAI API Endpoint
|
||||
* (optional) Azure OpenAI API Key
|
||||
|
||||
You can provide these values as OS environment variables.
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
export AZURE_AI_SEARCH_API_KEY=<My AI Search API Key>
|
||||
export AZURE_AI_SEARCH_ENDPOINT=<My AI Search Index>
|
||||
export OPENAI_API_KEY=<My Azure AI API Key> (Optional)
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
You can replace Azure Open AI implementation with any valid OpenAI implementation that supports the Embeddings interface. For example, you could use Spring AI's Open AI or TransformersEmbedding implementations for embeddings instead of the Azure implementation.
|
||||
====
|
||||
|
||||
== Dependencies
|
||||
|
||||
Add these dependencies to your project:
|
||||
|
||||
1. Select an Embeddings interface implementation. You can choose between:
|
||||
|
||||
* or OpenAI Embedding:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
* Or Azure AI Embedding:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
* Or Local Sentence Transformers Embedding:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-transformers-embedding-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
2. Azure (AI Search) Vector Store
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-azure-vector-store</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
== Sample Code
|
||||
|
||||
To configure an Azure `SearchIndexClient` in your application, you can use the following code:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public SearchIndexClient searchIndexClient() {
|
||||
return new SearchIndexClientBuilder().endpoint(System.getenv("AZURE_AI_SEARCH_ENDPOINT"))
|
||||
.credential(new AzureKeyCredential(System.getenv("AZURE_AI_SEARCH_API_KEY")))
|
||||
.buildClient();
|
||||
}
|
||||
----
|
||||
|
||||
To create a vector store, you can use the following code by injecting the `SearchIndexClient` bean created in the above sample along with an `EmbeddingClient` provided by the Spring AI library that implements the desired Embeddings interface.
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public VectorStore vectorStore(SearchIndexClient searchIndexClient, EmbeddingClient embeddingClient) {
|
||||
return new AzureVectorStore(searchIndexClient, embeddingClient,
|
||||
// Define the metadata fields to be used
|
||||
// in the similarity search filters.
|
||||
List.of(MetadataField.text("country"),
|
||||
MetadataField.int64("year"),
|
||||
MetadataField.bool("active")));
|
||||
}
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
You must list explicitly all metadata field names and types for any metadata key used in the filter expression. The list above registers filterable metadata fields: `country` of type `TEXT`, `year` of type `INT64`, and `active` of type `BOOLEAN`.
|
||||
|
||||
If the filterable metadata fields are expanded with new entries, you have to (re)upload/update the documents with this metadata.
|
||||
====
|
||||
|
||||
In your main code, create some documents:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
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", "BG", "year", 2020)),
|
||||
new Document("The World is Big and Salvation Lurks Around the Corner"),
|
||||
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("country", "NL", "year", 2023)));
|
||||
----
|
||||
|
||||
Add the documents to your vector store:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
vectorStore.add(List.of(document));
|
||||
----
|
||||
|
||||
And finally, retrieve documents similar to a query:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
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 link:https://docs.spring.io/spring-ai/reference/api/vectordbs.html#_metadata_filters[metadata filters] with AzureVectorStore as well.
|
||||
|
||||
For example, you can use either the text expression language:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
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:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
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 Azure Search link:https://learn.microsoft.com/en-us/azure/search/search-query-odata-filter[OData filters]. For example, the following portable filter expression:
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
country in ['UK', 'NL'] && year >= 2020
|
||||
----
|
||||
|
||||
is converted into Azure OData link:https://learn.microsoft.com/en-us/azure/search/search-query-odata-filter[filter expression]:
|
||||
|
||||
[source,graphql]
|
||||
----
|
||||
$filter search.in(meta_country, 'UK,NL', ',') and meta_year ge 2020
|
||||
----
|
||||
@@ -0,0 +1,164 @@
|
||||
= Chroma
|
||||
|
||||
This section will walk you through setting up the Chroma VectorStore to store document embeddings and perform similarity searches.
|
||||
|
||||
link:https://github.com/chroma-core/chroma/pkgs/container/chroma[Chroma Container]
|
||||
|
||||
== What is Chroma?
|
||||
|
||||
link:https://docs.trychroma.com/[Chroma] is the open-source embedding database. It gives you the tools to store document embeddings, content, and metadata and to search through those embeddings, including metadata filtering.
|
||||
|
||||
=== Prerequisites
|
||||
|
||||
1. OpenAI Account: Create an account at link:https://platform.openai.com/signup[OpenAI Signup] and generate the token at link:https://platform.openai.com/account/api-keys[API Keys].
|
||||
|
||||
2. Access to ChromeDB. The <<appendix-a, setup local ChromaDB>> appendix shows how to set up a DB locally with a Docker container.
|
||||
|
||||
On startup, the `ChromaVectorStore` creates the required collection if one is not provisioned already.
|
||||
|
||||
== Configuration
|
||||
|
||||
To set up ChromaVectorStore, you'll need to provide your OpenAI API Key. Set it as an environment variable like so:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
export SPRING_AI_OPENAI_API_KEY='Your_OpenAI_API_Key'
|
||||
----
|
||||
|
||||
== Dependencies
|
||||
|
||||
Add these dependencies to your project:
|
||||
|
||||
* OpenAI: Required for calculating embeddings.
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||||
<version>0.7.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
* Chroma VectorStore.
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-chroma-store</artifactId>
|
||||
<version>0.7.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
== Sample Code
|
||||
|
||||
Create a `RestTemplate` instance with proper ChromaDB authorization configurations and Use it to create a `ChromaApi` instance:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ChromaApi chromaApi(RestTemplate restTemplate) {
|
||||
String chromaUrl = "http://localhost:8000";
|
||||
ChromaApi chromaApi = ChromaApi(chromaUrl, restTemplate);
|
||||
return chromaApi;
|
||||
}
|
||||
----
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
For ChromaDB secured with link:https://docs.trychroma.com/usage-guide#static-api-token-authentication[Static API Token Authentication] use the `ChromaApi#withKeyToken(<Your Token Credentials>)` method to set your credentials. Check the `ChromaWhereIT` for an example.
|
||||
|
||||
For ChromaDB secured with link:https://docs.trychroma.com/usage-guide#basic-authentication[Basic Authentication] use the `ChromaApi#withBasicAuth(<your user>, <your password>)` method to set your credentials. Check the `BasicAuthChromaWhereIT` for an example.
|
||||
====
|
||||
|
||||
Integrate with OpenAI's embeddings by adding the Spring Boot OpenAI starter to your project. This provides you with an implementation of the Embeddings client:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public VectorStore chromaVectorStore(EmbeddingClient embeddingClient, ChromaApi chromaApi) {
|
||||
return new ChromaVectorStore(embeddingClient, chromaApi, "TestCollection");
|
||||
}
|
||||
----
|
||||
|
||||
In your main code, create some documents:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
List<Document> documents = List.of(
|
||||
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("meta1", "meta1")),
|
||||
new Document("The World is Big and Salvation Lurks Around the Corner"),
|
||||
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("meta2", "meta2")));
|
||||
----
|
||||
|
||||
Add the documents to your vector store:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
vectorStore.add(List.of(document));
|
||||
----
|
||||
|
||||
And finally, retrieve documents similar to a query:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
List<Document> results = vectorStore.similaritySearch("Spring", 5);
|
||||
----
|
||||
|
||||
If all goes well, you should retrieve the document containing the text "Spring AI rocks!!".
|
||||
|
||||
=== Metadata filtering
|
||||
|
||||
You can leverage the generic, portable link:https://docs.spring.io/spring-ai/reference/api/vectordbs.html#_metadata_filters[metadata filters] with ChromaVector store as well.
|
||||
|
||||
For example, you can use either the text expression language:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
vectorStore.similaritySearch("The World", TOP_K, SIMILARITY_THRESHOLD,
|
||||
"author in ['john', 'jill'] && article_type == 'blog'");
|
||||
----
|
||||
|
||||
or programmatically using the `Filter.Expression` DSL:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
FilterExpressionBuilder b = new FilterExpressionBuilder();
|
||||
|
||||
vectorStore.similaritySearch("The World", TOP_K, SIMILARITY_THRESHOLD,
|
||||
b.and(
|
||||
b.in(List.of("john", "jill")),
|
||||
b.eq("article_type", "blog")).build());
|
||||
----
|
||||
|
||||
NOTE: Those (portable) filter expressions get automatically converted into the proprietary Chroma `where` link:https://docs.trychroma.com/usage-guide#using-where-filters[filter expressions].
|
||||
|
||||
For example, this portable filter expression:
|
||||
|
||||
```sql
|
||||
author in ['john', 'jill'] && article_type == 'blog'
|
||||
```
|
||||
|
||||
is converted inot the proprietyar Chroma format
|
||||
|
||||
```json
|
||||
{"$and":[
|
||||
{"author": {"$in": ["john", "jill"]}},
|
||||
{"article_type":{"$eq":"blog"}}]
|
||||
}
|
||||
```
|
||||
|
||||
=== Run Chroma Locally
|
||||
|
||||
```shell
|
||||
docker run -it --rm --name chroma -p 8000:8000 ghcr.io/chroma-core/chroma:0.4.15
|
||||
```
|
||||
|
||||
Starts a chroma store at <http://localhost:8000/api/v1>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
= Milvus
|
||||
|
||||
link:https://milvus.io/[Milvus] is an open-source vector database that has garnered significant attention in the fields of data science and machine learning. One of its standout features lies in its robust support for vector indexing and querying. Milvus employs state-of-the-art, cutting-edge algorithms to accelerate the search process, making it exceptionally efficient at retrieving similar vectors, even when handling extensive datasets.
|
||||
|
||||
Milvus's popularity also comes from its ease of integration with popular Python-based frameworks such as PyTorch and TensorFlow, allowing for seamless inclusion in existing machine learning workflows.
|
||||
|
||||
In the e-commerce industry, Milvus is used in recommendation systems, which suggest products based on user preferences. In image and video analysis, it excels in tasks like object recognition, image similarity search, and content-based image retrieval. Additionally, it is commonly used in natural language processing for document clustering, semantic search, and question-answering systems.
|
||||
|
||||
== Starting Milvus Store
|
||||
|
||||
From within the `src/test/resources/` folder run:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
docker-compose up
|
||||
----
|
||||
|
||||
To clean the environment:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
docker-compose down; rm -Rf ./volumes
|
||||
----
|
||||
|
||||
Then connect to the vector store on link:http://localhost:19530[http://localhost:19530] or for management link:http://localhost:9001[http://localhost:9001] (user: `minioadmin`, pass: `minioadmin`)
|
||||
|
||||
== Troubleshooting
|
||||
|
||||
If Docker complains about resources, then execute:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
docker system prune --all --force --volumes
|
||||
----
|
||||
@@ -0,0 +1,81 @@
|
||||
= Neo4j
|
||||
|
||||
This section walks you through setting up `Neo4jVectorStore` to store document embeddings and perform similarity searches.
|
||||
|
||||
== What is Neo4j?
|
||||
|
||||
link:https://neo4j.com[Neo4j] is an open-source NoSQL graph database. It is a fully transactional database (ACID) that stores data structured as graphs consisting of nodes, connected by relationships. Inspired by the structure of the real world, it allows for high query performance on complex data while remaining intuitive and simple for the developer.
|
||||
|
||||
== What is Neo4j Vector Search?
|
||||
|
||||
link:https://neo4j.com/docs/cypher-manual/current/indexes-for-vector-search/[Neo4j's Vector Search] got introduced in Neo4j 5.11 and was considered GA with the release of version 5.13. Embeddings can be stored on _Node_ properties and can be queried with the `db.index.vector.queryNodes()` function. Those indexes are powered by Lucene using a Hierarchical Navigable Small World Graph (HNSW) to perform a k approximate nearest neighbors (k-ANN) query over the vector fields.
|
||||
|
||||
=== Prerequisites
|
||||
|
||||
1. OpenAI Account: Create an account at link:https://platform.openai.com/signup[OpenAI Signup] and generate the token at link:https://platform.openai.com/account/api-keys[API Keys].
|
||||
|
||||
2. A running Neo4j (5.13+) instance
|
||||
a. link:https://hub.docker.com/_/neo4j[Docker] image _neo4j:5.13_
|
||||
b. link:https://neo4j.com/download/[Neo4j Desktop]
|
||||
c. link:https://neo4j.com/cloud/aura-free/[Neo4j Aura]
|
||||
d. link:https://neo4j.com/deployment-center/[Neo4j Server] instance
|
||||
|
||||
== Configuration
|
||||
|
||||
To connect to Neo4j and use the `Neo4jVectorStore`, you need to provide (e.g. via `application.properties`) configurations for your instance.
|
||||
|
||||
Additionally, you'll need to provide your OpenAI API Key. Set it as an environment variable like so:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
export SPRING_AI_OPENAI_API_KEY='Your_OpenAI_API_Key'
|
||||
----
|
||||
|
||||
== Repository
|
||||
|
||||
To acquire Spring AI artifacts, declare the Spring Snapshot repository:
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
----
|
||||
|
||||
== Dependencies
|
||||
|
||||
Add these dependencies to your project:
|
||||
|
||||
* OpenAI: Required for calculating embeddings.
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
* Neo4j Vector Store
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-neo4j-store</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
== Sample Code
|
||||
|
||||
To configure `Neo4jVectorStore` in your application, you can use the following setup:
|
||||
|
||||
Add to `application.properties` (using your Neo4j credentials):
|
||||
|
||||
@@ -1,53 +1,54 @@
|
||||
# PGvector Vector Store
|
||||
= PGvector
|
||||
|
||||
This readme walks you through setting up the PGvector `VectorStore` to store document embeddings and perform similarity searches.
|
||||
This section walks you through setting up the PGvector `VectorStore` to store document embeddings and perform similarity searches.
|
||||
|
||||
## What is PGvector?
|
||||
== What is PGvector?
|
||||
|
||||
[PGvector](https://github.com/pgvector/pgvector) is an open-source extension for PostgreSQL that enables storing and searching over machine learning-generated embeddings. It provides different capabilities that let users identify both exact and approximate nearest neighbors. It is designed to work seamlessly with other PostgreSQL features, including indexing and querying.
|
||||
link:https://github.com/pgvector/pgvector[PGvector] is an open-source extension for PostgreSQL that enables storing and searching over machine learning-generated embeddings. It provides different capabilities that let users identify both exact and approximate nearest neighbors. It is designed to work seamlessly with other PostgreSQL features, including indexing and querying.
|
||||
|
||||
## Prerequisites
|
||||
=== Prerequisites
|
||||
|
||||
1. OpenAI Account: Create an account at [OpenAI Signup](https://platform.openai.com/signup) and generate the token at [API Keys](https://platform.openai.com/account/api-keys).
|
||||
1. OpenAI Account: Create an account at link:https://platform.openai.com/signup[OpenAI Signup] and generate the token at link:https://platform.openai.com/account/api-keys[API Keys].
|
||||
|
||||
2. Access to PostgresSQL instance with following configurations
|
||||
2. Access to PostgreSQL instance with the following configurations
|
||||
|
||||
The [setup local Postgres/PGVector](#appendix_a) appendix shows how to setup a DB locally with a Docker container.
|
||||
The <<appendix_a,setup local Postgres/PGVector>> appendix shows how to set up a DB locally with a Docker container.
|
||||
|
||||
On startup the `PgVectorStore` will attempt to install the required database extensions and create the required `vector_store` table with index.
|
||||
Optionally, you can do this manually like so:
|
||||
On startup, the `PgVectorStore` will attempt to install the required database extensions and create the required `vector_store` table with an index. Optionally, you can do this manually like so:
|
||||
|
||||
(Optional)
|
||||
```sql
|
||||
CREATE EXTENSION IF NOT EXISTS vector
|
||||
CREATE EXTENSION IF NOT EXISTS hstore
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"
|
||||
[sql]
|
||||
----
|
||||
CREATE EXTENSION IF NOT EXISTS vector
|
||||
CREATE EXTENSION IF NOT EXISTS hstore
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"
|
||||
|
||||
CREATE TABLE IF NOT EXISTS vector_store (
|
||||
id uuid DEFAULT uuid_generate_v4 () PRIMARY KEY,
|
||||
content text,
|
||||
metadata json,
|
||||
embedding vector(1536)
|
||||
)
|
||||
CREATE TABLE IF NOT EXISTS vector_store (
|
||||
id uuid DEFAULT uuid_generate_v4() PRIMARY KEY,
|
||||
content text,
|
||||
metadata json,
|
||||
embedding vector(1536)
|
||||
)
|
||||
|
||||
CREATE INDEX ON vector_store USING HNSW (embedding vector_cosine_ops)
|
||||
```
|
||||
CREATE INDEX ON vector_store USING HNSW (embedding vector_cosine_ops)
|
||||
----
|
||||
|
||||
## Configuration
|
||||
== Configuration
|
||||
|
||||
To set up `PgVectorStore`, you need to provide (via `application.yaml`) configurations to your PostgresSQL database.
|
||||
To set up `PgVectorStore`, you need to provide (via `application.yaml`) configurations to your PostgreSQL database.
|
||||
|
||||
Additionally, you'll need to provide your OpenAI API Key. Set it as an environment variable like so:
|
||||
|
||||
```bash
|
||||
[source,bash]
|
||||
----
|
||||
export SPRING_AI_OPENAI_API_KEY='Your_OpenAI_API_Key'
|
||||
```
|
||||
----
|
||||
|
||||
## Repository
|
||||
== Repository
|
||||
|
||||
To acquire Spring AI artifacts, declare the Spring Snapshot repository:
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
@@ -56,15 +57,16 @@ To acquire Spring AI artifacts, declare the Spring Snapshot repository:
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
```
|
||||
----
|
||||
|
||||
## Dependencies
|
||||
== Dependencies
|
||||
|
||||
Add these dependencies to your project:
|
||||
|
||||
1. PostgresSQL connection and `JdbcTemplate` auto-configuration.
|
||||
* PostgreSQL connection and `JdbcTemplate` auto-configuration.
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
@@ -75,83 +77,91 @@ Add these dependencies to your project:
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
```
|
||||
----
|
||||
|
||||
2. OpenAI: Required for calculating embeddings.
|
||||
* OpenAI: Required for calculating embeddings.
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
----
|
||||
|
||||
3. PGvector
|
||||
* PGvector
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-pgvector-store</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
----
|
||||
|
||||
## Sample Code
|
||||
== Sample Code
|
||||
|
||||
To configure `PgVectorStore` in your application, you can use the following setup:
|
||||
|
||||
Add to `application.yml` (using your DB credentials):
|
||||
|
||||
```yml
|
||||
[yml]
|
||||
----
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:postgresql://localhost:5432/vector_store
|
||||
username: postgres
|
||||
password: postgres
|
||||
```
|
||||
datasource:
|
||||
url: jdbc:postgresql://localhost:5432/vector_store
|
||||
username: postgres
|
||||
password: postgres
|
||||
----
|
||||
|
||||
Integrate with OpenAI's embeddings by adding the Spring Boot OpenAI Starter to your project.
|
||||
This provides you with an implementation of the Embeddings client:
|
||||
Integrate with OpenAI's embeddings by adding the Spring Boot OpenAI Starter to your project. This provides you with an implementation of the Embeddings client:
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public VectorStore vectorStore(JdbcTemplate jdbcTemplate, EmbeddingClient embeddingClient) {
|
||||
return new PgVectorStore(jdbcTemplate, embeddingClient);
|
||||
}
|
||||
```
|
||||
----
|
||||
|
||||
In your main code, create some documents:
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
List<Document> documents = List.of(
|
||||
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("meta1", "meta1")),
|
||||
new Document("The World is Big and Salvation Lurks Around the Corner"),
|
||||
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("meta2", "meta2")));
|
||||
```
|
||||
----
|
||||
|
||||
Add the documents to your vector store:
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
vectorStore.add(List.of(document));
|
||||
```
|
||||
----
|
||||
|
||||
And finally, retrieve documents similar to a query:
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
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!!".
|
||||
|
||||
## <a name="appendix_a" /> Appendix A: Run Postgres & PGVector DB locally
|
||||
== Run Postgres & PGVector DB locally
|
||||
|
||||
```
|
||||
----
|
||||
docker run -it --rm --name postgres -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres ankane/pgvector
|
||||
```
|
||||
----
|
||||
|
||||
You can connect to this server like this:
|
||||
|
||||
```
|
||||
----
|
||||
psql -U postgres -h localhost -p 5432
|
||||
```
|
||||
----
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# Pinecone Vector Store
|
||||
= Pinecone
|
||||
|
||||
This readme walks you through setting up the Pinecone `VectorStore` to store document embeddings and perform similarity searches.
|
||||
This section walks you through setting up the Pinecone `VectorStore` to store document embeddings and perform similarity searches.
|
||||
|
||||
## What is Pinecone?
|
||||
== What is Pinecone?
|
||||
|
||||
[Pinecone](https://www.pinecone.io/) is a popular cloud-based vector database, which allows you to store and search vectors efficiently.
|
||||
link:https://www.pinecone.io/[Pinecone] is a popular cloud-based vector database, which allows you to store and search vectors efficiently.
|
||||
|
||||
## Prerequisites
|
||||
== Prerequisites
|
||||
|
||||
1. Pinecone Account: Before you start, sign up for a [Pinecone account](https://app.pinecone.io/).
|
||||
1. Pinecone Account: Before you start, sign up for a link:https://app.pinecone.io/[Pinecone account].
|
||||
2. Pinecone Project: Once registered, create a new project, an index, and generate an API key. You'll need these details for configuration.
|
||||
3. OpenAI Account: Create an account at [OpenAI Signup](https://platform.openai.com/signup) and generate the token at [API Keys](https://platform.openai.com/account/api-keys)
|
||||
3. OpenAI Account: Create an account at link:https://platform.openai.com/signup[OpenAI Signup] and generate the token at link:https://platform.openai.com/account/api-keys[API Keys].
|
||||
|
||||
## Configuration
|
||||
== Configuration
|
||||
|
||||
To set up `PineconeVectorStore`, gather the following details from your Pinecone account:
|
||||
|
||||
@@ -22,23 +22,26 @@ To set up `PineconeVectorStore`, gather the following details from your Pinecone
|
||||
* Pinecone Index Name
|
||||
* Pinecone Namespace
|
||||
|
||||
> **Note**
|
||||
> This information is available to you in the Pinecone UI portal.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
This information is available to you in the Pinecone UI portal.
|
||||
====
|
||||
|
||||
When setting up embeddings, select a vector dimension of `1536`. This matches the dimensionality of OpenAI's model `text-embedding-ada-002`, which we'll be using for this guide.
|
||||
|
||||
Additionally, you'll need to provide your OpenAI API Key. Set it as an environment variable like so:
|
||||
|
||||
```bash
|
||||
[source,bash]
|
||||
----
|
||||
export SPRING_AI_OPENAI_API_KEY='Your_OpenAI_API_Key'
|
||||
```
|
||||
----
|
||||
|
||||
## Repository
|
||||
== Repository
|
||||
|
||||
To acquire Spring AI artifacts, declare the Spring Snapshot repository:
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
@@ -47,37 +50,40 @@ To acquire Spring AI artifacts, declare the Spring Snapshot repository:
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
```
|
||||
----
|
||||
|
||||
## Dependencies
|
||||
== Dependencies
|
||||
|
||||
Add these dependencies to your project:
|
||||
|
||||
1. OpenAI: Required for calculating embeddings.
|
||||
* OpenAI: Required for calculating embeddings.
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
----
|
||||
|
||||
2. Pinecone
|
||||
* Pinecone
|
||||
|
||||
```xml
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-pinecone</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
----
|
||||
|
||||
## Sample Code
|
||||
== Sample Code
|
||||
|
||||
To configure Pinecone in your application, you can use the following setup:
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public PineconeVectorStoreConfig pineconeVectorStoreConfig() {
|
||||
|
||||
@@ -89,37 +95,41 @@ public PineconeVectorStoreConfig pineconeVectorStoreConfig() {
|
||||
.withNamespace("") // the free tier doesn't support namespaces.
|
||||
.build();
|
||||
}
|
||||
```
|
||||
----
|
||||
|
||||
Integrate with OpenAI's embeddings by adding the Spring Boot OpenAI starter to your project.
|
||||
This provides you with an implementation of the Embeddings client:
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public VectorStore vectorStore(PineconeVectorStoreConfig config, EmbeddingClient embeddingClient) {
|
||||
return new PineconeVectorStore(config, embeddingClient);
|
||||
}
|
||||
```
|
||||
----
|
||||
|
||||
In your main code, create some documents:
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
List<Document> documents = List.of(
|
||||
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("meta1", "meta1")),
|
||||
new Document("The World is Big and Salvation Lurks Around the Corner"),
|
||||
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("meta2", "meta2")));
|
||||
```
|
||||
----
|
||||
|
||||
Add the documents to Pinecone:
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
vectorStore.add(List.of(document));
|
||||
```
|
||||
----
|
||||
|
||||
And finally, retrieve documents similar to a query:
|
||||
|
||||
```java
|
||||
[source,java]
|
||||
----
|
||||
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!!".
|
||||
@@ -0,0 +1,207 @@
|
||||
= Weaviate
|
||||
|
||||
This section will walk you through setting up the Weaviate VectorStore to store document embeddings and perform similarity searches.
|
||||
|
||||
== What is Weaviate?
|
||||
|
||||
link:https://weaviate.io/[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 provides 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 ONNX Transformers Embedding instructions.
|
||||
- `OpenAI Embedding` - uses the OpenAI embedding endpoint. You need to create an account at link:https://platform.openai.com/signup[OpenAI Signup] and generate the api-key token at link:https://platform.openai.com/account/api-keys[API Keys].
|
||||
- You can also use the `Azure OpenAI Embedding` or the `PostgresML Embedding Client`.
|
||||
2. `Weaviate cluster`. You can set up a cluster locally in a Docker container or create a link:https://console.weaviate.cloud/[Weaviate Cloud Service]. For the latter, you need to create a Weaviate account, set up a cluster, and get your access API key from the link:https://console.weaviate.cloud/dashboard[dashboard details].
|
||||
|
||||
On startup, the `WeaviateVectorStore` creates the required `SpringAiWeaviate` object schema if it's not already provisioned.
|
||||
|
||||
== Dependencies
|
||||
|
||||
Add these dependencies to your project:
|
||||
|
||||
* Embedding Client boot starter, required for calculating embeddings.
|
||||
|
||||
* Transformers Embedding (Local) and follow the ONNX Transformers Embedding instructions.
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-transformers-embedding-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
or use OpenAI (Cloud)
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<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:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
export SPRING_AI_OPENAI_API_KEY='Your_OpenAI_API_Key'
|
||||
----
|
||||
|
||||
* Add the Weaviate VectorStore dependency
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<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 the local Weaviate cluster:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@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 are expanded with new entries, you have to (re)upload/update the documents with this metadata.
|
||||
>
|
||||
> You can use the following Weaviate link:https://weaviate.io/developers/weaviate/api/graphql/filters#special-cases[system metadata] fields without explicit definition: `id`, `_creationTimeUnix`, and `_lastUpdateTimeUnix`.
|
||||
|
||||
Then in your main code, create some documents:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
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)));
|
||||
----
|
||||
|
||||
Now add the documents to your vector store:
|
||||
|
||||
|
||||
[source,java]
|
||||
----
|
||||
vectorStore.add(List.of(document));
|
||||
----
|
||||
|
||||
And finally, retrieve documents similar to a query:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
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 link:https://docs.spring.io/spring-ai/reference/api/vectordbs.html#_metadata_filters[metadata filters] with WeaviateVectorStore as well.
|
||||
|
||||
For example, you can use either the text expression language:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
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:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
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 link:https://weaviate.io/developers/weaviate/api/graphql/filters[where filters].
|
||||
For example, the following portable filter expression:
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
country in ['UK', 'NL'] && year >= 2020
|
||||
----
|
||||
|
||||
is converted into Weaviate GraphQL link:https://weaviate.io/developers/weaviate/api/graphql/filters[where filter expression]:
|
||||
|
||||
[source,graphql]
|
||||
----
|
||||
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
|
||||
}]
|
||||
----
|
||||
|
||||
== Run Weaviate cluster in docker container
|
||||
|
||||
Start Weaviate in a docker container:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
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.
|
||||
@@ -93,6 +93,21 @@ The "'rendered'" string becomes the content of the prompt supplied to the AI mod
|
||||
There is considerable variability in the specific data format of the prompt sent to the model.
|
||||
Initially starting as simple strings, prompts have evolved to include multiple messages, where each string in each message represents a distinct role for the model.
|
||||
|
||||
== Embeddings
|
||||
|
||||
Embeddings transform text into numerical arrays or vectors, enabling AI models to process and interpret language data.
|
||||
This transformation from text to numbers and back is a key element in how AI interacts with and understands human language.
|
||||
As a Java developer exploring AI, it's not necessary to comprehend the intricate mathematical theories or the specific implementations behind these vector representations.
|
||||
A basic understanding of their role and function within AI systems suffices, particularly when you're integrating AI functionalities into your applications.
|
||||
|
||||
Embeddings are particularly relevant in practical applications like the retrieval-augmented generation pattern.
|
||||
They enable the representation of data as points in a semantic space, which is akin to the 2-D space of Euclidean geometry, but in higher dimensions.
|
||||
This means just like how points on a plane in Euclidean geometry can be close or far based on their coordinates, in a semantic space, the proximity of points reflects the similarity in meaning.
|
||||
So, sentences about similar topics are positioned closer in this multi-dimensional space, much like points lying close to each other on a graph.
|
||||
This proximity aids in tasks like text classification, semantic search, and even product recommendations, as it allows the AI to discern and group related concepts based on their 'location' in this expanded semantic landscape.
|
||||
|
||||
You can think of this semantic space as a vector,
|
||||
|
||||
== Tokens
|
||||
|
||||
Tokens serve as the building blocks of how an AI model works.
|
||||
@@ -125,13 +140,6 @@ Output parsing employs meticulously crafted prompts, often necessitating multipl
|
||||
|
||||
This challenge has prompted OpenAI to introduce 'OpenAI Functions' as a means to specify the desired output format from the model precisely.
|
||||
|
||||
== Chaining Calls
|
||||
|
||||
A chain is a concept that represents a series of calls to an AI model.
|
||||
It uses the output from one call as the input to another.
|
||||
|
||||
By chaining calls together, you can support complex use cases by composing pipelines of multiple chains.
|
||||
|
||||
== Bringing Your Data to the AI model
|
||||
|
||||
How can you equip the AI model with information on which it has not been trained?
|
||||
|
||||
@@ -1,304 +0,0 @@
|
||||
# Azure AI Search VectorStore
|
||||
|
||||
This README will walk you through setting up the `AzureVectorStore`` to store document embeddings and perform similarity searches using the Azure AI Search Service.
|
||||
|
||||
[Azure AI Search](https://azure.microsoft.com/en-us/products/ai-services/cognitive-search) is a versatile cloud hosted cloud information retrieval system that is part of Microsoft's larger AI platform.
|
||||
Among other features, it allows users to query information using vector based storage and retrieval.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Azure Subscription: You will need an [Azure subscription](https://azure.microsoft.com/en-us/free/) to use any Azure service.
|
||||
2. Azure AI Search Service: Create an [AI Search service](https://portal.azure.com/#create/Microsoft.Search). Once the service is created,
|
||||
obtain the admin apiKey from the `Keys` section under `Settings` and retrieve the endpoint from the `Url` field under the `Overview` section.
|
||||
3. (Optional) Azure OpenAI Service: Create an an Azure [OpenAI service](https://portal.azure.com/#create/Microsoft.AIServicesOpenAI).
|
||||
**NOTE:** You may have to fill out a separate form to gain access to Azure Open AI services.
|
||||
Once the service is created, obtain the endpoint and apiKey from the `Keys and Endpoint` section under `Resource Management`
|
||||
|
||||
## Configuration
|
||||
|
||||
On startup the `AzureVectorStore` will attempt to create a new index within your AI Search service instance.
|
||||
Alternatively you create the index, manually as explained in [Appendix A](appendix_a).
|
||||
|
||||
To set up an AzureVectorStore, you will need the settings retrieved from the prerequisites above along with your index name:
|
||||
|
||||
* Azure AI Search Endpoint
|
||||
* Azure AI Search Key
|
||||
* (optional) Azure OpenAI API Endpoint
|
||||
* (optional) Azure OpenAI API Key
|
||||
|
||||
You can provide these values as OS environment variables.
|
||||
|
||||
```bash
|
||||
export 'AZURE_AI_SEARCH_API_KEY=<My AI Search API Key>'
|
||||
export 'AZURE_AI_SEARCH_ENDPOINT=<My AI Search Index>'
|
||||
export 'OPENAI_API_KEY=<My Azure AI API Key>' (Optional)
|
||||
```
|
||||
|
||||
**NOTE** You can replace Azure Open AI implementation with any valid OpenAI implementation that supports the Embeddings interface. For example, you could use Spring AIs Open AI or TransformersEmbedding implementations for embeddings instead of the Azure implementation.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Add these dependencies to your project:
|
||||
|
||||
1. Select an Embeddings interface implementation.
|
||||
You can choose between:
|
||||
|
||||
* or OpenAI Embedding:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
* Or Azure AI Embedding:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
* Or Local Sentence Transformers Embedding:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-transformers-embedding-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
2. Azure (AI Search) Vector Store
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-azure-vector-store</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Sample Code
|
||||
|
||||
To configure an Azure `SearchIndexClient` in your application, you can use the following code:
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public SearchIndexClient searchIndexClient() {
|
||||
return new SearchIndexClientBuilder().endpoint(System.getenv("AZURE_AI_SEARCH_ENDPOINT"))
|
||||
.credential(new AzureKeyCredential(System.getenv("AZURE_AI_SEARCH_API_KEY")))
|
||||
.buildClient();
|
||||
}
|
||||
```
|
||||
|
||||
To create a vector store, you can use the following code by injecting the `SearchIndexClient` bean created in the above sample along with and `EmbeddingClient` provided by Spring AI library that's implements the desired Embeddings interface.
|
||||
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public VectorStore vectorStore(SearchIndexClient searchIndexClient, EmbeddingClient embeddingClient) {
|
||||
return new AzureVectorStore(searchIndexClient, embeddingClient,
|
||||
// Define the metadata fields to be used
|
||||
// in the similarity search filters.
|
||||
List.of(MetadataField.text("country"),
|
||||
MetadataField.int64("year"),
|
||||
MetadataField.bool("active")));
|
||||
}
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> You must list explicitly all metadata field names and types for any metadata key used in filter expression.
|
||||
>The list above registers filterable metadata fields: `country` of type `TEXT`, `year` of type `INT64` 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.
|
||||
|
||||
In your main code, create some documents
|
||||
|
||||
```java
|
||||
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", "BG", "year", 2020)),
|
||||
new Document("The World is Big and Salvation Lurks Around the Corner"),
|
||||
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("country", "NL", "year", 2023)));
|
||||
```
|
||||
|
||||
Add the documents to your vector store:
|
||||
|
||||
```java
|
||||
vectorStore.add(List.of(document));
|
||||
```
|
||||
|
||||
And finally, retrieve documents similar to a query:
|
||||
|
||||
```java
|
||||
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](https://docs.spring.io/spring-ai/reference/api/vectordbs.html#_metadata_filters) with AzureVectorStore as well.
|
||||
|
||||
For example you can use either the text expression language:
|
||||
|
||||
```java
|
||||
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:
|
||||
|
||||
```java
|
||||
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 Azure Search [OData filters](https://learn.microsoft.com/en-us/azure/search/search-query-odata-filter).
|
||||
For example the following, portable, filter expression
|
||||
|
||||
```sql
|
||||
country in ['UK', 'NL'] && year >= 2020
|
||||
```
|
||||
|
||||
is converted into Azure, OData, [filter expression](https://learn.microsoft.com/en-us/azure/search/search-query-odata-filter):
|
||||
|
||||
```graphQL
|
||||
$filter search.in(meta_country, 'UK,NL', ',') and meta_year ge 2020
|
||||
```
|
||||
|
||||
## Integration With Azure OpenAI Studio Data Ingestion
|
||||
|
||||
Azure Open AI services provides a convenient method to upload documents into an Index as described in this Microsoft
|
||||
[learning document](https://learn.microsoft.com/en-us/azure/ai-services/openai/use-your-data-quickstart?tabs=command-line&pivots=programming-language-csharp).
|
||||
The `AzureVectorStore` implementation is compatible with indexes that use this methodology facilitating an *easier* way to integrate with your existing documents for the purpose of searching and integrating with the AI system.
|
||||
|
||||
## <a name="appendix_a" /> Appendix A: Create Vector Store Search Index </a>
|
||||
|
||||
The easiest way to crate a search index manually, is to create one from a JSON document.
|
||||
This can be done by clicking on the `Indexes` link under the `Search management` section.
|
||||
From the Indexes page, click `+ Add index` and select `Add index (JSON)`. In the
|
||||
`Add index (JSON)` window of the right side of your screen, enter the following JSON replacing `<INDEX NAME>` with the name you would like to give your index and click
|
||||
`save`.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "<INDEX NAME>",
|
||||
"defaultScoringProfile": null,
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
"type": "Edm.String",
|
||||
"searchable": false,
|
||||
"filterable": false,
|
||||
"retrievable": true,
|
||||
"sortable": false,
|
||||
"facetable": false,
|
||||
"key": true,
|
||||
"indexAnalyzer": null,
|
||||
"searchAnalyzer": null,
|
||||
"analyzer": null,
|
||||
"normalizer": null,
|
||||
"dimensions": null,
|
||||
"vectorSearchConfiguration": null,
|
||||
"synonymMaps": []
|
||||
},
|
||||
{
|
||||
"name": "embedding",
|
||||
"type": "Collection(Edm.Single)",
|
||||
"searchable": true,
|
||||
"filterable": false,
|
||||
"retrievable": true,
|
||||
"sortable": false,
|
||||
"facetable": false,
|
||||
"key": false,
|
||||
"indexAnalyzer": null,
|
||||
"searchAnalyzer": null,
|
||||
"analyzer": null,
|
||||
"normalizer": null,
|
||||
"dimensions": 1536, // set the dimensions for the configured Embedding Client. It defaults to to OpenAI's 1536 size.
|
||||
"vectorSearchConfiguration": "default",
|
||||
"synonymMaps": []
|
||||
},
|
||||
{
|
||||
"name": "content",
|
||||
"type": "Edm.String",
|
||||
"searchable": true,
|
||||
"filterable": false,
|
||||
"retrievable": true,
|
||||
"sortable": false,
|
||||
"facetable": false,
|
||||
"key": false,
|
||||
"indexAnalyzer": null,
|
||||
"searchAnalyzer": null,
|
||||
"analyzer": null,
|
||||
"normalizer": null,
|
||||
"dimensions": null,
|
||||
"vectorSearchConfiguration": null,
|
||||
"synonymMaps": []
|
||||
},
|
||||
{
|
||||
"name": "metadata",
|
||||
"type": "Edm.String",
|
||||
"searchable": true,
|
||||
"filterable": true,
|
||||
"retrievable": true,
|
||||
"sortable": true,
|
||||
"facetable": true,
|
||||
"key": false,
|
||||
"indexAnalyzer": null,
|
||||
"searchAnalyzer": null,
|
||||
"analyzer": null,
|
||||
"normalizer": null,
|
||||
"dimensions": null,
|
||||
"vectorSearchConfiguration": null,
|
||||
"synonymMaps": []
|
||||
}
|
||||
],
|
||||
"scoringProfiles": [],
|
||||
"corsOptions": null,
|
||||
"suggesters": [],
|
||||
"analyzers": [],
|
||||
"normalizers": [],
|
||||
"tokenizers": [],
|
||||
"tokenFilters": [],
|
||||
"charFilters": [],
|
||||
"encryptionKey": null,
|
||||
"semantic": null,
|
||||
"vectorSearch": {
|
||||
"algorithmConfigurations": [
|
||||
{
|
||||
"name": "default",
|
||||
"kind": "hnsw",
|
||||
"hnswParameters": {
|
||||
"metric": "cosine",
|
||||
"m": 4,
|
||||
"efConstruction": 400,
|
||||
"efSearch": 1000
|
||||
},
|
||||
"exhaustiveKnnParameters": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
@@ -1,154 +0,0 @@
|
||||
# Chroma VectorStore
|
||||
|
||||
This readme will walk you through setting up the Chroma VectorStore to store document embeddings and perform similarity searches.
|
||||
|
||||
<https://github.com/chroma-core/chroma/pkgs/container/chroma>
|
||||
|
||||
## What is Chroma?
|
||||
|
||||
[Chroma](https://docs.trychroma.com/) is the open-source embedding database. It gives you the tools to store document embeddings, content and metadata and to search through those embeddings including metadata filtering.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. OpenAI Account: Create an account at [OpenAI Signup](https://platform.openai.com/signup) and generate the token at [API Keys](https://platform.openai.com/account/api-keys).
|
||||
|
||||
2. Access to ChromeDB. The [setup local ChromaDB](#appendix_a) appendix show how to setup a DB locally with a Docker container.
|
||||
|
||||
On startup the `ChromaVectorStore` creates the required collection if one is not provisioned already.
|
||||
|
||||
## Configuration
|
||||
|
||||
To set up ChromaVectorStore, you'll need to provide your OpenAI API Key. Set it as an environment variable like so:
|
||||
|
||||
```bash
|
||||
export SPRING_AI_OPENAI_API_KEY='Your_OpenAI_API_Key'
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
Add these dependencies to your project:
|
||||
|
||||
1. OpenAI: Required for calculating embeddings.
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||||
<version>0.7.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
2. Chroma VectorStore.
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-chroma-store</artifactId>
|
||||
<version>0.7.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Sample Code
|
||||
|
||||
Create an `RestTemplate` instance with proper ChromaDB authorization configurations and Use it to create `ChromaApi` instance:
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ChromaApi chromaApi(RestTemplate restTemplate) {
|
||||
String chromaUrl = "http://localhost:8000";
|
||||
ChromaApi chromaApi = ChromaApi(chromaUrl, restTemplate);
|
||||
return chromaApi;
|
||||
}
|
||||
```
|
||||
> [!NOTE]
|
||||
> For ChromaDB secured with [Static API Token Authentication](https://docs.trychroma.com/usage-guide#static-api-token-authentication) use the `ChromaApi#withKeyToken(<Your Token Credentials>)` method to set your credentials. Check the `ChromaWhereIT` for an example.
|
||||
|
||||
> [!NOTE]
|
||||
> For ChromaDB secured with [Basic Authentication](https://docs.trychroma.com/usage-guide#basic-authentication) use the `ChromaApi#withBasicAuth(<your user>, <your password>)` method to set your credentials. Check the `BasicAuthChromaWhereIT` for an example.
|
||||
|
||||
|
||||
Integrate with OpenAI's embeddings by adding the Spring Boot OpenAI starter to your project.
|
||||
This provides you with an implementation of the Embeddings client:
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public VectorStore chromaVectorStore(EmbeddingClient embeddingClient, ChromaApi chromaApi) {
|
||||
return new ChromaVectorStore(embeddingClient, chromaApi, "TestCollection");
|
||||
}
|
||||
```
|
||||
|
||||
In your main code, create some documents
|
||||
|
||||
```java
|
||||
List<Document> documents = List.of(
|
||||
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("meta1", "meta1")),
|
||||
new Document("The World is Big and Salvation Lurks Around the Corner"),
|
||||
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("meta2", "meta2")));
|
||||
```
|
||||
|
||||
Add the documents to your vector store:
|
||||
|
||||
```java
|
||||
vectorStore.add(List.of(document));
|
||||
```
|
||||
|
||||
And finally, retrieve documents similar to a query:
|
||||
|
||||
```java
|
||||
List<Document> results = vectorStore.similaritySearch("Spring", 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](https://docs.spring.io/spring-ai/reference/api/vectordbs.html#_metadata_filters) with ChromaVector store as well.
|
||||
|
||||
For example you can use either the text expression language:
|
||||
|
||||
```java
|
||||
vectorStore.similaritySearch("The World", TOP_K, SIMILARITY_THRESHOLD,
|
||||
"author in ['john', 'jill'] && article_type == 'blog'");
|
||||
```
|
||||
|
||||
or programmatically using the `Filter.Expression` DSL:
|
||||
|
||||
```java
|
||||
FilterExpressionBuilder b = new FilterExpressionBuilder();
|
||||
|
||||
vectorStore.similaritySearch("The World", TOP_K, SIMILARITY_THRESHOLD,
|
||||
b.and(
|
||||
b.in(List.of("john", "jill")),
|
||||
b.eq("article_type", "blog")).build());
|
||||
```
|
||||
|
||||
NOTE: Those (portable) filter expressions get automatically converted into the proprietary Chroma `where` [filter expressions](https://docs.trychroma.com/usage-guide#using-where-filters).
|
||||
|
||||
For example this portable filter expression:
|
||||
|
||||
```sql
|
||||
author in ['john', 'jill'] && article_type == 'blog'
|
||||
```
|
||||
|
||||
is converted into the proprietary Chroma format:
|
||||
|
||||
```json
|
||||
{"$and":[
|
||||
{"author": {"$in": ["john", "jill"]}},
|
||||
{"article_type":{"$eq":"blog"}}]
|
||||
}"
|
||||
```
|
||||
|
||||
|
||||
## <a name="appendix_a" /> Appendix A: Run Chroma Locally
|
||||
|
||||
```
|
||||
docker run -it --rm --name chroma -p 8000:8000 ghcr.io/chroma-core/chroma:0.4.15
|
||||
```
|
||||
|
||||
starts a chroma store at <http://localhost:8000/api/v1>
|
||||
@@ -1,35 +0,0 @@
|
||||
# Introduction to Milvus
|
||||
|
||||
[Milvus](https://milvus.io/) is an open-source vector database that has garnered significant attention in the fields of data science and machine learning.
|
||||
One of its standout features lies in its robust support for vector indexing and querying.
|
||||
Milvus employs state-of-the-art, cutting-edge algorithms to accelerate the search process, making it exceptionally efficient at retrieving similar vectors, even when handling extensive datasets.
|
||||
|
||||
Milvus's popularity also comes from its ease of integration with popular Python based frameworks such as PyTorch and TensorFlow, allowing for seamless inclusion in existing machine learning workflows.
|
||||
|
||||
In the e-commerce industry, Milvus is used in recommendation systems, which suggest products based on user preferences.
|
||||
In image and video analysis, it excels in tasks like object recognition, image similarity search, and content-based image retrieval.
|
||||
Additionally, it is commonly used in natural language processing for document clustering, semantic search, and question-answering systems.
|
||||
|
||||
## Starting Milvus Store
|
||||
|
||||
From within the `src/test/resources/` folder run:
|
||||
|
||||
```
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
To clean the environment:
|
||||
|
||||
```
|
||||
docker-compose down; rm -Rf ./volumes
|
||||
```
|
||||
|
||||
Then connect to the vector store on http://localhost:19530 or for management http://localhost:9001 (user: `minioadmin`, pass: `minioadmin`)
|
||||
|
||||
## Throubleshooting
|
||||
|
||||
If Docker complains about resources, then execute:
|
||||
|
||||
```
|
||||
docker system prune --all --force --volumes
|
||||
```
|
||||
@@ -1,141 +0,0 @@
|
||||
# Neo4j Store
|
||||
|
||||
This readme walks you through setting up `Neo4jVectorStore` to store document embeddings and perform similarity searches.
|
||||
|
||||
## What is Neo4j?
|
||||
|
||||
[Neo4j](https://neo4j.com) is an open source NoSQL graph database.
|
||||
It is a fully transactional database (ACID) that stores data structured as graphs consisting of nodes, connected by relationships.
|
||||
Inspired by the structure of the real world, it allows for high query performance on complex data, while remaining intuitive and simple for the developer.
|
||||
|
||||
## What is Neo4j Vector Search?
|
||||
|
||||
[Neo4j's Vector Search](https://neo4j.com/docs/cypher-manual/current/indexes-for-vector-search/) got introduced in Neo4j 5.11 and was considered GA with the release of version 5.13.
|
||||
Embeddings can be stored on _Node_ properties and can be queried with the [`db.index.vector.queryNodes()`](https://neo4j.com/docs/operations-manual/5/reference/procedures/#procedure_db_index_vector_queryNodes) function.
|
||||
Those indexes are powered by Lucene using a Hierarchical Navigable Small World Graph (HNSW) to perform a k approximate nearest neighbors (k-ANN) query over the vector fields.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. OpenAI Account: Create an account at [OpenAI Signup](https://platform.openai.com/signup) and generate the token at [API Keys](https://platform.openai.com/account/api-keys).
|
||||
|
||||
2. A running Neo4j (5.13+) instance
|
||||
1. [Docker](https://hub.docker.com/_/neo4j) image _neo4j:5.13_
|
||||
2. [Neo4j Desktop](https://neo4j.com/download/)
|
||||
3. [Neo4j Aura](https://neo4j.com/cloud/aura-free/)
|
||||
4. [Neo4j Server](https://neo4j.com/deployment-center/) instance
|
||||
|
||||
## Configuration
|
||||
|
||||
To connect to Neo4j and use the `Neo4jVectorStore`, you need to provide (e.g. via `application.properties`) configurations for your instance.
|
||||
|
||||
Additionally, you'll need to provide your OpenAI API Key. Set it as an environment variable like so:
|
||||
|
||||
```bash
|
||||
export SPRING_AI_OPENAI_API_KEY='Your_OpenAI_API_Key'
|
||||
```
|
||||
|
||||
## Repository
|
||||
|
||||
To acquire Spring AI artifacts, declare the Spring Snapshot repository:
|
||||
|
||||
```xml
|
||||
<repository>
|
||||
<id>spring-snapshots</id>
|
||||
<name>Spring Snapshots</name>
|
||||
<url>https://repo.spring.io/snapshot</url>
|
||||
<releases>
|
||||
<enabled>false</enabled>
|
||||
</releases>
|
||||
</repository>
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
Add these dependencies to your project:
|
||||
|
||||
1. OpenAI: Required for calculating embeddings.
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
2. Neo4j Vector Store
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-neo4j-store</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Sample Code
|
||||
|
||||
To configure `Neo4jVectorStore` in your application, you can use the following setup:
|
||||
|
||||
Add to `application.properties` (using your Neo4j credentials):
|
||||
|
||||
```
|
||||
spring.neo4j.uri=neo4j://localhost:7687
|
||||
spring.neo4j.authentication.username=neo4j
|
||||
spring.neo4j.authentication.password=password
|
||||
```
|
||||
|
||||
Integrate with OpenAI's embeddings by adding the Spring Boot OpenAI Starter to your project.
|
||||
This provides you with an implementation of the Embeddings client:
|
||||
|
||||
```java
|
||||
public VectorStore vectorStore(Driver driver, EmbeddingClient embeddingClient) {
|
||||
return new Neo4jVectorStore(driver, embeddingClient,
|
||||
Neo4jVectorStore.Neo4jVectorStoreConfig.defaultConfig());
|
||||
}
|
||||
```
|
||||
|
||||
In your main code, create some documents:
|
||||
|
||||
```java
|
||||
List<Document> documents = List.of(
|
||||
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("meta1", "meta1")),
|
||||
new Document("The World is Big and Salvation Lurks Around the Corner"),
|
||||
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("meta2", "meta2")));
|
||||
```
|
||||
|
||||
Add the documents to your vector store:
|
||||
|
||||
```java
|
||||
vectorStore.add(List.of(document));
|
||||
```
|
||||
|
||||
And finally, retrieve documents similar to a query:
|
||||
|
||||
```java
|
||||
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!!" as the first result.
|
||||
|
||||
## Neo4jVectorStore config
|
||||
|
||||
As you have already noticed, the `Neo4jVectorStore` accepts a configuration parameter.
|
||||
The default configuration should fit for most of the basic use-cases, but if you want to tweak it a little bit for you needs, you can edit those defaults.
|
||||
|
||||
The default params
|
||||
* embedding dimension = 1536
|
||||
* distance type = cosine
|
||||
* document node label = "Document"
|
||||
* node property for embedding = "embedding"
|
||||
* database name = "neo4j"
|
||||
|
||||
can be configured with
|
||||
|
||||
```java
|
||||
Neo4jVectorStore.Neo4jVectorStoreConfig.builder()
|
||||
.withDatabaseName("databaseName")
|
||||
.withDistanceType(Neo4jVectorStore.Neo4jDistanceType.COSINE / Neo4jVectorStore.Neo4jDistanceType.EUCLIDEAN)
|
||||
.withLabel("CustomLabel")
|
||||
.withEmbeddingProperty("vectorEmbedding")
|
||||
.withEmbeddingDimension(1024)
|
||||
```
|
||||
@@ -1,196 +0,0 @@
|
||||
# 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](https://weaviate.io/) 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](../../embedding-clients/transformers-embedding/) instructions.
|
||||
- `OpenAI Embedding` - uses the OpenAI embedding endpoint. You need to create an account at [OpenAI Signup](https://platform.openai.com/signup) and generate the api-key token at [API Keys](https://platform.openai.com/account/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](#appendix_a)) or create a [Weaviate Cloud Service](https://console.weaviate.cloud/). For later you need to create an weaviate account spin a cluster and get your access api-key from the [dashboard details](https://console.weaviate.cloud/dashboard).
|
||||
|
||||
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)
|
||||
|
||||
```xml
|
||||
<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](../../embedding-clients/transformers-embedding/README.md) instructions.
|
||||
|
||||
- or OpenAI (Cloud)
|
||||
|
||||
```xml
|
||||
<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:
|
||||
|
||||
```bash
|
||||
export SPRING_AI_OPENAI_API_KEY='Your_OpenAI_API_Key'
|
||||
```
|
||||
|
||||
2. Weaviate VectorStore.
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.experimental.ai</groupId>
|
||||
<artifactId>spring-ai-weaviate-store</artifactId>
|
||||
<version>0.7.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## <a name="usage"/> Usage </a>
|
||||
|
||||
Create a WeaviateVectorStore instance connected to local Weaviate cluster:
|
||||
|
||||
```java
|
||||
@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](https://weaviate.io/developers/weaviate/api/graphql/filters#special-cases) fields without explicit definition: `id`, `_creationTimeUnix` and `_lastUpdateTimeUnix`.
|
||||
|
||||
Then yn your main code, create some documents
|
||||
|
||||
```java
|
||||
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:
|
||||
|
||||
```java
|
||||
vectorStore.add(List.of(document));
|
||||
```
|
||||
|
||||
And finally, retrieve documents similar to a query:
|
||||
|
||||
```java
|
||||
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](https://docs.spring.io/spring-ai/reference/api/vectordbs.html#_metadata_filters) with WeaviateVectorStore as well.
|
||||
|
||||
For example you can use either the text expression language:
|
||||
|
||||
```java
|
||||
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:
|
||||
|
||||
```java
|
||||
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](https://weaviate.io/developers/weaviate/api/graphql/filters).
|
||||
For example the following, portable, filter expression
|
||||
|
||||
```sql
|
||||
country in ['UK', 'NL'] && year >= 2020
|
||||
```
|
||||
|
||||
is converted into Weaviate, GraphQL, [where filter expression](https://weaviate.io/developers/weaviate/api/graphql/filters):
|
||||
|
||||
```graphQL
|
||||
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
|
||||
}]
|
||||
```
|
||||
|
||||
## <a name="appendix_a"/> Appendix A: Run Weaviate cluster in docker container </a>
|
||||
|
||||
Start Weaviate in a docker container:
|
||||
|
||||
```bash
|
||||
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](#usage).
|
||||
Reference in New Issue
Block a user