A MoonBit client for the Qdrant vector database REST API.
moon add yuzhiblue/moon-qdrantdocker run -p 6333:6333 qdrant/qdrantlet client = QdrantClient::new("http://localhost:6333")
// health check
let ok = client.health()
// create a collection with 4-dimensional cosine vectors
client.create_collection(
"demo",
CollectionConfig::new(VectorParams::new(4, Distance::Cosine)),
)
// list collections
let names = client.list_collections()
// inspect a collection
let info = client.collection_info("demo")
// does it exist?
let exists = client.collection_exists("demo")
// write some points
client.upsert_points("demo", [
PointStruct::new(1, [0.1, 0.2, 0.3, 0.4], { "tag": "alpha" }),
PointStruct::new(2, [0.5, 0.6, 0.7, 0.8], { "tag": "beta" }),
])
// read one back
let point = client.get_point("demo", 1)
// search for the most similar points
let hits = client.search_points("demo", [0.1, 0.2, 0.3, 0.4], limit=2)
// search with a payload filter
let filtered = client.search_points(
"demo",
[0.1, 0.2, 0.3, 0.4],
limit=2,
filter={ "must": [{ "key": "tag", "match": { "value": "alpha" } }] },
)
// delete points by id
client.delete_points("demo", [2])
// drop the collection
client.delete_collection("demo")// only hits scoring 0.9 or better, skipping the first hit
///|
let hits = client.search_points(
"demo",
[0.1, 0.2, 0.3, 0.4],
2,
score_threshold=Some(0.9),
offset=Some(1),
search_params=Some(SearchParams::new(exact=Some(true))),
)
// several searches in one round trip
///|
let batch = client.search_points_batch("demo", [
{ "vector": [0.1, 0.2, 0.3, 0.4], "limit": 2 },
{ "vector": [0.9, 0.8, 0.7, 0.6], "limit": 2 },
])let named : Map[String, VectorParams] = Map([])
named["text"] = VectorParams::new(4, Distance::Cosine)
named["image"] = VectorParams::new(8, Distance::Dot)
client.create_collection("multi", CollectionConfig::new_named(named))
let vectors : Map[String, Array[Double]] = Map([])
vectors["text"] = [0.1, 0.2, 0.3, 0.4]
vectors["image"] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
client.upsert_points("multi", [PointStruct::new_named(1, vectors, { "tag": "a" })])
// search against the "text" vector
let hits = client.search_points(
"multi",
[0.1, 0.2, 0.3, 0.4],
1,
using_vector=Some("text"),
)
// or via a NamedVector input
let hits = client.search_points_named(
"multi",
NamedVector::new("image", [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]),
1,
)// merge fields into the payload of points 1 and 2
client.set_payload("demo", { "active": true }, ids=Some([1, 2]))
// replace the whole payload of points matching a filter
client.overwrite_payload(
"demo",
{ "state": "new" },
filter=Some(Filter::new().must(Condition::match_keyword("tag", "alpha"))),
)
// drop selected keys from point 1
client.delete_payload_by_keys("demo", ["active"], ids=Some([1]))
// drop the whole payload of all points matching a filter
client.delete_payload("demo", filter=Some(Filter::new()))// nearest neighbor
let hits = client.query_nearest("demo", [0.1, 0.2, 0.3, 0.4], 2)
// recommendation: like the positive vectors, unlike the negative ones
let positive : Array[Json] = [
Json::array([0.1, 0.2, 0.3, 0.4]),
Json::number(3), // point ids are accepted too
]
let negative : Array[Json] = [Json::array([0.9, 0.8, 0.7, 0.6])]
let recs = client.query_recommend(
"demo",
positive,
negative=Some(negative),
limit=5,
)
// facet: how many points carry each distinct value of a payload field
let facet = client.facet_points("demo", "tag", 10)
for hit in facet.hits {
println(hit.value.stringify() + ": " + hit.count.to_string())
}
// grouped search: top hits per distinct payload value
let groups = client.search_points_groups(
"demo",
[0.1, 0.2, 0.3, 0.4],
2, // hits per group
"tag", // group-by field
10, // max groups
)
for group in groups {
println(
"group " + group.id.stringify() + " -> " +
group.hits.length().to_string() + " hits",
)
}// cluster state (works on single-node deployments too)
let cluster = client.cluster_info()
println("cluster status: " + cluster.status)
println("peers: " + cluster.peers.length().to_string())
// per-collection shard / replica layout
let layout = client.collection_cluster_info("demo")
for shard in layout.local_shards {
println(
"shard " + shard.shard_id.to_string() + ": " +
shard.state + " (" + shard.points_count.to_string() + " points)",
)
}
// shard lifecycle (multi-node clusters)
client.replicate_shard("demo", 0L, 1L, 2L)
client.create_shard_replica("demo", 0L, 2L)
client.delete_shard_replica("demo", 0L, 2L)
// write lock + server version
client.set_locks(true, error_message=Some("maintenance"))
let lock = client.get_locks()
println("writes locked: " + lock.write.to_string())
let info = client.service_info()
match info.version {
Some(v) => println("qdrant version: " + v)
None => ()
}// update replication settings
client.update_collection(
"demo",
CollectionUpdate::new(replication_factor=Some(2)),
)
// index a payload field for fast filtered access
client.create_payload_index("demo", "tag", "keyword")
let indexes = client.list_payload_indexes("demo")
client.delete_payload_index("demo", "tag")
// snapshot the collection for backup / migration
let snap = client.create_snapshot("demo")
let snapshots = client.list_snapshots("demo")
client.delete_snapshot("demo", snap.name)moon run cmd/main -- http://localhost:6333docker run -p 6333:6333 qdrant/qdrant
moon run examples/demo -- http://localhost:6333moon check --deny-warn
moon test
moon fmtdocker run -p 6333:6333 qdrant/qdrant
moon run examples/integration_check -- http://localhost:6333
moon run examples/demo -- http://localhost:6333pub trait VectorProvider {
async fn create_collection(self : Self, name : String, config : CollectionConfig) -> Unit
async fn delete_collection(self : Self, name : String) -> Unit
async fn collection_exists(self : Self, name : String) -> Bool
async fn upsert_points(self : Self, name : String, points : Array[PointStruct]) -> Unit
async fn upsert_points_batch(self : Self, name : String, points : Array[PointStruct]) -> Unit
async fn search_points(self : Self, name : String, vector : Array[Double], limit : Int, filter? : Json?) -> Array[ScoredPoint]
async fn search_with_filter(self : Self, name : String, vector : Array[Double], limit : Int, filter : Filter) -> Array[ScoredPoint]
}pub struct AliasInfo {
alias_name : String
collection_name : String
}pub struct CollectionClusterInfo {
peer_id : Int64
shard_count : Int64
local_shards : Array[LocalShardInfo]
remote_shards : Array[RemoteShardInfo]
shard_transfers : Array[ShardTransferInfo]
}pub struct CollectionLock {
write : Bool
error_message : String?
}pub struct CollectionSummary {
name : String
}pub struct CollectionUpdate {
vectors : VectorParams?
named_vectors : Map[String, VectorParams]?
replication_factor : Int?
write_consistency_factor : Int?
}fn CollectionUpdate::new(vectors? : VectorParams?, named_vectors? : Map[String, VectorParams]?, replication_factor? : Int?, write_consistency_factor? : Int?) -> CollectionUpdatepub(all) enum Distance {
Cosine
Euclid
Dot
}pub struct LocalShardInfo {
shard_id : Int64
points_count : Int64
state : String
}pub struct PeerInfo {
uri : String?
last_hb_secs_ago : Int64?
last_resp_secs_ago : Int64?
last_update_secs_ago : Int64?
}fn PointStruct::new_named(id : Int, named_vectors : Map[String, Array[Double]], payload : Json) -> PointStructimpl VectorProvider for QdrantClientasync fn search_points(self : QdrantClient, name : String, vector : Array[Double], limit : Int, filter? : Json?) -> Array[ScoredPoint]async fn search_with_filter(self : QdrantClient, name : String, vector : Array[Double], limit : Int, filter : Filter) -> Array[ScoredPoint]async fn upsert_points_batch(self : QdrantClient, name : String, points : Array[PointStruct]) -> Unitasync fn QdrantClient::collection_cluster_info(self : QdrantClient, name : String) -> CollectionClusterInfoasync fn QdrantClient::count_points(self : QdrantClient, name : String, filter? : Filter?, exact? : Bool) -> Intasync fn QdrantClient::create_alias(self : QdrantClient, alias_name : String, collection : String) -> Unitasync fn QdrantClient::create_collection(self : QdrantClient, name : String, config : CollectionConfig) -> Unitasync fn QdrantClient::create_payload_index(self : QdrantClient, name : String, field : String, schema : String, wait? : Bool) -> Unitasync fn QdrantClient::create_shard_replica(self : QdrantClient, name : String, shard_id : Int64, peer_id : Int64) -> Boolasync fn QdrantClient::create_snapshot(self : QdrantClient, name : String, wait? : Bool) -> SnapshotInfoasync fn QdrantClient::delete_payload(self : QdrantClient, name : String, ids? : Array[Int]?, filter? : Filter?, wait? : Bool) -> Unitasync fn QdrantClient::delete_payload_by_keys(self : QdrantClient, name : String, keys : Array[String], ids? : Array[Int]?, filter? : Filter?, wait? : Bool) -> Unitasync fn QdrantClient::delete_payload_index(self : QdrantClient, name : String, field : String, wait? : Bool) -> Unitasync fn QdrantClient::delete_points(self : QdrantClient, name : String, ids : Array[Int], wait? : Bool) -> Unitasync fn QdrantClient::delete_points_by_filter(self : QdrantClient, name : String, filter : Filter, wait? : Bool) -> Unitasync fn QdrantClient::delete_shard_replica(self : QdrantClient, name : String, shard_id : Int64, peer_id : Int64) -> Boolasync fn QdrantClient::delete_snapshot(self : QdrantClient, name : String, snapshot : String, wait? : Bool) -> Unitasync fn QdrantClient::facet_points(self : QdrantClient, name : String, key : String, limit : Int, filter? : Filter?, exact? : Bool) -> FacetResultasync fn QdrantClient::get_point(self : QdrantClient, name : String, id : Int, with_payload? : Bool, with_vector? : Bool) -> PointStruct?async fn QdrantClient::list_payload_indexes(self : QdrantClient, name : String) -> Array[PayloadIndexInfo]async fn QdrantClient::overwrite_payload(self : QdrantClient, name : String, payload : Json, ids? : Array[Int]?, filter? : Filter?, wait? : Bool) -> Unitasync fn QdrantClient::query_nearest(self : QdrantClient, name : String, vector : Array[Double], limit : Int, filter? : Filter?, using_vector? : String?, score_threshold? : Double?, with_payload? : Bool, with_vector? : Bool) -> Array[ScoredPoint]async fn QdrantClient::query_points(self : QdrantClient, name : String, query : Json, limit : Int, filter? : Filter?, using_vector? : String?, score_threshold? : Double?, with_payload? : Bool, with_vector? : Bool) -> Array[ScoredPoint]async fn QdrantClient::query_recommend(self : QdrantClient, name : String, positive : Array[Json], negative? : Array[Json]?, limit : Int, filter? : Filter?, using_vector? : String?, score_threshold? : Double?, with_payload? : Bool, with_vector? : Bool) -> Array[ScoredPoint]async fn QdrantClient::replicate_shard(self : QdrantClient, name : String, shard_id : Int64, from_peer_id : Int64, to_peer_id : Int64) -> Boolasync fn QdrantClient::retrieve_points(self : QdrantClient, name : String, ids : Array[Int], with_payload? : Bool, with_vector? : Bool) -> Array[PointStruct]async fn QdrantClient::scroll_points(self : QdrantClient, name : String, limit : Int, filter? : Filter?, offset? : Int?, with_payload? : Bool, with_vector? : Bool) -> ScrollResultasync fn QdrantClient::search_points(self : QdrantClient, name : String, vector : Array[Double], limit : Int, filter? : Json?, with_payload? : Bool, with_vector? : Bool, score_threshold? : Double?, offset? : Int?, using_vector? : String?, search_params? : SearchParams?) -> Array[ScoredPoint]async fn QdrantClient::search_points_batch(self : QdrantClient, name : String, searches : Array[Json]) -> Array[Array[ScoredPoint]]async fn QdrantClient::search_points_groups(self : QdrantClient, name : String, vector : Array[Double], limit : Int, group_by : String, group_size : Int, filter? : Json?, with_payload? : Bool, with_vector? : Bool, score_threshold? : Double?, using_vector? : String?, search_params? : SearchParams?) -> Array[ScoredPointGroup]async fn QdrantClient::search_points_named(self : QdrantClient, name : String, named_vector : NamedVector, limit : Int, filter? : Json?, with_payload? : Bool, with_vector? : Bool, score_threshold? : Double?, offset? : Int?, search_params? : SearchParams?) -> Array[ScoredPoint]async fn QdrantClient::search_points_with_filter(self : QdrantClient, name : String, vector : Array[Double], limit : Int, filter : Filter, with_payload? : Bool, with_vector? : Bool, score_threshold? : Double?, offset? : Int?, using_vector? : String?, search_params? : SearchParams?) -> Array[ScoredPoint]async fn QdrantClient::search_with_filter(self : QdrantClient, name : String, vector : Array[Double], limit : Int, filter : Filter, with_payload? : Bool, with_vector? : Bool) -> Array[ScoredPoint]async fn QdrantClient::set_locks(self : QdrantClient, write : Bool, error_message? : String?) -> Unitasync fn QdrantClient::set_payload(self : QdrantClient, name : String, payload : Json, ids? : Array[Int]?, filter? : Filter?, wait? : Bool) -> Unitasync fn QdrantClient::update_collection(self : QdrantClient, name : String, update : CollectionUpdate) -> Unitasync fn QdrantClient::upsert_points(self : QdrantClient, name : String, points : Array[PointStruct], wait? : Bool) -> Unitasync fn QdrantClient::upsert_points_batch(self : QdrantClient, name : String, points : Array[PointStruct], wait? : Bool) -> Unitpub struct RaftInfo {
term : Int64?
commit : Int64?
pending_operations : Int64?
leader : Int64?
role : String?
is_voter : Bool?
}pub struct RemoteShardInfo {
shard_id : Int64
peer_id : Int64
state : String
}pub struct SearchParams {
hnsw_ef : Int?
exact : Bool?
}pub struct ServiceInfo {
version : String?
commit : String?
}pub struct ShardTransferInfo {
shard_id : Int64
from : Int64
to : Int64
method_name : String?
}pub struct SnapshotInfo {
name : String
creation_time : String?
size : Int?
}fn collection_cluster_op_body(op : String, shard_id : Int64, peer_id? : Int64?, from_peer_id? : Int64?, to_peer_id? : Int64?) -> Jsonfn join_url(base : String, path : String) -> Stringfn parse_int64(s : String) -> Int64?Install
Download zipA MoonBit client for the Qdrant vector database REST API.