brainy/src/storage/adapters/optimizedS3Search.ts
David Snelling 9c87982a7d 🧠 Brainy 2.0.0 - Zero-Configuration AI Database with Triple Intelligence™
MAJOR RELEASE: Complete evolution of Brainy with groundbreaking features and performance.

🎯 KEY FEATURES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Triple Intelligence™ Engine
  - Unified Vector + Metadata + Graph search
  - O(log n) performance on all operations
  - 3ms average search latency at any scale

 API Consolidation
  - 15+ search methods → 2 clean APIs
  - search() for vector similarity
  - find() for natural language queries

 Natural Language Processing
  - 220+ pre-computed NLP patterns
  - Instant context understanding
  - "Show me recent React components with tests"

 Zero Configuration
  - Works instantly, no setup required
  - Built-in embedding models (no API keys)
  - Smart defaults for everything
  - Automatic optimization

 Enterprise Features (Free for Everyone)
  - Scales to 10M+ items
  - Write-Ahead Logging (WAL) for durability
  - Distributed architecture with sharding
  - Read/write separation
  - Connection pooling & request deduplication
  - Built-in monitoring & health checks

 Universal Compatibility
  - Node.js, Browser, Edge Workers
  - 4 Storage Adapters (Memory, FileSystem, OPFS, S3)
  - TypeScript with full type safety
  - Worker-based embeddings

📦 WHAT'S INCLUDED:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• Core AI Database with HNSW indexing
• 19 Production-ready augmentations
• Universal Memory Manager
• Complete CLI with all commands
• Brain Cloud integration (soulcraft.com)
• Comprehensive documentation
• 52 test files with 400+ tests
• Migration guide from 1.x

📊 PERFORMANCE:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• Initialize: 450ms (24MB memory)
• Search: 3ms average (up to 10M items)
• Metadata Filter: 0.8ms (O(log n))
• Bulk Import: 2.3s per 1000 items
• Production Scale: 5.8ms at 10M items

🔧 TECHNICAL IMPROVEMENTS:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• TypeScript compilation: 153 errors → 0
• Memory usage: 200MB → 24MB baseline
• Circular dependencies resolved
• Worker thread communication fixed
• Storage adapter consistency
• Request coalescing for 3x performance

🛠️ CLI FEATURES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• brainy add - Smart data ingestion
• brainy find - Natural language search
• brainy search - Vector similarity
• brainy chat - AI conversation mode
• brainy cloud - Brain Cloud integration
• brainy augment - Manage extensions
• 100% API compatibility

📚 DOCUMENTATION:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• Professional README with examples
• Quick Start guide (5 minutes)
• Enterprise Features guide
• Migration guide from 1.x
• API reference
• Architecture documentation

🌟 USE CASES:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• AI memory layer for chatbots
• Semantic document search
• Code intelligence platforms
• Knowledge management systems
• Real-time recommendation engines
• Customer support automation

MIT License - Enterprise features included free for everyone.
No premium tiers, no paywalls, no limits.

Built with ❤️ by the Brainy community.
Visit https://soulcraft.com for Brain Cloud integration.
2025-08-26 12:32:21 -07:00

339 lines
No EOL
9.2 KiB
TypeScript

