CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-dev-langchain4j--langchain4j-qdrant

LangChain4j Qdrant integration providing a vector store embedding implementation for Qdrant database with metadata filtering support

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

examples.mddocs/

Code Examples

Practical examples for common operations with QdrantEmbeddingStore.

Store Initialization

Basic Initialization (Local)

import dev.langchain4j.store.embedding.qdrant.QdrantEmbeddingStore;

QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
    .collectionName("my-embeddings")
    .build();

Cloud Configuration

QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
    .host("qdrant.example.com")
    .port(6334)
    .collectionName("my-embeddings")
    .useTls(true)
    .apiKey("your-api-key")
    .build();

Custom Payload Key

QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
    .collectionName("my-embeddings")
    .payloadTextKey("content")  // Default is "text_segment"
    .build();

Custom Client

import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;

QdrantClient customClient = new QdrantClient(
    QdrantGrpcClient.newBuilder("localhost", 6334, false)
        .withApiKey("your-api-key")
        .build()
);

QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
    .client(customClient)
    .collectionName("my-embeddings")
    .build();

Adding Embeddings

Add Single Embedding Without Text

import dev.langchain4j.data.embedding.Embedding;

Embedding embedding = Embedding.from(new float[]{0.1f, 0.2f, 0.3f});
String id = store.add(embedding);
System.out.println("Generated ID: " + id);

Add with Specific ID

import java.util.UUID;

String customId = UUID.randomUUID().toString();
Embedding embedding = Embedding.from(new float[]{0.1f, 0.2f, 0.3f});
store.add(customId, embedding);

Add with Text Segment

import dev.langchain4j.data.segment.TextSegment;

Embedding embedding = Embedding.from(new float[]{0.1f, 0.2f, 0.3f});
TextSegment segment = TextSegment.from("Sample document text");
String id = store.add(embedding, segment);

Add with Text and Metadata

import dev.langchain4j.data.document.Metadata;
import dev.langchain4j.data.segment.TextSegment;
import java.util.UUID;

Metadata metadata = new Metadata();
metadata.put("author", "John Doe");
metadata.put("category", "documentation");
metadata.put("year", 2024);
metadata.put("score", 9.5);
metadata.put("documentId", UUID.randomUUID());

TextSegment segment = TextSegment.from("Sample document text", metadata);
Embedding embedding = Embedding.from(new float[]{0.1f, 0.2f, 0.3f});
String id = store.add(embedding, segment);

Bulk Add Embeddings

import java.util.Arrays;
import java.util.List;

List<Embedding> embeddings = Arrays.asList(
    Embedding.from(new float[]{0.1f, 0.2f}),
    Embedding.from(new float[]{0.3f, 0.4f}),
    Embedding.from(new float[]{0.5f, 0.6f})
);

List<String> ids = store.addAll(embeddings);
System.out.println("Generated " + ids.size() + " IDs");

Bulk Add with IDs and Text Segments

import java.util.UUID;

List<String> ids = Arrays.asList(
    UUID.randomUUID().toString(),
    UUID.randomUUID().toString()
);

List<Embedding> embeddings = Arrays.asList(
    Embedding.from(new float[]{0.1f, 0.2f}),
    Embedding.from(new float[]{0.3f, 0.4f})
);

List<TextSegment> segments = Arrays.asList(
    TextSegment.from("First document"),
    TextSegment.from("Second document")
);

store.addAll(ids, embeddings, segments);

Searching Embeddings

Basic Search

import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
import dev.langchain4j.store.embedding.EmbeddingSearchResult;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.data.segment.TextSegment;

Embedding queryEmbedding = Embedding.from(new float[]{0.15f, 0.25f});

EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
    .queryEmbedding(queryEmbedding)
    .maxResults(5)
    .minScore(0.7)
    .build();

EmbeddingSearchResult<TextSegment> results = store.search(request);

Process Search Results

