@mastra/core
Version:
Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack.
294 lines (210 loc) • 7.76 kB
Markdown
# Upstash vector store
The UpstashVector class provides vector search using [Upstash Vector](https://upstash.com/vector), a serverless vector database service that provides vector similarity search with metadata filtering capabilities and hybrid search support.
## Constructor options
**url** (`string`): Upstash Vector database URL
**token** (`string`): Upstash Vector API token
## Methods
### `createIndex()`
Note: This method is a no-op for Upstash as indexes are created automatically.
**indexName** (`string`): Name of the index to create
**dimension** (`number`): Vector dimension (must match your embedding model)
**metric** (`'cosine' | 'euclidean' | 'dotproduct'`): Distance metric for similarity search (Default: `cosine`)
### `upsert()`
**indexName** (`string`): Name of the index to upsert into
**vectors** (`number[][]`): Array of embedding vectors
**sparseVectors** (`{ indices: number[], values: number[] }[]`): Array of sparse vectors for hybrid search. Each sparse vector must have matching indices and values arrays.
**metadata** (`Record<string, any>[]`): Metadata for each vector
**ids** (`string[]`): Optional vector IDs (auto-generated if not provided)
### `query()`
**indexName** (`string`): Name of the index to query
**queryVector** (`number[]`): Query vector to find similar vectors
**sparseVector** (`{ indices: number[], values: number[] }`): Optional sparse vector for hybrid search. Must have matching indices and values arrays.
**topK** (`number`): Number of results to return (Default: `10`)
**filter** (`Record<string, any>`): Metadata filters for the query
**includeVector** (`boolean`): Whether to include vectors in the results (Default: `false`)
**fusionAlgorithm** (`FusionAlgorithm`): Algorithm used to combine dense and sparse search results in hybrid search (e.g., RRF - Reciprocal Rank Fusion)
**queryMode** (`QueryMode`): Search mode: 'DENSE' for dense-only, 'SPARSE' for sparse-only, or 'HYBRID' for combined search
### `listIndexes()`
Returns an array of index names (namespaces) as strings.
### `describeIndex()`
**indexName** (`string`): Name of the index to describe
Returns:
```typescript
interface IndexStats {
dimension: number
count: number
metric: 'cosine' | 'euclidean' | 'dotproduct'
}
```
### `deleteIndex()`
**indexName** (`string`): Name of the index (namespace) to delete
### `updateVector()`
**indexName** (`string`): Name of the index to update
**id** (`string`): ID of the item to update
**update** (`object`): Update object containing vector, sparse vector, and/or metadata
The `update` object can have the following properties:
- `vector` (optional): An array of numbers representing the new dense vector.
- `sparseVector` (optional): A sparse vector object with `indices` and `values` arrays for hybrid indexes.
- `metadata` (optional): A record of key-value pairs for metadata.
### `deleteVector()`
**indexName** (`string`): Name of the index from which to delete the item
**id** (`string`): ID of the item to delete
Attempts to delete an item by its ID from the specified index. Logs an error message if the deletion fails.
## Hybrid vector search
Upstash Vector supports hybrid search that combines semantic search (dense vectors) with keyword-based search (sparse vectors) for improved relevance and accuracy.
### Basic Hybrid Usage
```typescript
import { UpstashVector } from '@mastra/upstash'
const vectorStore = new UpstashVector({
id: 'upstash-vector',
url: process.env.UPSTASH_VECTOR_URL,
token: process.env.UPSTASH_VECTOR_TOKEN,
})
// Upsert vectors with both dense and sparse components
const denseVectors = [
[0.1, 0.2, 0.3],
[0.4, 0.5, 0.6],
]
const sparseVectors = [
{ indices: [1, 5, 10], values: [0.8, 0.6, 0.4] },
{ indices: [2, 6, 11], values: [0.7, 0.5, 0.3] },
]
await vectorStore.upsert({
indexName: 'hybrid-index',
vectors: denseVectors,
sparseVectors: sparseVectors,
metadata: [{ title: 'Document 1' }, { title: 'Document 2' }],
})
// Query with hybrid search
const results = await vectorStore.query({
indexName: 'hybrid-index',
queryVector: [0.1, 0.2, 0.3],
sparseVector: { indices: [1, 5], values: [0.9, 0.7] },
topK: 10,
})
```
### Advanced Hybrid Search Options
```typescript
import { FusionAlgorithm, QueryMode } from '@upstash/vector'
// Query with specific fusion algorithm
const fusionResults = await vectorStore.query({
indexName: 'hybrid-index',
queryVector: [0.1, 0.2, 0.3],
sparseVector: { indices: [1, 5], values: [0.9, 0.7] },
fusionAlgorithm: FusionAlgorithm.RRF,
topK: 10,
})
// Dense-only search
const denseResults = await vectorStore.query({
indexName: 'hybrid-index',
queryVector: [0.1, 0.2, 0.3],
queryMode: QueryMode.DENSE,
topK: 10,
})
// Sparse-only search
const sparseResults = await vectorStore.query({
indexName: 'hybrid-index',
queryVector: [0.1, 0.2, 0.3], // Still required for index structure
sparseVector: { indices: [1, 5], values: [0.9, 0.7] },
queryMode: QueryMode.SPARSE,
topK: 10,
})
```
### Updating Hybrid Vectors
```typescript
// Update both dense and sparse components
await vectorStore.updateVector({
indexName: 'hybrid-index',
id: 'vector-id',
update: {
vector: [0.2, 0.3, 0.4],
sparseVector: { indices: [2, 7, 12], values: [0.9, 0.8, 0.6] },
metadata: { title: 'Updated Document' },
},
})
```
## Response types
Query results are returned in this format:
```typescript
interface QueryResult {
id: string
score: number
metadata: Record<string, any>
vector?: number[] // Only included if includeVector is true
}
```
## Error handling
The store throws typed errors that can be caught:
```typescript
try {
await store.query({
indexName: 'index_name',
queryVector: queryVector,
})
} catch (error) {
if (error instanceof VectorStoreError) {
console.log(error.code) // 'connection_failed' | 'invalid_dimension' | etc
console.log(error.details) // Additional error context
}
}
```
## Environment variables
Required environment variables:
- `UPSTASH_VECTOR_URL`: Your Upstash Vector database URL
- `UPSTASH_VECTOR_TOKEN`: Your Upstash Vector API token
## Usage example
### Local embeddings with fastembed
Embeddings are numeric vectors used by memory's `semanticRecall` to retrieve related messages by meaning (not keywords). This setup uses `@mastra/fastembed` to generate vector embeddings.
Install `fastembed` to get started:
**npm**:
```bash
npm install @mastra/fastembed@latest
```
**pnpm**:
```bash
pnpm add @mastra/fastembed@latest
```
**Yarn**:
```bash
yarn add @mastra/fastembed@latest
```
**Bun**:
```bash
bun add @mastra/fastembed@latest
```
Add the following to your agent:
```typescript
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'
import { UpstashStore, UpstashVector } from '@mastra/upstash'
import { fastembed } from '@mastra/fastembed'
export const upstashAgent = new Agent({
id: 'upstash-agent',
name: 'Upstash Agent',
instructions:
'You are an AI agent with the ability to automatically recall memories from previous interactions.',
model: 'openai/gpt-5.4',
memory: new Memory({
storage: new UpstashStore({
id: 'upstash-agent-storage',
url: process.env.UPSTASH_REDIS_REST_URL!,
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
}),
vector: new UpstashVector({
id: 'upstash-agent-vector',
url: process.env.UPSTASH_VECTOR_REST_URL!,
token: process.env.UPSTASH_VECTOR_REST_TOKEN!,
}),
embedder: fastembed,
options: {
lastMessages: 10,
semanticRecall: {
topK: 3,
messageRange: 2,
},
},
}),
})
```
## Related
- [Metadata Filters](https://mastra.ai/reference/rag/metadata-filters)