/**
* Optimized S3 Search and Pagination
* Provides efficient search and pagination capabilities for S3-compatible storage
*/
import { HNSWNoun, GraphVerb } from '../../coreTypes.js'
import { createModuleLogger } from '../../utils/logger.js'
import { getDirectoryPath } from '../baseStorage.js'
const logger = createModuleLogger('OptimizedS3Search')
/**
* Pagination result interface
*/
export interface PaginationResult<T> {
items: T[]
totalCount?: number
hasMore: boolean
nextCursor?: string
}
/**
* Filter interface for nouns
*/
export interface NounFilter {
nounType?: string | string[]
service?: string | string[]
metadata?: Record<string, any>
}
/**
* Filter interface for verbs
*/
export interface VerbFilter {
verbType?: string | string[]
sourceId?: string | string[]
targetId?: string | string[]
service?: string | string[]
metadata?: Record<string, any>
}
/**
* Interface for storage operations needed by optimized search
*/
export interface StorageOperations {
listObjectKeys(prefix: string, limit: number, cursor?: string): Promise<{
keys: string[]
hasMore: boolean
nextCursor?: string
}>
getObject<T>(key: string): Promise<T | null>
getMetadata(id: string, type: 'noun' | 'verb'): Promise<any | null>
}
/**
* Optimized search implementation for S3-compatible storage
*/
export class OptimizedS3Search {
constructor(private storage: StorageOperations) {}
/**
* Get nouns with optimized pagination and filtering
*/
async getNounsWithPagination(options: {
limit?: number
cursor?: string
filter?: NounFilter
} = {}): Promise<PaginationResult<HNSWNoun>> {
const limit = options.limit || 100
const cursor = options.cursor
try {
// List noun objects with pagination
const listResult = await this.storage.listObjectKeys(`${getDirectoryPath('noun', 'vector')}/`, limit * 2, cursor)
if (!listResult.keys.length) {
return {
items: [],
hasMore: false
}
}
// Load nouns in parallel batches
const nouns: HNSWNoun[] = []
const batchSize = 10
for (let i = 0; i < listResult.keys.length && nouns.length < limit; i += batchSize) {
const batch = listResult.keys.slice(i, i + batchSize)
const batchPromises = batch.map(key => this.storage.getObject<HNSWNoun>(key))
const batchResults = await Promise.all(batchPromises)
for (const noun of batchResults) {
if (!noun) continue
// Apply filters
if (options.filter && !(await this.matchesNounFilter(noun, options.filter))) {
continue
}
nouns.push(noun)
if (nouns.length >= limit) {
break
}
}
}
// Determine if there are more items
const hasMore = listResult.hasMore || nouns.length >= limit
// Set next cursor
let nextCursor: string | undefined
if (hasMore && nouns.length > 0) {
nextCursor = nouns[nouns.length - 1].id
}
return {
items: nouns.slice(0, limit),
hasMore,
nextCursor
}
} catch (error) {
logger.error('Failed to get nouns with pagination:', error)
return {
items: [],
hasMore: false
}
}
}
/**
* Get verbs with optimized pagination and filtering
*/
async getVerbsWithPagination(options: {
limit?: number
cursor?: string
filter?: VerbFilter
} = {}): Promise<PaginationResult<GraphVerb>> {
const limit = options.limit || 100
const cursor = options.cursor
try {
// List verb objects with pagination
const listResult = await this.storage.listObjectKeys(`${getDirectoryPath('verb', 'vector')}/`, limit * 2, cursor)
if (!listResult.keys.length) {
return {
items: [],
hasMore: false
}
}
// Load verbs in parallel batches
const verbs: GraphVerb[] = []
const batchSize = 10
for (let i = 0; i < listResult.keys.length && verbs.length < limit; i += batchSize) {
const batch = listResult.keys.slice(i, i + batchSize)
// Load verbs and their metadata in parallel
const batchPromises = batch.map(async (key) => {
const verbData = await this.storage.getObject<any>(key)
if (!verbData) return null
// Get metadata
const verbId = key.replace(`${getDirectoryPath('verb', 'vector')}/`, '').replace('.json', '')
const metadata = await this.storage.getMetadata(verbId, 'verb')
// Combine into GraphVerb
return this.combineVerbWithMetadata(verbData, metadata)
})
const batchResults = await Promise.all(batchPromises)
for (const verb of batchResults) {
if (!verb) continue
// Apply filters
if (options.filter && !this.matchesVerbFilter(verb, options.filter)) {
continue
}
verbs.push(verb)
if (verbs.length >= limit) {
break
}
}
}
// Determine if there are more items
const hasMore = listResult.hasMore || verbs.length >= limit
// Set next cursor
let nextCursor: string | undefined
if (hasMore && verbs.length > 0) {
nextCursor = verbs[verbs.length - 1].id
}
return {
items: verbs.slice(0, limit),
hasMore,
nextCursor
}
} catch (error) {
logger.error('Failed to get verbs with pagination:', error)
return {
items: [],
hasMore: false
}
}
}
/**
* Check if a noun matches the filter criteria
*/
private async matchesNounFilter(noun: HNSWNoun, filter: NounFilter): Promise<boolean> {
// Get metadata for filtering
const metadata = await this.storage.getMetadata(noun.id, 'noun')
// Filter by noun type
if (filter.nounType) {
const nounTypes = Array.isArray(filter.nounType) ? filter.nounType : [filter.nounType]
const nounType = metadata?.type || metadata?.noun
if (!nounType || !nounTypes.includes(nounType)) {
return false
}
}
// Filter by service
if (filter.service) {
const services = Array.isArray(filter.service) ? filter.service : [filter.service]
if (!metadata?.service || !services.includes(metadata.service)) {
return false
}
}
// Filter by metadata
if (filter.metadata) {
if (!metadata) return false
for (const [key, value] of Object.entries(filter.metadata)) {
if (metadata[key] !== value) {
return false
}
}
}
return true
}
/**
* Check if a verb matches the filter criteria
*/
private matchesVerbFilter(verb: GraphVerb, filter: VerbFilter): boolean {
// Filter by verb type
if (filter.verbType) {
const verbTypes = Array.isArray(filter.verbType) ? filter.verbType : [filter.verbType]
if (!verb.type || !verbTypes.includes(verb.type)) {
return false
}
}
// Filter by source ID
if (filter.sourceId) {
const sourceIds = Array.isArray(filter.sourceId) ? filter.sourceId : [filter.sourceId]
if (!verb.sourceId || !sourceIds.includes(verb.sourceId)) {
return false
}
}
// Filter by target ID
if (filter.targetId) {
const targetIds = Array.isArray(filter.targetId) ? filter.targetId : [filter.targetId]
if (!verb.targetId || !targetIds.includes(verb.targetId)) {
return false
}
}
// Filter by service
if (filter.service) {
const services = Array.isArray(filter.service) ? filter.service : [filter.service]
if (!verb.metadata?.service || !services.includes(verb.metadata.service)) {
return false
}
}
// Filter by metadata
if (filter.metadata) {
if (!verb.metadata) return false
for (const [key, value] of Object.entries(filter.metadata)) {
if (verb.metadata[key] !== value) {
return false
}
}
}
return true
}
/**
* Combine HNSWVerb data with metadata to create GraphVerb
*/
private combineVerbWithMetadata(verbData: any, metadata: any): GraphVerb | null {
if (!verbData || !metadata) return null
// Create default timestamp if not present
const defaultTimestamp = {
seconds: Math.floor(Date.now() / 1000),
nanoseconds: (Date.now() % 1000) * 1000000
}
// Create default createdBy if not present
const defaultCreatedBy = {
augmentation: 'unknown',
version: '1.0'
}
return {
id: verbData.id,
vector: verbData.vector,
sourceId: metadata.sourceId,
targetId: metadata.targetId,
source: metadata.source,
target: metadata.target,
verb: metadata.verb,
type: metadata.type,
weight: metadata.weight || 1.0,
metadata: metadata.metadata || {},
createdAt: metadata.createdAt || defaultTimestamp,
updatedAt: metadata.updatedAt || defaultTimestamp,
createdBy: metadata.createdBy || defaultCreatedBy,
data: metadata.data,
embedding: verbData.vector
}
}
}