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

setup.mddocs/

Setup and Configuration

Complete guide for setting up and configuring QdrantEmbeddingStore.

Prerequisites

Required Components

  1. Running Qdrant Instance

    • Local installation or cloud-hosted instance
    • GRPC port accessible (default: 6334)
    • Version compatibility: Qdrant 1.x+
  2. Qdrant Collection

    • Must be created before using the library
    • Vector dimensions must match your embedding model
    • Distance metric should be Cosine for similarity search
  3. Java Environment

    • Java 17 or higher
    • Maven or Gradle build tool

Installing Qdrant

Local Installation (Docker)

docker pull qdrant/qdrant
docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant

Local Installation (Binary)

# Download from https://github.com/qdrant/qdrant/releases
# Extract and run
./qdrant

Cloud Qdrant

Sign up at https://cloud.qdrant.io/ and create a cluster.

Creating a Qdrant Collection

Using Qdrant Client

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();

Using REST API

curl -X PUT 'http://localhost:6333/collections/my-collection' \
  -H 'Content-Type: application/json' \
  -d '{
    "vectors": {
      "size": 384,
      "distance": "Cosine"
    }
  }'

Common Embedding Dimensions

  • all-MiniLM-L6-v2: 384 dimensions
  • all-mpnet-base-v2: 768 dimensions
  • text-embedding-ada-002: 1536 dimensions
  • sentence-transformers/all-MiniLM-L12-v2: 384 dimensions

Dependency Installation

Maven

Add to pom.xml:

<dependencies>
    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-qdrant</artifactId>
        <version>1.11.0</version>
    </dependency>
</dependencies>

Gradle (Groovy)

Add to build.gradle:

dependencies {
    implementation 'dev.langchain4j:langchain4j-qdrant:1.11.0'
}

Gradle (Kotlin DSL)

Add to build.gradle.kts:

dependencies {
    implementation("dev.langchain4j:langchain4j-qdrant:1.11.0")
}

Configuration Options

Builder Configuration

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();

Configuration Parameter Details

collectionName (REQUIRED)

The name of the Qdrant collection to use.

.collectionName("my-embeddings")
  • Must be created in Qdrant before use
  • Cannot be null or empty
  • Throws NullPointerException if not set

host

The hostname or IP address of the Qdrant instance.

.host("localhost")              // Local
.host("qdrant.example.com")     // Remote
.host("abc123.qdrant.io")       // Cloud
  • Default: "localhost"
  • Use IP address or hostname
  • For cloud, use provided cluster URL

port

The GRPC port of the Qdrant instance.

.port(6334)  // Default GRPC port
  • Default: 6334
  • HTTP API uses port 6333 (not used by this library)
  • GRPC API uses port 6334

useTls

Whether to use TLS/SSL encryption for connection.

.useTls(false)  // Local without TLS
.useTls(true)   // Cloud with TLS
  • Default: false
  • Set to true for cloud deployments
  • Set to true if Qdrant configured with TLS

apiKey

API key for authentication.

.apiKey("your-api-key")     // With authentication
.apiKey(null)               // No authentication
  • Default: null (no authentication)
  • Required for Qdrant Cloud
  • Optional for local deployments
  • Can be used with local Qdrant if configured

payloadTextKey

The field name used to store text segments in Qdrant payload.

.payloadTextKey("text_segment")  // Default
.payloadTextKey("content")       // Custom
  • Default: "text_segment"
  • Change only if you have specific requirements
  • Must be consistent for all operations on the collection

client

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();
  • Overrides host, port, useTls, and apiKey settings
  • Use for advanced client configuration
  • Allows reuse of existing client instance

Connection Patterns

Local Development

Default 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();

Cloud Deployment

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();

Remote Server with Authentication

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();

Custom Client Configuration

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();

Environment-Based Configuration

Using Environment Variables

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();

Using Configuration Properties

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=

Using Spring Configuration

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();
    }
}

Verifying Connection

Test Connection

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();
}

Check Collection Exists

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();
}

Collection Management

Check Collection Details

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();

Create Collection with Options

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();

Delete Collection

QdrantClient client = new QdrantClient(
    QdrantGrpcClient.newBuilder("localhost", 6334, false).build()
);

client.deleteCollectionAsync("my-collection").get();
client.close();

Connection Pooling

The library uses a single GRPC client per QdrantEmbeddingStore instance. For connection pooling:

Single Shared Instance

// 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();
    }
}

Multiple Collections

// 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();

Troubleshooting

Connection Refused

Problem: java.net.ConnectException: Connection refused

Solutions:

  • Verify Qdrant is running
  • Check host and port are correct
  • Ensure firewall allows connection to port 6334
# Test connection
curl http://localhost:6333/
# Should return Qdrant version info

TLS/SSL Errors

Problem: SSL handshake errors

Solutions:

  • Verify useTls(true) is set for HTTPS endpoints
  • Verify useTls(false) is set for HTTP endpoints
  • Check certificate validity for cloud deployments

Authentication Errors

Problem: UNAUTHENTICATED or PERMISSION_DENIED

Solutions:

  • Verify API key is correct
  • Check API key has necessary permissions
  • Ensure .apiKey() is set if Qdrant requires authentication

Collection Not Found

Problem: Collection 'my-collection' not found

Solutions:

  • Create collection before using (see Creating a Qdrant Collection section)
  • Verify collection name is spelled correctly
  • Check you're connecting to correct Qdrant instance

Vector Dimension Mismatch

Problem: Vector dimension mismatch

Solutions:

  • Verify collection vector size matches embedding model output
  • Check embedding model configuration
  • Recreate collection with correct dimensions
// Get embedding dimension
EmbeddingModel model = new AllMiniLmL6V2QuantizedEmbeddingModel();
Embedding embedding = model.embed("test").content();
System.out.println("Dimension: " + embedding.vector().length);

Performance Tuning

Collection Configuration

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();

Batch Operations

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);
}

Resource Management

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@1.11.0

docs

api.md

error-handling.md

examples.md

filters.md

index.md

setup.md

tile.json