for (EmbeddingMatch<TextSegment> match : results.matches()) {
    System.out.println("Score: " + match.score());
    System.out.println("ID: " + match.embeddingId());

    TextSegment segment = match.embedded();
    if (segment != null) {
        System.out.println("Text: " + segment.text());
        System.out.println("Metadata: " + segment.metadata());
    }
}

Search with Metadata Filter

import dev.langchain4j.store.embedding.filter.Filter;
import static dev.langchain4j.store.embedding.filter.MetadataFilterBuilder.*;

Filter filter = metadataKey("category").isEqualTo("documentation");

EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
    .queryEmbedding(queryEmbedding)
    .maxResults(10)
    .minScore(0.8)
    .filter(filter)
    .build();

EmbeddingSearchResult<TextSegment> results = store.search(request);

Search with Complex Filter

import dev.langchain4j.store.embedding.filter.logical.And;
import dev.langchain4j.store.embedding.filter.logical.Or;

Filter complexFilter = new And(
    metadataKey("category").isEqualTo("documentation"),
    new Or(
        metadataKey("priority").isGreaterThan(5),
        metadataKey("urgent").isEqualTo(true)
    )
);

EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
    .queryEmbedding(queryEmbedding)
    .maxResults(5)
    .filter(complexFilter)
    .build();

EmbeddingSearchResult<TextSegment> results = store.search(request);

Removing Embeddings

Remove Single Embedding

String id = "550e8400-e29b-41d4-a716-446655440000";
store.remove(id);

Remove Multiple Embeddings

import java.util.Arrays;

Collection<String> ids = Arrays.asList(
    "550e8400-e29b-41d4-a716-446655440000",
    "550e8400-e29b-41d4-a716-446655440001"
);
store.removeAll(ids);

Remove by Metadata Filter

// Remove all embeddings from 2019 or earlier
Filter filter = metadataKey("year").isLessThan(2020);
store.removeAll(filter);

Remove by Multiple Criteria

// Remove documentation from specific author
Filter filter = new And(
    metadataKey("category").isEqualTo("documentation"),
    metadataKey("author").isEqualTo("John Doe")
);
store.removeAll(filter);

Clear All Embeddings

// Option 1: Remove all
store.removeAll();

// Option 2: Clear store
store.clearStore();

Store Management

Cleanup Pattern

QdrantEmbeddingStore store = null;
try {
    store = QdrantEmbeddingStore.builder()
        .collectionName("my-collection")
        .build();

    // Use store...
    store.add(embedding, segment);

} finally {
    if (store != null) {
        store.close();
    }
}

Try-with-Resources (If Implementing AutoCloseable)

// Note: Current implementation requires manual close()
try {
    QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
        .collectionName("my-collection")
        .build();

    // Use store...

    store.close();
} catch (Exception e) {
    // Handle exception
}

Integration with LangChain4j

Complete RAG Pipeline

import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.AllMiniLmL6V2QuantizedEmbeddingModel;
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.splitter.DocumentSplitters;
import dev.langchain4j.data.segment.TextSegment;

// Initialize components
EmbeddingModel embeddingModel = new AllMiniLmL6V2QuantizedEmbeddingModel();
QdrantEmbeddingStore embeddingStore = QdrantEmbeddingStore.builder()
    .collectionName("documents")
    .build();

// Process document
Document document = Document.from("Long document text...");
DocumentSplitter splitter = DocumentSplitters.recursive(300, 50);
List<TextSegment> segments = splitter.split(document);

// Store embeddings
for (TextSegment segment : segments) {
    Embedding embedding = embeddingModel.embed(segment).content();
    embeddingStore.add(embedding, segment);
}

// Search
String query = "What is the main topic?";
Embedding queryEmbedding = embeddingModel.embed(query).content();
EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
    .queryEmbedding(queryEmbedding)
    .maxResults(3)
    .minScore(0.7)
    .build();

EmbeddingSearchResult<TextSegment> results = embeddingStore.search(request);

Semantic Search with Metadata

import dev.langchain4j.data.document.Metadata;

