Files
Portfolio/blog-posts/43-redis-stack-vector-database.md
damjan_savicandClaude Opus 4.5 e1bbe5455d Initial commit: Portfolio Website
Vollständige Next.js 15 Portfolio-Website mit:
- Blog-System mit 100+ Artikeln
- Supabase-Integration
- Responsive Design mit Tailwind CSS
- TypeScript-Konfiguration
- Testing-Setup mit Vitest und Playwright

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 15:07:20 +01:00

480 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Redis Stack: In-Memory Vector Database für AI
**Meta-Description:** Redis als Vector Database nutzen. RediSearch, RedisJSON, Vector Set und High-Performance AI-Anwendungen.
**Keywords:** Redis Stack, Vector Database, RediSearch, RedisJSON, In-Memory Database, AI Cache, Semantic Search
---
## Einführung
Redis 8 vereint alle Module in einem Package: **Vector Search, JSON, Full-Text Search** und mehr. Als In-Memory Database bietet Redis ultra-niedrige Latenz für AI-Anwendungen ideal für Caching, Session Management und Echtzeit-Suche.
---
## Redis 8 Stack
```
┌─────────────────────────────────────────────────────────────┐
│ REDIS 8 STACK │
├─────────────────────────────────────────────────────────────┤
│ │
│ Core Data Structures: │
│ ├── Strings, Lists, Sets, Hashes, Sorted Sets │
│ ├── Streams (Event Streaming) │
│ └── HyperLogLog, Bitmaps │
│ │
│ New in Redis 8: │
│ ├── Vector Set (Beta) - Similarity Search │
│ ├── JSON - Native JSON Document Store │
│ ├── Time Series - Metrics & Monitoring │
│ └── Probabilistic Structures │
│ ├── Bloom Filter │
│ ├── Cuckoo Filter │
│ ├── Count-Min Sketch │
│ ├── Top-K │
│ └── T-Digest │
│ │
│ Search Capabilities: │
│ ├── Full-Text Search │
│ ├── Vector Search (FLAT, HNSW, SVS-VAMANA) │
│ ├── Numeric/Tag Filtering │
│ └── Geospatial Queries │
│ │
│ Performance: │
│ └── Sub-Millisecond Latency (In-Memory) │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
## Setup
```bash
# Docker
docker run -d --name redis-stack -p 6379:6379 -p 8001:8001 redis/redis-stack:latest
# Redis Cloud (Managed)
# https://redis.com/try-free/
```
```typescript
// lib/redis.ts
import { createClient } from 'redis';
const redis = createClient({
url: process.env.REDIS_URL || 'redis://localhost:6379'
});
redis.on('error', (err) => console.error('Redis Client Error', err));
await redis.connect();
export default redis;
```
---
## Vector Search mit Hash
```typescript
import redis from '@/lib/redis';
import { SchemaFieldTypes, VectorAlgorithms } from 'redis';
// 1. Index erstellen
async function createVectorIndex() {
try {
await redis.ft.create('idx:docs', {
'$.title': {
type: SchemaFieldTypes.TEXT,
AS: 'title'
},
'$.content': {
type: SchemaFieldTypes.TEXT,
AS: 'content'
},
'$.category': {
type: SchemaFieldTypes.TAG,
AS: 'category'
},
'$.embedding': {
type: SchemaFieldTypes.VECTOR,
AS: 'embedding',
ALGORITHM: VectorAlgorithms.HNSW,
TYPE: 'FLOAT32',
DIM: 1536,
DISTANCE_METRIC: 'COSINE'
}
}, {
ON: 'JSON',
PREFIX: 'doc:'
});
console.log('Index created');
} catch (e) {
if ((e as Error).message.includes('Index already exists')) {
console.log('Index already exists');
} else {
throw e;
}
}
}
// 2. Document speichern (JSON)
async function saveDocument(
id: string,
title: string,
content: string,
category: string,
embedding: number[]
) {
await redis.json.set(`doc:${id}`, '$', {
title,
content,
category,
embedding
});
}
// 3. Vector Search
async function searchSimilar(
queryEmbedding: number[],
limit: number = 5
) {
const results = await redis.ft.search('idx:docs', '*=>[KNN $K @embedding $BLOB AS score]', {
PARAMS: {
K: limit.toString(),
BLOB: Buffer.from(new Float32Array(queryEmbedding).buffer)
},
RETURN: ['title', 'content', 'score'],
SORTBY: {
BY: 'score',
DIRECTION: 'ASC' // Lower = more similar for COSINE
},
DIALECT: 2
});
return results.documents.map(doc => ({
id: doc.id,
title: doc.value.title,
content: doc.value.content,
score: 1 - parseFloat(doc.value.score as string) // Convert to similarity
}));
}
// 4. Hybrid Search (Vector + Filter)
async function searchWithFilter(
queryEmbedding: number[],
category: string,
limit: number = 5
) {
const results = await redis.ft.search(
'idx:docs',
`(@category:{${category}})=>[KNN $K @embedding $BLOB AS score]`,
{
PARAMS: {
K: limit.toString(),
BLOB: Buffer.from(new Float32Array(queryEmbedding).buffer)
},
RETURN: ['title', 'content', 'category', 'score'],
DIALECT: 2
}
);
return results.documents;
}
```
---
## Vector Set (Redis 8 Beta)
```typescript
// Neuer Datentyp in Redis 8 - Inspiriert von Sorted Sets
// Vector hinzufügen
await redis.sendCommand([
'VADD', 'products',
'VECTOR', ...embedding.map(v => v.toString()),
'product:123'
]);
// Ähnliche Vektoren finden
const similar = await redis.sendCommand([
'VSIM', 'products',
'VECTOR', ...queryEmbedding.map(v => v.toString()),
'COUNT', '10'
]);
// Vorteile von Vector Set:
// - Einfachere API als RediSearch
// - Optimiert für Similarity Search
// - Von Salvatore Sanfilippo (Redis Creator) entwickelt
```
---
## Session Cache mit Vector Search
```typescript
// Kombination: Session Management + Semantic Search
interface UserSession {
userId: string;
lastQuery: string;
queryEmbedding: number[];
searchHistory: string[];
createdAt: number;
expiresAt: number;
}
// Session speichern
async function saveSession(session: UserSession) {
const key = `session:${session.userId}`;
await redis.json.set(key, '$', session);
await redis.expireAt(key, session.expiresAt);
}
// Ähnliche Queries aus History finden
async function findSimilarPastQueries(
userId: string,
currentQueryEmbedding: number[]
) {
// Alle Sessions mit Query-History durchsuchen
const results = await redis.ft.search(
'idx:sessions',
'*=>[KNN 5 @queryEmbedding $BLOB AS score]',
{
PARAMS: {
BLOB: Buffer.from(new Float32Array(currentQueryEmbedding).buffer)
},
RETURN: ['userId', 'lastQuery', 'score'],
DIALECT: 2
}
);
return results.documents;
}
```
---
## Full-Text + Vector Hybrid Search
```typescript
// Index mit Text + Vector
await redis.ft.create('idx:articles', {
'$.title': {
type: SchemaFieldTypes.TEXT,
AS: 'title',
WEIGHT: 2.0
},
'$.body': {
type: SchemaFieldTypes.TEXT,
AS: 'body'
},
'$.tags': {
type: SchemaFieldTypes.TAG,
AS: 'tags'
},
'$.embedding': {
type: SchemaFieldTypes.VECTOR,
AS: 'embedding',
ALGORITHM: VectorAlgorithms.HNSW,
TYPE: 'FLOAT32',
DIM: 1536,
DISTANCE_METRIC: 'COSINE'
}
}, {
ON: 'JSON',
PREFIX: 'article:'
});
// Hybrid Search: Text + Vector
async function hybridSearch(
textQuery: string,
queryEmbedding: number[],
limit: number = 10
) {
// Full-Text Search
const textResults = await redis.ft.search(
'idx:articles',
`@title|body:(${textQuery})`,
{
RETURN: ['title', 'body'],
LIMIT: { from: 0, size: limit }
}
);
// Vector Search
const vectorResults = await redis.ft.search(
'idx:articles',
'*=>[KNN $K @embedding $BLOB AS vector_score]',
{
PARAMS: {
K: limit.toString(),
BLOB: Buffer.from(new Float32Array(queryEmbedding).buffer)
},
RETURN: ['title', 'body', 'vector_score'],
DIALECT: 2
}
);
// Scores kombinieren (RRF - Reciprocal Rank Fusion)
const combined = new Map<string, { doc: any; score: number }>();
const k = 60; // RRF constant
textResults.documents.forEach((doc, rank) => {
const score = 1 / (k + rank + 1);
combined.set(doc.id, {
doc: doc.value,
score: score
});
});
vectorResults.documents.forEach((doc, rank) => {
const vectorScore = 1 / (k + rank + 1);
const existing = combined.get(doc.id);
if (existing) {
existing.score += vectorScore;
} else {
combined.set(doc.id, {
doc: doc.value,
score: vectorScore
});
}
});
return Array.from(combined.values())
.sort((a, b) => b.score - a.score)
.slice(0, limit);
}
```
---
## Caching für AI Embeddings
```typescript
// Embedding Cache - vermeidet wiederholte API-Calls
async function getOrCreateEmbedding(
text: string,
generateFn: (text: string) => Promise<number[]>
): Promise<number[]> {
// Hash als Cache Key
const hash = await crypto.subtle.digest(
'SHA-256',
new TextEncoder().encode(text)
);
const cacheKey = `emb:${Buffer.from(hash).toString('hex').slice(0, 16)}`;
// Cache Check
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
// Generate & Cache
const embedding = await generateFn(text);
await redis.set(cacheKey, JSON.stringify(embedding), {
EX: 60 * 60 * 24 * 7 // 7 Tage TTL
});
return embedding;
}
// RAG Response Cache
async function getCachedRAGResponse(
queryEmbedding: number[],
threshold: number = 0.95
) {
// Suche nach sehr ähnlichen vorherigen Queries
const results = await redis.ft.search(
'idx:rag_cache',
'*=>[KNN 1 @queryEmbedding $BLOB AS score]',
{
PARAMS: {
BLOB: Buffer.from(new Float32Array(queryEmbedding).buffer)
},
RETURN: ['query', 'response', 'score'],
DIALECT: 2
}
);
if (results.documents.length > 0) {
const similarity = 1 - parseFloat(results.documents[0].value.score as string);
if (similarity >= threshold) {
return results.documents[0].value.response;
}
}
return null;
}
```
---
## Pub/Sub für Real-Time Updates
```typescript
// Vector Search + Real-Time Updates
// Publisher
async function publishNewDocument(doc: Document) {
// In Redis speichern
await saveDocument(doc.id, doc.title, doc.content, doc.category, doc.embedding);
// Event publishen
await redis.publish('documents:new', JSON.stringify({
id: doc.id,
title: doc.title,
category: doc.category
}));
}
// Subscriber
const subscriber = redis.duplicate();
await subscriber.connect();
await subscriber.subscribe('documents:new', (message) => {
const doc = JSON.parse(message);
console.log('New document:', doc.title);
// UI Update, Cache Invalidation, etc.
});
```
---
## Fazit
Redis Stack bietet:
1. **Sub-Millisecond Latency**: In-Memory für Echtzeit-AI
2. **Unified Platform**: Vector, JSON, Full-Text in einem System
3. **Vector Set**: Neuer Datentyp für einfache Similarity Search
4. **Caching Layer**: Ideal für Embedding-Caches
Perfekt als High-Performance Layer vor AI-Anwendungen.
---
## Bildprompts
1. "In-memory database with vectors flowing at high speed, performance concept"
2. "Redis logo with vector arrows and AI neural network, modern database"
3. "Cache layer between AI model and application, latency optimization"
---
## Quellen
- [Redis Vector Database](https://redis.io/solutions/vector-database/)
- [Redis 8 GA Announcement](https://redis.io/blog/redis-8-ga/)
- [RediSearch Documentation](https://redis.io/docs/latest/develop/ai/search-and-query/)
- [Redis Vector Search Concepts](https://redis.io/docs/latest/develop/ai/search-and-query/vectors/)