-
Notifications
You must be signed in to change notification settings - Fork 0
Smart Search System
Complete semantic search implementation with OpenAI embeddings and pgvector.
The Smart Search System provides powerful semantic search capabilities using:
- OpenAI text-embedding-3-small for generating vector embeddings
- pgvector PostgreSQL extension for vector similarity search
- Hybrid search combining semantic and keyword-based approaches
- Advanced filtering by date, user, channel, content type, etc.
- Search analytics with history and saved searches
- Background workers for asynchronous embedding generation
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Frontend Layer β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β SmartSearch.tsx β SearchFilters.tsx β SavedSearches.tsxβ
ββββββββββββββ¬βββββββββββββββββββββ¬βββββββββββββββ¬βββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β API Layer β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β /api/ai/search β /api/ai/embed β /api/search/ β
β /api/workers/embeddings β /api/search/suggestions β
ββββββββββββββ¬βββββββββββββββββββββ¬βββββββββββββββ¬βββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Service Layer β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β smart-search.ts β embeddings.ts β vector-store.ts β filters.tsβ
ββββββββββββββ¬βββββββββββββββββββββ¬βββββββββββββββ¬βββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Database Layer β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β PostgreSQL + pgvector β Messages β Embeddings β Queue β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Tables:
-
nchat_messages.embedding- Vector embeddings (1536 dimensions) -
nchat_embedding_cache- Cache for generated embeddings -
nchat_embedding_queue- Queue for background processing -
nchat_search_history- User search history -
nchat_saved_searches- Saved search queries
Indexes:
- HNSW index on embeddings for fast similarity search
- Composite indexes for filtered searches
- Full-text search indexes for hybrid search
Functions:
-
nchat_search_messages_semantic()- Semantic similarity search -
nchat_find_similar_messages()- Find related messages -
nchat_queue_embedding()- Queue message for embedding -
nchat_embedding_queue_stats()- Queue statistics -
nchat_clean_embedding_cache()- Cache cleanup
Features:
- OpenAI API integration
- Batch embedding generation
- LRU cache with automatic eviction
- Token usage tracking
- Cost estimation
- Error handling and retry logic
Usage:
import { getEmbeddingService } from '@/lib/ai/embeddings'
const service = getEmbeddingService()
// Generate single embedding
const result = await service.generateEmbedding({
text: 'Hello world',
})
// Generate batch embeddings
const batchResult = await service.generateBatchEmbeddings({
texts: ['Message 1', 'Message 2', 'Message 3'],
})
// Get statistics
const stats = service.getStats()
console.log(`Cache hit rate: ${stats.hitRate}%`)
console.log(`Total cost: $${stats.totalCost}`)Features:
- PostgreSQL connection pooling
- Vector similarity search
- Embedding CRUD operations
- Queue management
- Coverage statistics
Usage:
import { getVectorStore } from '@/lib/database/vector-store'
const vectorStore = getVectorStore()
// Search by semantic similarity
const results = await vectorStore.searchSimilar('how to deploy', {
similarityThreshold: 0.7,
limit: 20,
channelId: 'abc-123',
dateFrom: new Date('2024-01-01'),
})
// Find similar messages
const similar = await vectorStore.findSimilarMessages('message-id', {
threshold: 0.8,
limit: 10,
})
// Store embedding
await vectorStore.storeEmbedding('message-id', embedding, 'text-embedding-3-small')Features:
- Fluent API for building search filters
- SQL generation with parameterization
- Filter validation
- Support for complex queries
Usage:
import { createFilterBuilder } from '@/lib/search/filters'
const builder = createFilterBuilder()
.query('deployment issues')
.dateRange(new Date('2024-01-01'), new Date('2024-12-31'))
.fromUsers(['user-1', 'user-2'])
.inChannels(['channel-1'])
.hasAttachments(true)
.isPinned(true)
.semantic(0.75)
.sort('hybrid')
.limit(50)
const { sql, params } = builder.buildQuery()Features:
- Background processing of embedding queue
- Configurable batch size and polling interval
- Automatic retry on failures
- Statistics tracking
- Graceful shutdown
Usage:
import { startEmbeddingWorker } from '@/lib/workers/embedding-worker'
// Start worker
const worker = await startEmbeddingWorker({
batchSize: 10,
pollIntervalMs: 5000,
maxRetries: 3,
})
// Get stats
const stats = worker.getStats()
console.log(`Processed: ${stats.totalProcessed}`)
console.log(`Success rate: ${stats.totalSuccess / stats.totalProcessed}%`)
// Stop worker
await worker.stop()Search messages with natural language queries.
Request:
{
"query": "how to deploy the application",
"messages": [...],
"options": {
"limit": 20,
"threshold": 0.7,
"includeContext": true,
"filters": {
"channelId": "abc-123",
"dateFrom": "2024-01-01"
}
}
}Response:
{
"success": true,
"results": [
{
"message": {...},
"score": 0.92,
"matchType": "semantic",
"highlights": ["..."],
"context": {
"before": [...],
"after": [...]
}
}
],
"count": 15,
"provider": "openai",
"isSemanticSearch": true
}Generate embeddings for text content.
Request:
{
"texts": ["First message content", "Second message content"],
"model": "text-embedding-3-small"
}Response:
{
"success": true,
"embeddings": [[...], [...]],
"model": "text-embedding-3-small",
"usage": {
"promptTokens": 24,
"totalTokens": 24
},
"cached": 1,
"generated": 1
}Get search suggestions based on history.
Request:
GET /api/search/suggestions?q=deploy&limit=10&userId=user-123
Response:
{
"success": true,
"suggestions": [
{
"query": "deployment issues",
"count": 15,
"lastUsed": "2024-01-20T10:30:00Z"
}
]
}Get embedding worker status and stats.
Response:
{
"success": true,
"worker": {
"isRunning": true,
"stats": {
"totalProcessed": 1523,
"totalSuccess": 1520,
"totalFailed": 3,
"averageProcessingTime": 245
}
},
"queue": {
"pending": 42,
"processing": 10,
"failed": 3,
"completedToday": 256
},
"coverage": {
"total": 10000,
"withEmbeddings": 9500,
"needingEmbeddings": 500,
"percentage": 95.0
}
}Start or stop the embedding worker.
Request:
{
"action": "start",
"config": {
"batchSize": 10,
"pollIntervalMs": 5000
}
}# Required for semantic search
OPENAI_API_KEY=sk-...
# Database connection
DATABASE_URL=postgresql://user:pass@localhost:5432/db
# Optional: Custom model
NEXT_PUBLIC_EMBEDDING_MODEL=text-embedding-3-smallRun the migration to set up pgvector:
# Via nself CLI
cd .backend
nself db migrate up
# Or directly with psql
psql -U postgres -d your_database -f migrations/028_pgvector_semantic_search.sqlStart the embedding worker in your application:
// In your server startup or API route
import { startEmbeddingWorker } from '@/lib/workers/embedding-worker'
await startEmbeddingWorker({
batchSize: 20, // Process 20 messages at a time
pollIntervalMs: 10000, // Check queue every 10 seconds
idleDelayMs: 60000, // Wait 60 seconds when queue is empty
maxRetries: 3, // Retry failed embeddings 3 times
})With 10,000 messages and text-embedding-3-small:
| Operation | Time | Cost |
|---|---|---|
| Generate embedding (single) | ~150ms | $0.000003 |
| Generate embeddings (batch 100) | ~2s | $0.0003 |
| Semantic search (no filters) | ~50ms | - |
| Semantic search (with filters) | ~30ms | - |
| Hybrid search | ~80ms | - |
- Use batch operations - Process embeddings in batches of 50-100
- Enable caching - Reduces API calls by 70-90%
- Use HNSW index - Faster than IVFFlat for most workloads
- Filter before searching - Reduces vector comparison overhead
- Adjust similarity threshold - Higher = faster but fewer results
- Horizontal scaling: Run multiple worker instances with different configs
- Vertical scaling: Increase batch size and worker concurrency
- Database scaling: Use connection pooling (configured for 20 connections)
- Cost control: Set daily spending limits in OpenAI dashboard
The smart search supports advanced query syntax:
# Basic text search
deployment issues
# Filter by user
from:john deployment
# Filter by channel
in:general announcement
# Date range
after:2024-01-01 before:2024-12-31 release
# Content type filters
has:link documentation
has:file has:image screenshots
is:pinned important
# Combine filters
from:alice in:engineering has:code after:2024-01-01
Check queue stats to monitor processing:
const vectorStore = getVectorStore()
const stats = await vectorStore.getQueueStats()
if (stats.failedCount > 100) {
console.warn('High failure rate detected!')
}
if (stats.pendingCount > 1000) {
console.warn('Queue backlog growing!')
}Monitor embedding coverage:
const coverage = await vectorStore.getCoverageStats()
console.log(`Coverage: ${coverage.coveragePercentage}%`)
console.log(`Needing embeddings: ${coverage.messagesNeedingEmbeddings}`)Track embedding costs:
const service = getEmbeddingService()
const stats = service.getStats()
console.log(`Total tokens: ${stats.totalTokens}`)
console.log(`Total cost: $${stats.totalCost.toFixed(4)}`)
console.log(`Cache hit rate: ${(stats.hitRate * 100).toFixed(1)}%`)1. "pgvector extension not found"
-- Install pgvector extension
CREATE EXTENSION IF NOT EXISTS vector;2. "OpenAI API key not configured"
# Set environment variable
export OPENAI_API_KEY=sk-...3. "Worker not processing queue"
// Check worker status
const worker = getEmbeddingWorker()
console.log(worker.isActive()) // Should be true
// Restart if needed
await worker.stop()
await worker.start()4. "Slow semantic search"
-- Verify HNSW index exists
SELECT indexname, indexdef
FROM pg_indexes
WHERE tablename = 'nchat_messages'
AND indexname LIKE '%embedding%';
-- Rebuild if missing
CREATE INDEX idx_messages_embedding_hnsw
ON nchat_messages
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);5. "High API costs"
// Increase cache size
const service = new EmbeddingService()
// Cache stores up to 10,000 embeddings by default
// Use smaller batch sizes
const worker = startEmbeddingWorker({
batchSize: 5, // Smaller batches = more caching opportunities
})- Support for multiple embedding models
- Cross-lingual search with multilingual models
- Document/file content search
- Voice message transcription and search
- Search result clustering
- Personalized search ranking
- A/B testing framework for search quality
- Search analytics dashboard
Part of nself-chat v0.7.0
nself-chat v0.3.0 | GitHub | Issues | Discussions | Demo
Edit this page | MIT License | Β© 2026
(See π Security section below for 2FA, PIN Lock, and security audits.)
(Search lives in π Reference below.)
- π¬ Advanced Messaging
- π E2EE Setup
- π Search Setup
- π Call Management
- πΊ Live Streaming
- π₯οΈ Screen Sharing
- πΉ Video Calling
- ποΈ Voice Calling
- π± Mobile Optimization
- π§ͺ Testing
- π i18n
- π API Overview
- π Complete Reference
- π» API Examples
- π€ Bot API
- π Auth API
- π GraphQL Schema
- π Deployment Overview
- π³ Docker
- βΈοΈ Kubernetes
- β Helm Charts
- β Production Checklist
- π Production Validation
- π’ Multi-Tenant
- ποΈ Architecture
- π Diagrams
- ποΈ Database Schema
- π Project Structure
- π TypeScript Types
- π SPORT Reference
- π 2FA
- π¬ Messaging
- π Call Management
- π Call State Machine
- π E2EE
- πΊ Live Streaming
- π± Mobile Calls
- π PIN Lock
- π Polls
- π₯οΈ Screen Sharing
- π Search
- π Social Media
- ποΈ Voice Calling
- π Security Overview
- π‘οΈ Security Audit
- β‘ Performance
- π Best Practices
- π 2FA
- π PIN Lock
- π E2EE
- π‘οΈ E2EE Audit
v1.0.0 β’ 2026