Skip to content
Docs · Data

Vector DB

Embedding collections for semantic search and RAG. Send vectors, or send text and Harakumo embeds it; filter by metadata and split a collection per user with namespaces.

View as Markdown
All topics
On this page

Each collection is its own vector index. The default is 768 dimensions — what Harakumo's default embedding model (bge-base) produces, so text you send fits as-is. Choose 384 (bge-small) or 1,024 (bge-large) to match those models, or 1,536 for vectors you make elsewhere; larger is refused.

embed("query")nearest matches#42 0.91#7 0.88#19 0.84semantic search over your embeddings

In plain words

Search by meaning instead of exact words. You add your texts, and it finds the ones closest in meaning to what someone asks.

For example: Someone types "how do I get my money back" into a help center and finds the article called "Refunds".

Embed, upsert, query

SDK
const { collection } = await hk.vectors.create(project.id, {
  name: 'docs', dimensions: 768, metric: 'cosine',
  metadataIndexes: [{ propertyName: 'lang', indexType: 'string' }],
});

// Send text and let Harakumo embed it (metered on AI credits), or send your own "values".
await hk.vectors.upsert(collection.id, [
  { id: 'doc-1', text: 'Peaches are in season in July.', metadata: { lang: 'en' } },
  { id: 'doc-2', text: 'Mangoes ripen best at room temperature.', metadata: { lang: 'en' } },
]);

const { matches } = await hk.vectors.query(collection.id, {
  text: 'when can I buy peaches?', topK: 3, filter: { lang: 'en' }, returnMetadata: 'all',
});

Namespaces and filters

  • Give each vector a namespace (one per end user, say); a query that names the namespace sees only its vectors.
  • Filters work on metadata fields made filterable with metadataIndexes at create time, or later with POST /api/vectors/:id { action: "index-metadata", propertyName, indexType }. Only vectors written after a field is indexed are filterable. Filtering on a field that is not indexed is a 400 that says so.
  • Delete vectors with POST /api/vectors/:id { action: "delete", ids: [...] }.

Limits

  • Upsert up to 1,000 vectors per request (100 when sending text); metadata up to 10 KB per vector.
  • topK up to 100, or 50 when returning full metadata or values.
  • Upserts are applied in the background: new vectors become searchable in about a minute, and the upsert answer says so. GET /api/vectors/:id reports the index's own count, which trails new writes by as much.
  • Collections per plan: 1 hobby, 10 pro, 25 team, 100 scale. Vectors per collection: 10,000 hobby, 1,000,000 pro, 1,000,000 team, 1,000,000 scale; a write that would pass it answers 402 plan_limit and writes nothing. Near the limit every vector sent counts as new until the index has processed it, even one that replaces an existing id, and a delete makes room once the index has processed it.
  • Keys: a key limited to the project works for everything here; a read-only key can query but not upsert or delete.

Reference

SDK
const { embeddings } = await hk.ai.embed(['fresh mango', 'ripe banana'], 'bge-base');   // 768 dims
await hk.vectors.upsert(collectionId, [{ id: 'a', values: embeddings[0], metadata: { title: 'Mango' } }]);
const { matches } = await hk.vectors.query(collectionId, { vector: embeddings[1], topK: 5 });