LangChain4j Qdrant integration providing a vector store embedding implementation for Qdrant database with metadata filtering support
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Practical examples for common operations with QdrantEmbeddingStore.
import dev.langchain4j.store.embedding.qdrant.QdrantEmbeddingStore;
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.collectionName("my-embeddings")
.build();QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.host("qdrant.example.com")
.port(6334)
.collectionName("my-embeddings")
.useTls(true)
.apiKey("your-api-key")
.build();QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.collectionName("my-embeddings")
.payloadTextKey("content") // Default is "text_segment"
.build();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();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);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);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);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);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");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);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);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());
}
}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);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);String id = "550e8400-e29b-41d4-a716-446655440000";
store.remove(id);import java.util.Arrays;
Collection<String> ids = Arrays.asList(
"550e8400-e29b-41d4-a716-446655440000",
"550e8400-e29b-41d4-a716-446655440001"
);
store.removeAll(ids);// Remove all embeddings from 2019 or earlier
Filter filter = metadataKey("year").isLessThan(2020);
store.removeAll(filter);// Remove documentation from specific author
Filter filter = new And(
metadataKey("category").isEqualTo("documentation"),
metadataKey("author").isEqualTo("John Doe")
);
store.removeAll(filter);// Option 1: Remove all
store.removeAll();
// Option 2: Clear store
store.clearStore();QdrantEmbeddingStore store = null;
try {
store = QdrantEmbeddingStore.builder()
.collectionName("my-collection")
.build();
// Use store...
store.add(embedding, segment);
} finally {
if (store != null) {
store.close();
}
}// Note: Current implementation requires manual close()
try {
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.collectionName("my-collection")
.build();
// Use store...
store.close();
} catch (Exception e) {
// Handle exception
}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);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 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);
}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
}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");
}try {
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.collectionName("my-collection")
.build();
} catch (NullPointerException e) {
System.err.println("Missing required configuration: " + e.getMessage());
}// 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();// 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