Skip to main content

Valkey

https://valkey.io/

Maven Dependency​

You can use Valkey with LangChain4j in plain Java or Spring Boot applications.

Plain Java​

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-valkey</artifactId>
<version>${latest version here}</version>
</dependency>

Spring Boot​

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-valkey-spring-boot-starter</artifactId>
<version>${latest version here}</version>
</dependency>

Or, you can use BOM to manage dependencies consistently:

<dependencyManagement>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-bom</artifactId>
<version>${latest version here}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>

Overview​

The langchain4j-community-valkey module provides integration with Valkey as an embedding store using Valkey's built-in vector search capabilities (Valkey 8+).

It uses the official valkey-glide client to connect to the Valkey server. Embeddings, text, and metadata are stored as structured JSON documents with HNSW indexing for sub-millisecond similarity search.

Prerequisites​

Requires Valkey 9.1+. The valkey-bundle image includes the JSON and Search modules needed for vector indexing.

docker run -d --name valkey -p 6379:6379 valkey/valkey-bundle:latest

APIs​

  • ValkeyEmbeddingStore

Creating a ValkeyEmbeddingStore​

import dev.langchain4j.community.store.embedding.valkey.ValkeyEmbeddingStore;
import glide.api.GlideClient;
import glide.api.models.configuration.GlideClientConfiguration;
import glide.api.models.configuration.NodeAddress;

// 1. Create a GlideClient connection
GlideClientConfiguration config = GlideClientConfiguration.builder()
.address(NodeAddress.builder().host("localhost").port(6379).build())
.build();

GlideClient client = GlideClient.createClient(config).get();

// 2. Build the embedding store
ValkeyEmbeddingStore embeddingStore = ValkeyEmbeddingStore.builder()
.client(client)
.dimension(384) // Must match your embedding model's output dimension
.indexName("my-index") // Optional, defaults to "embedding-index"
.prefix("docs:") // Optional, defaults to "embedding:"
.build();

On build(), the store checks if the index exists in Valkey. If not, it creates one with HNSW indexing and COSINE distance metric (the defaults).

Configuration Options​

ParameterDescriptionDefault
clientGlideClient instance (required)—
dimensionEmbedding vector dimension (required if index does not exist)—
indexNameName of the Valkey search index"embedding-index"
prefixKey prefix for stored embeddings (should end with :)"embedding:"
metadataKeysCollection of metadata keys to persist as Tag fields—
metadataConfigMap of metadata key to FieldInfo for custom field types—
operationTimeoutSecondsTimeout in seconds for each Valkey operation60

Distance Metrics​

Valkey supports three distance metrics via the MetricType enum:

  • COSINE — Cosine similarity (default)
  • IP — Inner product
  • L2 — Euclidean distance

Storing and Searching Embeddings​

import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
import dev.langchain4j.store.embedding.EmbeddingSearchResult;

import java.util.List;

EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();

// Batch ingest
List<TextSegment> docs = List.of(
TextSegment.from("Valkey is a high-performance in-memory data store."),
TextSegment.from("Vector search finds similar items by embedding distance."),
TextSegment.from("HNSW is an algorithm for approximate nearest neighbors.")
);
List<Embedding> embeddings = embeddingModel.embedAll(docs).content();
List<String> ids = embeddingStore.addAll(embeddings, docs);

// Search
Embedding queryEmbedding = embeddingModel.embed("How does similarity search work?").content();
EmbeddingSearchResult<TextSegment> results = embeddingStore.search(
EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(3)
.minScore(0.5)
.build()
);

for (EmbeddingMatch<TextSegment> match : results.matches()) {
System.out.printf("%.3f: %s%n", match.score(), match.embedded().text());
}

Metadata Filtering​

Valkey supports the following filter types on metadata:

  • Numeric fields: eq, neq, gt, gte, lt, lte
  • Tag/Text fields: eq, neq, in, notIn

To enable metadata filtering, configure metadata fields when building the store. For simple tag-based filtering, use metadataKeys:

ValkeyEmbeddingStore store = ValkeyEmbeddingStore.builder()
.client(client)
.dimension(384)
.metadataKeys(List.of("category", "author"))
.build();

For typed fields (e.g., numeric vs. tag), use metadataConfig:

import glide.api.models.commands.FT.FTCreateOptions.FieldInfo;
import glide.api.models.commands.FT.FTCreateOptions.NumericField;
import glide.api.models.commands.FT.FTCreateOptions.TagField;

Map<String, FieldInfo> metadataConfig = Map.of(
"category", new FieldInfo("$.category", "category", new TagField(',', true)),
"year", new FieldInfo("$.year", "year", new NumericField())
);

ValkeyEmbeddingStore store = ValkeyEmbeddingStore.builder()
.client(client)
.dimension(384)
.indexName("filtered-docs")
.prefix("filtered:")
.metadataConfig(metadataConfig)
.build();

Then use filters in search requests:

import static dev.langchain4j.store.embedding.filter.MetadataFilterBuilder.metadataKey;

// TAG filter
Filter securityFilter = metadataKey("category").isEqualTo("security");

// NUMERIC filter
Filter recentFilter = metadataKey("year").isGreaterThanOrEqualTo(2025);

// Combined AND filter
Filter combined = metadataKey("category").isEqualTo("security")
.and(metadataKey("year").isGreaterThanOrEqualTo(2025));

// OR filter
Filter either = metadataKey("category").isEqualTo("security")
.or(metadataKey("category").isEqualTo("performance"));

EmbeddingSearchResult<TextSegment> results = store.search(
EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(5)
.filter(combined)
.build()
);

Examples​