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
Complete guide for setting up and configuring QdrantEmbeddingStore.
Running Qdrant Instance
Qdrant Collection
Java Environment
docker pull qdrant/qdrant
docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant# Download from https://github.com/qdrant/qdrant/releases
# Extract and run
./qdrantSign up at https://cloud.qdrant.io/ and create a cluster.
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.VectorParams;
import io.qdrant.client.grpc.Collections.Distance;
// Create client
QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost", 6334, false).build()
);
// Create collection
client.createCollectionAsync(
"my-collection",
VectorParams.newBuilder()
.setDistance(Distance.Cosine) // Use cosine similarity
.setSize(384) // Dimension of embeddings
.build()
).get();
client.close();curl -X PUT 'http://localhost:6333/collections/my-collection' \
-H 'Content-Type: application/json' \
-d '{
"vectors": {
"size": 384,
"distance": "Cosine"
}
}'Add to pom.xml:
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-qdrant</artifactId>
<version>1.11.0</version>
</dependency>
</dependencies>Add to build.gradle:
dependencies {
implementation 'dev.langchain4j:langchain4j-qdrant:1.11.0'
}Add to build.gradle.kts:
dependencies {
implementation("dev.langchain4j:langchain4j-qdrant:1.11.0")
}import dev.langchain4j.store.embedding.qdrant.QdrantEmbeddingStore;
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.collectionName("my-collection") // REQUIRED
.host("localhost") // Default: "localhost"
.port(6334) // Default: 6334
.useTls(false) // Default: false
.apiKey(null) // Default: null (no auth)
.payloadTextKey("text_segment") // Default: "text_segment"
.build();The name of the Qdrant collection to use.
.collectionName("my-embeddings")NullPointerException if not setThe hostname or IP address of the Qdrant instance.
.host("localhost") // Local
.host("qdrant.example.com") // Remote
.host("abc123.qdrant.io") // Cloud"localhost"The GRPC port of the Qdrant instance.
.port(6334) // Default GRPC port6334Whether to use TLS/SSL encryption for connection.
.useTls(false) // Local without TLS
.useTls(true) // Cloud with TLSfalsetrue for cloud deploymentstrue if Qdrant configured with TLSAPI key for authentication.
.apiKey("your-api-key") // With authentication
.apiKey(null) // No authenticationnull (no authentication)The field name used to store text segments in Qdrant payload.
.payloadTextKey("text_segment") // Default
.payloadTextKey("content") // Custom"text_segment"Use a custom configured Qdrant 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-collection")
.build();host, port, useTls, and apiKey settingsDefault configuration for local Qdrant:
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.collectionName("my-collection")
.build();Explicit configuration:
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.host("localhost")
.port(6334)
.collectionName("my-collection")
.useTls(false)
.build();For Qdrant Cloud:
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.host("your-cluster.qdrant.io")
.port(6334)
.collectionName("my-collection")
.useTls(true)
.apiKey("your-api-key-here")
.build();For remote Qdrant with API key:
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.host("qdrant.example.com")
.port(6334)
.collectionName("my-collection")
.useTls(true)
.apiKey(System.getenv("QDRANT_API_KEY"))
.build();For advanced scenarios:
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import java.time.Duration;
QdrantGrpcClient grpcClient = QdrantGrpcClient.newBuilder(
"localhost",
6334,
false // useTls
)
.withApiKey("your-api-key")
.withDeadline(Duration.ofSeconds(30))
.build();
QdrantClient client = new QdrantClient(grpcClient);
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.client(client)
.collectionName("my-collection")
.payloadTextKey("content")
.build();QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.host(System.getenv("QDRANT_HOST"))
.port(Integer.parseInt(System.getenv("QDRANT_PORT")))
.collectionName(System.getenv("QDRANT_COLLECTION"))
.useTls(Boolean.parseBoolean(System.getenv("QDRANT_USE_TLS")))
.apiKey(System.getenv("QDRANT_API_KEY"))
.build();import java.util.Properties;
import java.io.FileInputStream;
Properties props = new Properties();
props.load(new FileInputStream("qdrant.properties"));
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.host(props.getProperty("qdrant.host", "localhost"))
.port(Integer.parseInt(props.getProperty("qdrant.port", "6334")))
.collectionName(props.getProperty("qdrant.collection"))
.useTls(Boolean.parseBoolean(props.getProperty("qdrant.use.tls", "false")))
.apiKey(props.getProperty("qdrant.api.key"))
.build();Example qdrant.properties:
qdrant.host=localhost
qdrant.port=6334
qdrant.collection=my-embeddings
qdrant.use.tls=false
qdrant.api.key=import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QdrantConfig {
@Value("${qdrant.host:localhost}")
private String host;
@Value("${qdrant.port:6334}")
private int port;
@Value("${qdrant.collection}")
private String collectionName;
@Value("${qdrant.use-tls:false}")
private boolean useTls;
@Value("${qdrant.api-key:#{null}}")
private String apiKey;
@Bean
public QdrantEmbeddingStore qdrantEmbeddingStore() {
return QdrantEmbeddingStore.builder()
.host(host)
.port(port)
.collectionName(collectionName)
.useTls(useTls)
.apiKey(apiKey)
.build();
}
}try {
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.collectionName("test-collection")
.build();
// Try a simple operation
Embedding testEmbedding = Embedding.from(new float[]{1.0f, 0.0f});
String id = store.add(testEmbedding);
System.out.println("Connection successful! ID: " + id);
// Cleanup
store.remove(id);
store.close();
} catch (Exception e) {
System.err.println("Connection failed: " + e.getMessage());
e.printStackTrace();
}import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost", 6334, false).build()
);
try {
// List collections
var collections = client.listCollectionsAsync().get();
System.out.println("Available collections:");
collections.forEach(collection ->
System.out.println(" - " + collection.getName())
);
// Check specific collection
var collectionInfo = client.getCollectionInfoAsync("my-collection").get();
System.out.println("Collection info: " + collectionInfo);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
} finally {
client.close();
}import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost", 6334, false).build()
);
// Get collection information
var info = client.getCollectionInfoAsync("my-collection").get();
System.out.println("Vector size: " + info.getConfig().getParams().getVectorParams().getSize());
System.out.println("Distance: " + info.getConfig().getParams().getVectorParams().getDistance());
System.out.println("Point count: " + info.getPointsCount());
client.close();import io.qdrant.client.grpc.Collections.VectorParams;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.OptimizersConfigDiff;
QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost", 6334, false).build()
);
client.createCollectionAsync(
"my-collection",
VectorParams.newBuilder()
.setDistance(Distance.Cosine)
.setSize(384)
.build(),
OptimizersConfigDiff.newBuilder()
.setIndexingThreshold(20000)
.build()
).get();
client.close();QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost", 6334, false).build()
);
client.deleteCollectionAsync("my-collection").get();
client.close();The library uses a single GRPC client per QdrantEmbeddingStore instance. For connection pooling:
// Create once, reuse across application
public class QdrantStoreProvider {
private static final QdrantEmbeddingStore INSTANCE =
QdrantEmbeddingStore.builder()
.collectionName("shared-collection")
.build();
public static QdrantEmbeddingStore getInstance() {
return INSTANCE;
}
public static void shutdown() {
INSTANCE.close();
}
}// For multiple collections, create separate instances
QdrantClient sharedClient = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost", 6334, false).build()
);
QdrantEmbeddingStore store1 = QdrantEmbeddingStore.builder()
.client(sharedClient)
.collectionName("collection-1")
.build();
QdrantEmbeddingStore store2 = QdrantEmbeddingStore.builder()
.client(sharedClient)
.collectionName("collection-2")
.build();
// Close shared client when done
sharedClient.close();Problem: java.net.ConnectException: Connection refused
Solutions:
# Test connection
curl http://localhost:6333/
# Should return Qdrant version infoProblem: SSL handshake errors
Solutions:
useTls(true) is set for HTTPS endpointsuseTls(false) is set for HTTP endpointsProblem: UNAUTHENTICATED or PERMISSION_DENIED
Solutions:
.apiKey() is set if Qdrant requires authenticationProblem: Collection 'my-collection' not found
Solutions:
Problem: Vector dimension mismatch
Solutions:
// Get embedding dimension
EmbeddingModel model = new AllMiniLmL6V2QuantizedEmbeddingModel();
Embedding embedding = model.embed("test").content();
System.out.println("Dimension: " + embedding.vector().length);For optimal performance, configure collection indexing:
import io.qdrant.client.grpc.Collections.OptimizersConfigDiff;
client.updateCollectionAsync(
"my-collection",
OptimizersConfigDiff.newBuilder()
.setIndexingThreshold(20000) // Index after 20k points
.setVacuumMinVectorNumber(1000)
.build()
).get();Use bulk operations for better performance:
// Good: Bulk insert
List<Embedding> embeddings = generateEmbeddings(1000);
store.addAll(embeddings);
// Less optimal: Individual inserts
for (Embedding embedding : embeddings) {
store.add(embedding);
}Always close stores when done:
QdrantEmbeddingStore store = QdrantEmbeddingStore.builder()
.collectionName("my-collection")
.build();
try {
// Use store...
} finally {
store.close(); // Release GRPC connection
}Install with Tessl CLI
npx tessl i tessl/maven-dev-langchain4j--langchain4j-qdrant