# 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(); 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 ): Promise { // 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/)