Skip to Content
We are live but in Staging 🎉

Vectors — API Reference

Package: dodil.k3.vector.v1 · Service: VectorService

Direct vector writes for EXTERNAL-mode collections (created via AddVectorCollection). For PIPELINE-mode collections, these RPCs return FAILED_PRECONDITION — let Scriptum’s ingest pipeline drive embeddings instead.

RPCHTTP
InsertVectorsPOST /:bucket/vector/collections/:collection_id/vectors
UpsertVectorsPUT /:bucket/vector/collections/:collection_id/vectors
DeleteVectorsPOST /:bucket/vector/collections/:collection_id/vectors:delete

VectorRecord shape is documented at Core Concepts → VectorRecord — the dense oneof (dense_float / dense_binary / dense_float16 / dense_bfloat16 / dense_int8) must match the collection’s embedding_type.

gRPC setup — grpcurl, endpoints, reflection, and field-name casing — is covered once in Conventions → Using gRPC.

InsertVectors

Append rows. Duplicate ids cause Milvus to keep both rows (Milvus inserts are not unique-key-checked) — use UpsertVectors if you want last-write-wins on id.

Request

Dense-only (FLOAT) collection — minimal record per row:

curl -sS -X POST "https://k3.dev.dodil.io/kb-prod/vector/collections/col_a1b2.../vectors" \ -H "Authorization: Bearer $DODIL_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "bucket": "kb-prod", "collectionId": "col_a1b2...", "vectors": [ { "id": "doc-1", "denseFloat": { "values": [0.12, -0.04, 0.91, 0.33] }, "metadata": { "source": "papers/attention.pdf", "page": 4, "tags": ["transformer", "attention"] } }, { "id": "doc-2", "denseFloat": { "values": [0.18, 0.22, -0.05, 0.47] }, "metadata": { "source": "papers/bert.pdf", "page": 1, "tags": ["bert"] } } ] }'

Hybrid (BM25 sparse_mode) collection — include text so Milvus’s BM25 function can derive the sparse vector:

curl -sS -X POST "https://k3.dev.dodil.io/kb-prod/vector/collections/col_c3d4.../vectors" \ -H "Authorization: Bearer $DODIL_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "bucket": "kb-prod", "collectionId": "col_c3d4...", "vectors": [ { "id": "chunk-1", "denseFloat": { "values": [/* ... 1024 floats ... */] }, "text": "Multi-head attention allows the model to jointly attend to information from different representation subspaces.", "metadata": { "source": "papers/attention.pdf", "section": "3.2" } } ] }'

External sparse — caller supplies both dense + sparse parts of each record:

curl -sS -X POST "https://k3.dev.dodil.io/kb-prod/vector/collections/col_e5f6.../vectors" \ -H "Authorization: Bearer $DODIL_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "bucket": "kb-prod", "collectionId": "col_e5f6...", "vectors": [ { "id": "splade-1", "denseFloat": { "values": [/* dense 768 floats */] }, "sparse": { "indices": [42, 137, 1024, 8888], "values": [0.92, 0.41, 0.18, 0.07] }, "metadata": { "doc_id": "abc-123" } } ] }'

Response

{ "inserted": "2" }

inserted is the count K3 sent to Milvus successfully.

UpsertVectors

Last-write-wins on id. Existing rows are deleted, new rows inserted, in the same Milvus call.

Request

curl -sS -X PUT "https://k3.dev.dodil.io/kb-prod/vector/collections/col_a1b2.../vectors" \ -H "Authorization: Bearer $DODIL_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "bucket": "kb-prod", "collectionId": "col_a1b2...", "vectors": [ { "id": "doc-1", "denseFloat": { "values": [0.15, -0.02, 0.88, 0.35] }, "metadata": { "source": "papers/attention.pdf", "page": 4, "tags": ["transformer", "attention", "self-attention"], "version": 2 } } ] }'

Response

{ "inserted": "1", "deleted": "1" }

deleted is the count of pre-existing rows with matching ids that were replaced.

DeleteVectors

Removes rows by id. Ignored ids (not present in the collection) are silently skipped.

Request

curl -sS -X POST "https://k3.dev.dodil.io/kb-prod/vector/collections/col_a1b2.../vectors:delete" \ -H "Authorization: Bearer $DODIL_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "bucket": "kb-prod", "collectionId": "col_a1b2...", "ids": ["doc-1", "doc-2", "doc-3"] }'

Response

{ "deleted": "3" }

Constraints + gotchas

ConstraintWhat happens otherwise
Collection must be embedding_source = EXTERNALFAILED_PRECONDITION
dense oneof variant must match collection.embedding_typeINVALID_ARGUMENT
denseBinary length = dimensions / 8 bytesINVALID_ARGUMENT
denseFloat16 / denseBfloat16 length = dimensions * 2 bytesINVALID_ARGUMENT
denseInt8 length = dimensions bytesINVALID_ARGUMENT
sparse only accepted when collection.sparse_mode = EXTERNALINVALID_ARGUMENT
text only consumed when collection.sparse_mode = BM25 (otherwise ignored)no error — text is silently dropped
id non-empty, caller-suppliedINVALID_ARGUMENT on empty

For batched ingestion of large datasets, prefer UpsertVectors over InsertVectors so re-runs are idempotent (otherwise duplicates accumulate). For deletes + reinserts together, use UpsertVectors — it’s one Milvus call instead of two.


See also