package qdrant

  1. Overview
  2. Docs

ocaml-qdrant

Pure OCaml client for Qdrant vector database.

The first OCaml Qdrant client! Combines best practices from official Python, Rust, Go, and TypeScript clients.

Features

  • REST API client (no gRPC dependency)
  • Collection management (create, delete, info, exists)
  • Point operations (upsert, delete, get, batch upsert)
  • Vector search with filters and score threshold
  • Two Filter APIs: Sum types (explicit) + Fluent helpers (ergonomic)
  • Batch operations with automatic chunking (Python-inspired)
  • Recommend API with positive/negative examples
  • Async I/O with Lwt
  • Type-safe OCaml design

Install

opam install qdrant

Quick Start

let () = Lwt_main.run begin
  let open Lwt.Syntax in
  let open Qdrant in

  (* Create collection *)
  let* _ = create_collection
    ~name:"my_collection"
    ~vector_config:{ size = 1024; distance = Cosine }
    () in

  (* Insert points *)
  let* _ = upsert ~collection:"my_collection" ~points:[
    { id = "1"; vector = my_embedding; payload = [("text", `String "hello")] }
  ] () in

  (* Search *)
  let* results = search
    ~collection:"my_collection"
    ~vector:query_embedding
    ~limit:10
    () in

  Lwt.return ()
end

Filter API

Two styles are available - choose based on your preference:

Style 1: Sum Types (Explicit, Pattern-matchable)

Direct use of algebraic data types. Best for:

  • Pattern matching on filter conditions
  • Compile-time exhaustiveness checking
  • Maximum type safety
let open Qdrant.Filter in

(* Simple filter *)
let filter = Must [
  MatchKeyword ("category", "tech");
  Range ("price", { gt = None; gte = Some 10.0; lt = None; lte = Some 100.0 });
]

(* Complex filter with nesting *)
let filter = And [
  Must [MatchKeyword ("status", "active")];
  Should [
    MatchAny ("tags", ["ai"; "ml"; "data"]);
    GeoRadius ("location", { lat = 37.5; lon = 127.0 }, 1000.0);
  ];
  MustNot [IsNull "deleted_at"];
]

Style 2: Fluent Helpers (Ergonomic, Go/Rust-inspired)

Convenience functions wrapping sum types. Best for:

  • Quick prototyping
  • Cleaner syntax for common cases
  • Familiar to Go/Rust developers
let open Qdrant.Filter in

(* Simple filter *)
let filter = must [
  match_keyword "category" "tech";
  range "price" ~gte:10.0 ~lte:100.0 ();
]

(* Complex filter *)
let filter = combine [
  must [match_keyword "status" "active"];
  should [
    match_any "tags" ["ai"; "ml"; "data"];
    geo_radius "location" ~lat:37.5 ~lon:127.0 ~radius_m:1000.0;
  ];
  must_not [is_null "deleted_at"];
]

(* Full-text search *)
let filter = must [full_text "content" "machine learning"]

(* Null checks *)
let filter = must [is_not_null "required_field"]

Both styles produce identical JSON and can be used with search_with_filter:

let* results = search_with_filter
  ~collection:"items"
  ~vector:query_vec
  ~limit:10
  ~filter:(Filter.to_json filter)
  ()

Batch Operations

Python-inspired batch upsert with automatic chunking:

(* Insert 10,000 points in chunks of 100 *)
let* count = batch_upsert
  ~collection:"embeddings"
  ~points:large_point_list
  ~chunk_size:100
  () in
Printf.printf "Inserted %d points\n" count

Recommend API

Find similar items based on examples:

let* recommendations = recommend
  ~collection:"products"
  ~positive:["liked-item-1"; "liked-item-2"]
  ~negative:["disliked-item"]
  ~limit:10
  ()

Config

From Environment Variables (Recommended)

export QDRANT_URL="http://localhost:6333"
export QDRANT_API_KEY="your-api-key"  # optional
(* Explicit is better than implicit - use config_from_env *)
let config = Qdrant.config_from_env () in
let* result = Qdrant.health ~config () in
...

Programmatic Configuration

let config = Qdrant.{
  base_url = "https://your-qdrant.cloud";
  api_key = Some "your-key";
  timeout_s = 30.0;
}

Default Config

(* default_config = localhost:6333, no API key, 30s timeout *)
let* result = Qdrant.health () in  (* uses default_config *)

API Reference

Configuration

  • default_config - Default config (localhost:6333, no API key)
  • config_from_env - Create config from QDRANT_URL and QDRANT_API_KEY env vars

Health & Info

  • health - Check server status
  • version - Get Qdrant version

Collections

  • list_collections - List all collections
  • collection_exists - Check if collection exists
  • get_collection - Get collection info
  • create_collection - Create with vector config
  • delete_collection - Delete collection

Points

  • upsert - Insert/update points
  • batch_upsert - Bulk insert with chunking
  • delete_points - Delete by IDs
  • get_point - Get single point
  • search - Vector similarity search
  • search_with_filter - Search with payload filter
  • recommend - Recommendation based on examples

Scroll & Count

  • scroll - Paginate through all points
  • count - Count points in collection

Filter Module (Sum Types)

  • MatchKeyword, MatchAny, MatchInt, MatchBool, MatchText
  • Range, RangeInt
  • IsNull, IsEmpty, HasValue, NotEmpty
  • GeoRadius
  • Must, Should, MustNot, And

Filter Module (Fluent Helpers)

  • match_keyword, match_any, match_int, match_bool
  • full_text
  • range, range_int
  • is_null, is_not_null, is_empty, is_not_empty
  • geo_radius
  • must, should, must_not, combine

Inspiration

This client combines the best from official Qdrant clients:

  • Python: Batch operations with chunking, comprehensive API
  • Rust: Type safety, sum types for filters
  • Go: Fluent filter API, builder patterns (qdrant-go)
  • TypeScript: Clean async/await patterns

Testing

Unit Tests (No Qdrant Required)

dune runtest

27 tests covering types, filters, config, and error handling.

Integration Tests (Qdrant Required)

# Set up environment
export QDRANT_URL="http://localhost:6333"
# or for cloud: export QDRANT_URL="https://your-cluster.qdrant.io"
# export QDRANT_API_KEY="your-key"

# Run integration example
dune exec examples/basic.exe

Security

  • Path injection prevention (validates collection names and IDs)
  • HTTP header injection prevention (validates API keys)
  • Timeout protection against hung connections

License

MIT