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.
| RPC | HTTP |
|---|---|
InsertVectors | POST /:bucket/vector/collections/:collection_id/vectors |
UpsertVectors | PUT /:bucket/vector/collections/:collection_id/vectors |
DeleteVectors | POST /: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
HTTP
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
HTTP
{
"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
HTTP
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
HTTP
{
"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
HTTP
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
HTTP
{
"deleted": "3"
}Constraints + gotchas
| Constraint | What happens otherwise |
|---|---|
Collection must be embedding_source = EXTERNAL | FAILED_PRECONDITION |
dense oneof variant must match collection.embedding_type | INVALID_ARGUMENT |
denseBinary length = dimensions / 8 bytes | INVALID_ARGUMENT |
denseFloat16 / denseBfloat16 length = dimensions * 2 bytes | INVALID_ARGUMENT |
denseInt8 length = dimensions bytes | INVALID_ARGUMENT |
sparse only accepted when collection.sparse_mode = EXTERNAL | INVALID_ARGUMENT |
text only consumed when collection.sparse_mode = BM25 (otherwise ignored) | no error — text is silently dropped |
id non-empty, caller-supplied | INVALID_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
- Collections — how to create the EXTERNAL collection this RPC writes to
- Search — query the vectors you wrote here
- Core Concepts → VectorRecord — full record shape + all five dense variants
- Recipes → External Collection — end-to-end “BYO embeddings” walkthrough
grpcurlreference — full flag set + reflection-disabled fallbacks