// Index documents with metadata
List<String> documents = Arrays.asList(
    "Python is a programming language",
    "Java is a programming language",
    "Coffee is a hot beverage"
);

List<String> categories = Arrays.asList("tech", "tech", "food");

for (int i = 0; i < documents.size(); i++) {
    Metadata metadata = new Metadata();
    metadata.put("category", categories.get(i));
    metadata.put("index", i);

    TextSegment segment = TextSegment.from(documents.get(i), metadata);
    Embedding embedding = embeddingModel.embed(segment).content();
    embeddingStore.add(embedding, segment);
}

// Search with category filter
Filter techFilter = metadataKey("category").isEqualTo("tech");
Embedding queryEmbedding = embeddingModel.embed("programming").content();

EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
    .queryEmbedding(queryEmbedding)
    .maxResults(5)
    .filter(techFilter)
    .build();

EmbeddingSearchResult<TextSegment> results = embeddingStore.search(request);

Batch Processing Pattern

// Batch process large document collection
List<Document> documents = loadDocuments();
int batchSize = 100;

for (int i = 0; i < documents.size(); i += batchSize) {
    int end = Math.min(i + batchSize, documents.size());
    List<Document> batch = documents.subList(i, end);

    List<Embedding> embeddings = new ArrayList<>();
    List<TextSegment> segments = new ArrayList<>();

    for (Document doc : batch) {
        TextSegment segment = TextSegment.from(doc.text());
        Embedding embedding = embeddingModel.embed(segment).content();

        embeddings.add(embedding);
        segments.add(segment);
    }

    // Bulk insert batch
    List<String> ids = embeddingStore.addAll(embeddings);
    System.out.println("Processed batch: " + i + "-" + end);
}

Error Handling Patterns

Graceful Error Handling

try {
    String id = store.add(embedding, segment);
    System.out.println("Added with ID: " + id);
} catch (RuntimeException e) {
    System.err.println("Failed to add embedding: " + e.getMessage());
    // Log error, retry, or handle gracefully
}

Validation Before Removal

String id = "550e8400-e29b-41d4-a716-446655440000";

if (id != null && !id.trim().isEmpty()) {
    try {
        store.remove(id);
    } catch (IllegalArgumentException e) {
        System.err.println("Invalid ID format: " + e.getMessage());
    }
} else {
    System.err.println("ID cannot be null or empty");
}

Builder Validation

try {
    QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
        .collectionName("my-collection")
        .build();
} catch (NullPointerException e) {
    System.err.println("Missing required configuration: " + e.getMessage());
}

Testing Patterns

In-Memory Testing Setup

// For testing, use a local Qdrant instance
QdrantEmbeddingStore testStore = QdrantEmbeddingStore.builder()
    .host("localhost")
    .port(6334)
    .collectionName("test-collection")
    .build();

// Run tests...

// Cleanup after tests
testStore.clearStore();
testStore.close();

Test with Mock Data

// Create test embeddings
List<Embedding> testEmbeddings = Arrays.asList(
    Embedding.from(new float[]{1.0f, 0.0f}),
    Embedding.from(new float[]{0.0f, 1.0f}),
    Embedding.from(new float[]{0.5f, 0.5f})
);

List<TextSegment> testSegments = Arrays.asList(
    TextSegment.from("Test document 1"),
    TextSegment.from("Test document 2"),
    TextSegment.from("Test document 3")
);

// Add test data
for (int i = 0; i < testEmbeddings.size(); i++) {
    store.add(testEmbeddings.get(i), testSegments.get(i));
}

// Verify search works
Embedding query = Embedding.from(new float[]{0.9f, 0.1f});
EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
    .queryEmbedding(query)
    .maxResults(1)
    .build();

EmbeddingSearchResult<TextSegment> results = store.search(request);
assertEquals(1, results.matches().size());

Install with Tessl CLI

npx tessl i tessl/maven-dev-langchain4j--langchain4j-qdrant

docs

api.md

error-handling.md

examples.md

filters.md

index.md

setup.md

tile.json