@sparkleideas/plugins 3.0.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +401 -0
- package/__tests__/collection-manager.test.ts +332 -0
- package/__tests__/dependency-graph.test.ts +434 -0
- package/__tests__/enhanced-plugin-registry.test.ts +488 -0
- package/__tests__/plugin-registry.test.ts +368 -0
- package/__tests__/ruvector-bridge.test.ts +2429 -0
- package/__tests__/ruvector-integration.test.ts +1602 -0
- package/__tests__/ruvector-migrations.test.ts +1099 -0
- package/__tests__/ruvector-quantization.test.ts +846 -0
- package/__tests__/ruvector-streaming.test.ts +1088 -0
- package/__tests__/sdk.test.ts +325 -0
- package/__tests__/security.test.ts +348 -0
- package/__tests__/utils/ruvector-test-utils.ts +860 -0
- package/examples/plugin-creator/index.ts +636 -0
- package/examples/plugin-creator/plugin-creator.test.ts +312 -0
- package/examples/ruvector/README.md +288 -0
- package/examples/ruvector/attention-patterns.ts +394 -0
- package/examples/ruvector/basic-usage.ts +288 -0
- package/examples/ruvector/docker-compose.yml +75 -0
- package/examples/ruvector/gnn-analysis.ts +501 -0
- package/examples/ruvector/hyperbolic-hierarchies.ts +557 -0
- package/examples/ruvector/init-db.sql +119 -0
- package/examples/ruvector/quantization.ts +680 -0
- package/examples/ruvector/self-learning.ts +447 -0
- package/examples/ruvector/semantic-search.ts +576 -0
- package/examples/ruvector/streaming-large-data.ts +507 -0
- package/examples/ruvector/transactions.ts +594 -0
- package/examples/ruvector-plugins/hook-pattern-library.ts +486 -0
- package/examples/ruvector-plugins/index.ts +79 -0
- package/examples/ruvector-plugins/intent-router.ts +354 -0
- package/examples/ruvector-plugins/mcp-tool-optimizer.ts +424 -0
- package/examples/ruvector-plugins/reasoning-bank.ts +657 -0
- package/examples/ruvector-plugins/ruvector-plugins.test.ts +518 -0
- package/examples/ruvector-plugins/semantic-code-search.ts +498 -0
- package/examples/ruvector-plugins/shared/index.ts +20 -0
- package/examples/ruvector-plugins/shared/vector-utils.ts +257 -0
- package/examples/ruvector-plugins/sona-learning.ts +445 -0
- package/package.json +97 -0
- package/src/collections/collection-manager.ts +661 -0
- package/src/collections/index.ts +56 -0
- package/src/collections/official/index.ts +1040 -0
- package/src/core/base-plugin.ts +416 -0
- package/src/core/plugin-interface.ts +215 -0
- package/src/hooks/index.ts +685 -0
- package/src/index.ts +378 -0
- package/src/integrations/agentic-flow.ts +743 -0
- package/src/integrations/index.ts +88 -0
- package/src/integrations/ruvector/ARCHITECTURE.md +1245 -0
- package/src/integrations/ruvector/attention-advanced.ts +1040 -0
- package/src/integrations/ruvector/attention-executor.ts +782 -0
- package/src/integrations/ruvector/attention-mechanisms.ts +757 -0
- package/src/integrations/ruvector/attention.ts +1063 -0
- package/src/integrations/ruvector/gnn.ts +3050 -0
- package/src/integrations/ruvector/hyperbolic.ts +1948 -0
- package/src/integrations/ruvector/index.ts +394 -0
- package/src/integrations/ruvector/migrations/001_create_extension.sql +135 -0
- package/src/integrations/ruvector/migrations/002_create_vector_tables.sql +259 -0
- package/src/integrations/ruvector/migrations/003_create_indices.sql +328 -0
- package/src/integrations/ruvector/migrations/004_create_functions.sql +598 -0
- package/src/integrations/ruvector/migrations/005_create_attention_functions.sql +654 -0
- package/src/integrations/ruvector/migrations/006_create_gnn_functions.sql +728 -0
- package/src/integrations/ruvector/migrations/007_create_hyperbolic_functions.sql +762 -0
- package/src/integrations/ruvector/migrations/index.ts +35 -0
- package/src/integrations/ruvector/migrations/migrations.ts +647 -0
- package/src/integrations/ruvector/quantization.ts +2036 -0
- package/src/integrations/ruvector/ruvector-bridge.ts +2000 -0
- package/src/integrations/ruvector/self-learning.ts +2376 -0
- package/src/integrations/ruvector/streaming.ts +1737 -0
- package/src/integrations/ruvector/types.ts +1945 -0
- package/src/providers/index.ts +643 -0
- package/src/registry/dependency-graph.ts +568 -0
- package/src/registry/enhanced-plugin-registry.ts +994 -0
- package/src/registry/plugin-registry.ts +604 -0
- package/src/sdk/index.ts +563 -0
- package/src/security/index.ts +594 -0
- package/src/types/index.ts +446 -0
- package/src/workers/index.ts +700 -0
- package/tmp.json +0 -0
- package/tsconfig.json +25 -0
- package/vitest.config.ts +23 -0
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RuVector PostgreSQL Bridge - Attention Mechanisms Example
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates:
|
|
5
|
+
* - Multi-head attention for vector aggregation
|
|
6
|
+
* - Flash attention for long sequences
|
|
7
|
+
* - Sparse attention for efficiency
|
|
8
|
+
* - Cross-attention for multi-modal scenarios
|
|
9
|
+
*
|
|
10
|
+
* Run with: npx ts-node examples/ruvector/attention-patterns.ts
|
|
11
|
+
*
|
|
12
|
+
* @module @sparkleideas/plugins/examples/ruvector/attention-patterns
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
createRuVectorBridge,
|
|
17
|
+
type RuVectorBridge,
|
|
18
|
+
type AttentionConfig,
|
|
19
|
+
type AttentionInput,
|
|
20
|
+
} from '../../src/integrations/ruvector/index.js';
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
MultiHeadAttention,
|
|
24
|
+
SelfAttention,
|
|
25
|
+
CrossAttention,
|
|
26
|
+
CausalAttention,
|
|
27
|
+
AttentionRegistry,
|
|
28
|
+
type AttentionOptions,
|
|
29
|
+
} from '../../src/integrations/ruvector/attention.js';
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// Configuration
|
|
33
|
+
// ============================================================================
|
|
34
|
+
|
|
35
|
+
const config = {
|
|
36
|
+
connection: {
|
|
37
|
+
host: process.env.POSTGRES_HOST || 'localhost',
|
|
38
|
+
port: parseInt(process.env.POSTGRES_PORT || '5432', 10),
|
|
39
|
+
database: process.env.POSTGRES_DB || 'vectors',
|
|
40
|
+
user: process.env.POSTGRES_USER || 'postgres',
|
|
41
|
+
password: process.env.POSTGRES_PASSWORD || 'postgres',
|
|
42
|
+
},
|
|
43
|
+
embedDim: 512,
|
|
44
|
+
numHeads: 8,
|
|
45
|
+
headDim: 64,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// ============================================================================
|
|
49
|
+
// Helper Functions
|
|
50
|
+
// ============================================================================
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Generate random vectors for demonstration.
|
|
54
|
+
*/
|
|
55
|
+
function generateRandomVectors(count: number, dim: number): number[][] {
|
|
56
|
+
return Array.from({ length: count }, () =>
|
|
57
|
+
Array.from({ length: dim }, () => Math.random() * 2 - 1)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Measure execution time of an async function.
|
|
63
|
+
*/
|
|
64
|
+
async function measure<T>(name: string, fn: () => Promise<T>): Promise<T> {
|
|
65
|
+
const start = performance.now();
|
|
66
|
+
const result = await fn();
|
|
67
|
+
const duration = performance.now() - start;
|
|
68
|
+
console.log(` ${name}: ${duration.toFixed(2)}ms`);
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Print vector statistics.
|
|
74
|
+
*/
|
|
75
|
+
function printVectorStats(name: string, vec: number[]): void {
|
|
76
|
+
const min = Math.min(...vec);
|
|
77
|
+
const max = Math.max(...vec);
|
|
78
|
+
const mean = vec.reduce((a, b) => a + b, 0) / vec.length;
|
|
79
|
+
const magnitude = Math.sqrt(vec.reduce((s, v) => s + v * v, 0));
|
|
80
|
+
|
|
81
|
+
console.log(` ${name}:`);
|
|
82
|
+
console.log(` Dimension: ${vec.length}`);
|
|
83
|
+
console.log(` Range: [${min.toFixed(4)}, ${max.toFixed(4)}]`);
|
|
84
|
+
console.log(` Mean: ${mean.toFixed(4)}`);
|
|
85
|
+
console.log(` Magnitude: ${magnitude.toFixed(4)}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ============================================================================
|
|
89
|
+
// Main Example
|
|
90
|
+
// ============================================================================
|
|
91
|
+
|
|
92
|
+
async function main(): Promise<void> {
|
|
93
|
+
console.log('RuVector PostgreSQL Bridge - Attention Mechanisms Example');
|
|
94
|
+
console.log('==========================================================\n');
|
|
95
|
+
|
|
96
|
+
const bridge: RuVectorBridge = createRuVectorBridge({
|
|
97
|
+
connectionString: `postgresql://${config.connection.user}:${config.connection.password}@${config.connection.host}:${config.connection.port}/${config.connection.database}`,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Initialize attention registry
|
|
101
|
+
const registry = new AttentionRegistry();
|
|
102
|
+
|
|
103
|
+
// Register attention mechanisms
|
|
104
|
+
registry.register(new MultiHeadAttention({ numHeads: config.numHeads, headDim: config.headDim }));
|
|
105
|
+
registry.register(new SelfAttention({ headDim: config.headDim }));
|
|
106
|
+
registry.register(new CrossAttention({ numHeads: config.numHeads, headDim: config.headDim }));
|
|
107
|
+
registry.register(new CausalAttention({ numHeads: config.numHeads, headDim: config.headDim }));
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
await bridge.connect();
|
|
111
|
+
console.log('Connected to PostgreSQL\n');
|
|
112
|
+
|
|
113
|
+
// ========================================================================
|
|
114
|
+
// 1. Multi-Head Attention Example
|
|
115
|
+
// ========================================================================
|
|
116
|
+
console.log('1. Multi-Head Attention');
|
|
117
|
+
console.log(' ' + '-'.repeat(40));
|
|
118
|
+
console.log(' Parallel attention heads for capturing different relationships\n');
|
|
119
|
+
|
|
120
|
+
const multiHeadAttn = registry.get('multi_head');
|
|
121
|
+
console.log(` Configuration:`);
|
|
122
|
+
console.log(` - Heads: ${config.numHeads}`);
|
|
123
|
+
console.log(` - Head dimension: ${config.headDim}`);
|
|
124
|
+
console.log(` - Total dimension: ${config.numHeads * config.headDim}\n`);
|
|
125
|
+
|
|
126
|
+
// Generate sample data
|
|
127
|
+
const sequenceLength = 32;
|
|
128
|
+
const queries = generateRandomVectors(sequenceLength, config.headDim);
|
|
129
|
+
const keys = generateRandomVectors(sequenceLength, config.headDim);
|
|
130
|
+
const values = generateRandomVectors(sequenceLength, config.headDim);
|
|
131
|
+
|
|
132
|
+
// Compute attention for a single query
|
|
133
|
+
const singleOutput = await measure('Single query attention', async () => {
|
|
134
|
+
return multiHeadAttn.compute(queries[0], keys, values);
|
|
135
|
+
});
|
|
136
|
+
printVectorStats('Output vector', singleOutput);
|
|
137
|
+
|
|
138
|
+
// Batch computation
|
|
139
|
+
const batchOutput = await measure('Batch attention (32 queries)', async () => {
|
|
140
|
+
return multiHeadAttn.computeBatch(queries, keys, values);
|
|
141
|
+
});
|
|
142
|
+
console.log(` Batch output shape: [${batchOutput.length}, ${batchOutput[0].length}]\n`);
|
|
143
|
+
|
|
144
|
+
// ========================================================================
|
|
145
|
+
// 2. Self-Attention Example
|
|
146
|
+
// ========================================================================
|
|
147
|
+
console.log('2. Self-Attention');
|
|
148
|
+
console.log(' ' + '-'.repeat(40));
|
|
149
|
+
console.log(' Attention where Q, K, V come from the same sequence\n');
|
|
150
|
+
|
|
151
|
+
const selfAttn = registry.get('self_attention');
|
|
152
|
+
|
|
153
|
+
// Create a sequence where each token attends to all others
|
|
154
|
+
const selfSequence = generateRandomVectors(16, config.headDim);
|
|
155
|
+
|
|
156
|
+
// Self-attention: query = key = value = same sequence
|
|
157
|
+
const selfOutput = await measure('Self-attention (16 tokens)', async () => {
|
|
158
|
+
return selfAttn.computeBatch(selfSequence, selfSequence, selfSequence);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
console.log(` Input sequence: [${selfSequence.length}, ${selfSequence[0].length}]`);
|
|
162
|
+
console.log(` Output sequence: [${selfOutput.length}, ${selfOutput[0].length}]`);
|
|
163
|
+
|
|
164
|
+
// Show attention pattern (which tokens attend to which)
|
|
165
|
+
console.log('\n Attention pattern visualization (simplified):');
|
|
166
|
+
const attentionPattern = selfSequence.map((q, i) => {
|
|
167
|
+
const scores = selfSequence.map(k =>
|
|
168
|
+
q.reduce((sum, val, j) => sum + val * k[j], 0)
|
|
169
|
+
);
|
|
170
|
+
const maxIdx = scores.indexOf(Math.max(...scores));
|
|
171
|
+
return maxIdx;
|
|
172
|
+
});
|
|
173
|
+
console.log(` Token -> Most attended: [${attentionPattern.join(', ')}]\n`);
|
|
174
|
+
|
|
175
|
+
// ========================================================================
|
|
176
|
+
// 3. Cross-Attention Example (Encoder-Decoder)
|
|
177
|
+
// ========================================================================
|
|
178
|
+
console.log('3. Cross-Attention (Encoder-Decoder)');
|
|
179
|
+
console.log(' ' + '-'.repeat(40));
|
|
180
|
+
console.log(' Decoder attends to encoder outputs\n');
|
|
181
|
+
|
|
182
|
+
const crossAttn = registry.get('cross_attention');
|
|
183
|
+
|
|
184
|
+
// Simulate encoder output (e.g., from processing an image or source text)
|
|
185
|
+
const encoderOutput = generateRandomVectors(64, config.headDim);
|
|
186
|
+
|
|
187
|
+
// Simulate decoder queries (e.g., generating target text)
|
|
188
|
+
const decoderQueries = generateRandomVectors(16, config.headDim);
|
|
189
|
+
|
|
190
|
+
const crossOutput = await measure('Cross-attention (16 decoder queries, 64 encoder outputs)', async () => {
|
|
191
|
+
return crossAttn.computeBatch(decoderQueries, encoderOutput, encoderOutput);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
console.log(` Encoder sequence: [${encoderOutput.length}, ${encoderOutput[0].length}]`);
|
|
195
|
+
console.log(` Decoder queries: [${decoderQueries.length}, ${decoderQueries[0].length}]`);
|
|
196
|
+
console.log(` Cross-attention output: [${crossOutput.length}, ${crossOutput[0].length}]\n`);
|
|
197
|
+
|
|
198
|
+
// ========================================================================
|
|
199
|
+
// 4. Causal (Masked) Attention Example
|
|
200
|
+
// ========================================================================
|
|
201
|
+
console.log('4. Causal (Masked) Attention');
|
|
202
|
+
console.log(' ' + '-'.repeat(40));
|
|
203
|
+
console.log(' Autoregressive attention - each position only sees previous positions\n');
|
|
204
|
+
|
|
205
|
+
const causalAttn = registry.get('causal');
|
|
206
|
+
|
|
207
|
+
// Simulate autoregressive generation
|
|
208
|
+
const autoregSequence = generateRandomVectors(8, config.headDim);
|
|
209
|
+
|
|
210
|
+
const causalOutput = await measure('Causal attention (8 tokens)', async () => {
|
|
211
|
+
return causalAttn.computeBatch(autoregSequence, autoregSequence, autoregSequence);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
console.log(' Causal mask pattern (1 = attend, 0 = masked):');
|
|
215
|
+
for (let i = 0; i < 8; i++) {
|
|
216
|
+
const mask = Array.from({ length: 8 }, (_, j) => (j <= i ? '1' : '0')).join(' ');
|
|
217
|
+
console.log(` Token ${i}: [${mask}]`);
|
|
218
|
+
}
|
|
219
|
+
console.log();
|
|
220
|
+
|
|
221
|
+
// ========================================================================
|
|
222
|
+
// 5. Flash Attention Simulation
|
|
223
|
+
// ========================================================================
|
|
224
|
+
console.log('5. Flash Attention (Memory-Efficient)');
|
|
225
|
+
console.log(' ' + '-'.repeat(40));
|
|
226
|
+
console.log(' Tiled computation for long sequences with O(N) memory\n');
|
|
227
|
+
|
|
228
|
+
// Flash attention uses tiling to reduce memory usage
|
|
229
|
+
// Here we simulate the performance characteristics
|
|
230
|
+
|
|
231
|
+
const longSequenceLengths = [128, 256, 512, 1024];
|
|
232
|
+
|
|
233
|
+
console.log(' Sequence length | Standard Attention | Flash Attention (simulated)');
|
|
234
|
+
console.log(' ' + '-'.repeat(65));
|
|
235
|
+
|
|
236
|
+
for (const seqLen of longSequenceLengths) {
|
|
237
|
+
// Standard attention: O(N^2) memory
|
|
238
|
+
const standardMemory = seqLen * seqLen * 4; // float32
|
|
239
|
+
|
|
240
|
+
// Flash attention: O(N) memory with tiling
|
|
241
|
+
const blockSize = 64;
|
|
242
|
+
const flashMemory = 2 * blockSize * seqLen * 4;
|
|
243
|
+
|
|
244
|
+
const memoryRatio = (standardMemory / flashMemory).toFixed(1);
|
|
245
|
+
|
|
246
|
+
console.log(
|
|
247
|
+
` ${seqLen.toString().padStart(6)} tokens | ` +
|
|
248
|
+
`${(standardMemory / 1024).toFixed(0).padStart(10)} KB | ` +
|
|
249
|
+
`${(flashMemory / 1024).toFixed(0).padStart(10)} KB (${memoryRatio}x less)`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
console.log();
|
|
253
|
+
|
|
254
|
+
// ========================================================================
|
|
255
|
+
// 6. Sparse Attention Patterns
|
|
256
|
+
// ========================================================================
|
|
257
|
+
console.log('6. Sparse Attention Patterns');
|
|
258
|
+
console.log(' ' + '-'.repeat(40));
|
|
259
|
+
console.log(' Reduce computation by attending to subset of tokens\n');
|
|
260
|
+
|
|
261
|
+
// Demonstrate different sparse patterns
|
|
262
|
+
const sparsePatterns = {
|
|
263
|
+
local: 'Each token attends to k nearest neighbors',
|
|
264
|
+
strided: 'Attend every n-th token for global context',
|
|
265
|
+
global: 'Special tokens attend to all, others attend locally',
|
|
266
|
+
random: 'Random subset of tokens (BigBird style)',
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
console.log(' Common sparse attention patterns:');
|
|
270
|
+
Object.entries(sparsePatterns).forEach(([name, desc]) => {
|
|
271
|
+
console.log(` - ${name}: ${desc}`);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Compute complexity comparison
|
|
275
|
+
const N = 1024; // sequence length
|
|
276
|
+
const k = 64; // local window
|
|
277
|
+
const s = 16; // stride
|
|
278
|
+
|
|
279
|
+
console.log(`\n Complexity comparison (N=${N}, k=${k}, s=${s}):`);
|
|
280
|
+
console.log(` - Full attention: O(N^2) = ${N * N} ops`);
|
|
281
|
+
console.log(` - Local attention: O(N*k) = ${N * k} ops (${((N * k) / (N * N) * 100).toFixed(1)}%)`);
|
|
282
|
+
console.log(` - Strided attention: O(N*N/s) = ${Math.floor(N * N / s)} ops (${(100 / s).toFixed(1)}%)`);
|
|
283
|
+
console.log(` - Local + Strided: O(N*(k+N/s)) = ${N * (k + N / s)} ops`);
|
|
284
|
+
console.log();
|
|
285
|
+
|
|
286
|
+
// ========================================================================
|
|
287
|
+
// 7. Attention with KV Cache
|
|
288
|
+
// ========================================================================
|
|
289
|
+
console.log('7. Attention with KV Cache (Inference Optimization)');
|
|
290
|
+
console.log(' ' + '-'.repeat(40));
|
|
291
|
+
console.log(' Cache key-value pairs for autoregressive generation\n');
|
|
292
|
+
|
|
293
|
+
// Simulate KV cache for incremental generation
|
|
294
|
+
interface KVCache {
|
|
295
|
+
keys: number[][];
|
|
296
|
+
values: number[][];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const kvCache: KVCache = { keys: [], values: [] };
|
|
300
|
+
|
|
301
|
+
// Simulate generating 8 tokens one by one
|
|
302
|
+
console.log(' Simulating autoregressive generation with KV cache:');
|
|
303
|
+
|
|
304
|
+
const tokenDim = config.headDim;
|
|
305
|
+
let totalWithoutCache = 0;
|
|
306
|
+
let totalWithCache = 0;
|
|
307
|
+
|
|
308
|
+
for (let step = 0; step < 8; step++) {
|
|
309
|
+
// New token embedding
|
|
310
|
+
const newToken = generateRandomVectors(1, tokenDim)[0];
|
|
311
|
+
|
|
312
|
+
// Without cache: recompute all K, V
|
|
313
|
+
const withoutCacheOps = (step + 1) * (step + 1) * tokenDim;
|
|
314
|
+
totalWithoutCache += withoutCacheOps;
|
|
315
|
+
|
|
316
|
+
// With cache: only compute for new token
|
|
317
|
+
const withCacheOps = (step + 1) * tokenDim;
|
|
318
|
+
totalWithCache += withCacheOps;
|
|
319
|
+
|
|
320
|
+
// Update cache
|
|
321
|
+
kvCache.keys.push(newToken);
|
|
322
|
+
kvCache.values.push(newToken);
|
|
323
|
+
|
|
324
|
+
console.log(
|
|
325
|
+
` Step ${step + 1}: Without cache ${withoutCacheOps.toLocaleString()} ops, ` +
|
|
326
|
+
`With cache ${withCacheOps.toLocaleString()} ops ` +
|
|
327
|
+
`(${((1 - withCacheOps / withoutCacheOps) * 100).toFixed(1)}% reduction)`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
console.log(`\n Total: Without cache ${totalWithoutCache.toLocaleString()} ops, ` +
|
|
332
|
+
`With cache ${totalWithCache.toLocaleString()} ops`);
|
|
333
|
+
console.log(` Overall speedup: ${(totalWithoutCache / totalWithCache).toFixed(1)}x\n`);
|
|
334
|
+
|
|
335
|
+
// ========================================================================
|
|
336
|
+
// 8. SQL Generation for PostgreSQL
|
|
337
|
+
// ========================================================================
|
|
338
|
+
console.log('8. SQL Generation for PostgreSQL Execution');
|
|
339
|
+
console.log(' ' + '-'.repeat(40));
|
|
340
|
+
console.log(' Generate SQL for executing attention in PostgreSQL\n');
|
|
341
|
+
|
|
342
|
+
const input: AttentionInput = {
|
|
343
|
+
query: new Float32Array([0.1, 0.2, 0.3, 0.4]),
|
|
344
|
+
key: new Float32Array([0.5, 0.6, 0.7, 0.8]),
|
|
345
|
+
value: new Float32Array([0.9, 1.0, 1.1, 1.2]),
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// Multi-head attention SQL
|
|
349
|
+
const multiHeadSQL = multiHeadAttn.toSQL(input);
|
|
350
|
+
console.log(' Multi-Head Attention SQL:');
|
|
351
|
+
console.log(` ${multiHeadSQL}\n`);
|
|
352
|
+
|
|
353
|
+
// Self-attention SQL
|
|
354
|
+
const selfSQL = selfAttn.toSQL(input);
|
|
355
|
+
console.log(' Self-Attention SQL:');
|
|
356
|
+
console.log(` ${selfSQL}\n`);
|
|
357
|
+
|
|
358
|
+
// Causal attention SQL
|
|
359
|
+
const causalSQL = causalAttn.toSQL(input);
|
|
360
|
+
console.log(' Causal Attention SQL:');
|
|
361
|
+
console.log(` ${causalSQL}\n`);
|
|
362
|
+
|
|
363
|
+
// ========================================================================
|
|
364
|
+
// 9. Available Attention Mechanisms
|
|
365
|
+
// ========================================================================
|
|
366
|
+
console.log('9. Available Attention Mechanisms');
|
|
367
|
+
console.log(' ' + '-'.repeat(40));
|
|
368
|
+
|
|
369
|
+
const available = registry.getAllWithMetadata();
|
|
370
|
+
console.log(` Registered: ${available.length} mechanisms\n`);
|
|
371
|
+
|
|
372
|
+
available.forEach(mech => {
|
|
373
|
+
console.log(` ${mech.name} (${mech.type})`);
|
|
374
|
+
console.log(` Category: ${mech.category}`);
|
|
375
|
+
console.log(` ${mech.description}\n`);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// ========================================================================
|
|
379
|
+
// Done
|
|
380
|
+
// ========================================================================
|
|
381
|
+
console.log('='.repeat(60));
|
|
382
|
+
console.log('Attention mechanisms example completed!');
|
|
383
|
+
console.log('='.repeat(60));
|
|
384
|
+
|
|
385
|
+
} catch (error) {
|
|
386
|
+
console.error('Error:', error);
|
|
387
|
+
throw error;
|
|
388
|
+
} finally {
|
|
389
|
+
await bridge.disconnect();
|
|
390
|
+
console.log('\nDisconnected from PostgreSQL.');
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RuVector PostgreSQL Bridge - Basic Usage Example
|
|
3
|
+
*
|
|
4
|
+
* This example demonstrates fundamental operations:
|
|
5
|
+
* - Connecting to PostgreSQL with pgvector
|
|
6
|
+
* - Creating collections and inserting vectors
|
|
7
|
+
* - Performing similarity searches
|
|
8
|
+
* - Updating and deleting vectors
|
|
9
|
+
*
|
|
10
|
+
* Prerequisites:
|
|
11
|
+
* - PostgreSQL 14+ with pgvector extension
|
|
12
|
+
* - Docker: docker compose up -d
|
|
13
|
+
*
|
|
14
|
+
* Run with: npx ts-node examples/ruvector/basic-usage.ts
|
|
15
|
+
*
|
|
16
|
+
* @module @sparkleideas/plugins/examples/ruvector/basic-usage
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
createRuVectorBridge,
|
|
21
|
+
type RuVectorBridge,
|
|
22
|
+
type VectorRecord,
|
|
23
|
+
type VectorSearchOptions,
|
|
24
|
+
} from '../../src/integrations/ruvector/index.js';
|
|
25
|
+
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// Configuration
|
|
28
|
+
// ============================================================================
|
|
29
|
+
|
|
30
|
+
const config = {
|
|
31
|
+
connection: {
|
|
32
|
+
host: process.env.POSTGRES_HOST || 'localhost',
|
|
33
|
+
port: parseInt(process.env.POSTGRES_PORT || '5432', 10),
|
|
34
|
+
database: process.env.POSTGRES_DB || 'vectors',
|
|
35
|
+
user: process.env.POSTGRES_USER || 'postgres',
|
|
36
|
+
password: process.env.POSTGRES_PASSWORD || 'postgres',
|
|
37
|
+
},
|
|
38
|
+
dimensions: 384, // Common embedding dimension (e.g., sentence-transformers/all-MiniLM-L6-v2)
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Helper Functions
|
|
43
|
+
// ============================================================================
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Generate a random embedding vector for demonstration.
|
|
47
|
+
* In production, use a proper embedding model.
|
|
48
|
+
*/
|
|
49
|
+
function generateRandomEmbedding(dim: number): number[] {
|
|
50
|
+
const embedding = new Array(dim);
|
|
51
|
+
for (let i = 0; i < dim; i++) {
|
|
52
|
+
embedding[i] = Math.random() * 2 - 1; // Range [-1, 1]
|
|
53
|
+
}
|
|
54
|
+
// Normalize to unit length
|
|
55
|
+
const magnitude = Math.sqrt(embedding.reduce((sum, v) => sum + v * v, 0));
|
|
56
|
+
return embedding.map(v => v / magnitude);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Print search results in a readable format.
|
|
61
|
+
*/
|
|
62
|
+
function printResults(title: string, results: VectorRecord[]): void {
|
|
63
|
+
console.log(`\n${title}`);
|
|
64
|
+
console.log('='.repeat(50));
|
|
65
|
+
results.forEach((result, i) => {
|
|
66
|
+
console.log(`${i + 1}. ID: ${result.id}`);
|
|
67
|
+
console.log(` Distance: ${result.distance?.toFixed(4) ?? 'N/A'}`);
|
|
68
|
+
console.log(` Metadata: ${JSON.stringify(result.metadata)}`);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ============================================================================
|
|
73
|
+
// Main Example
|
|
74
|
+
// ============================================================================
|
|
75
|
+
|
|
76
|
+
async function main(): Promise<void> {
|
|
77
|
+
console.log('RuVector PostgreSQL Bridge - Basic Usage Example');
|
|
78
|
+
console.log('================================================\n');
|
|
79
|
+
|
|
80
|
+
// Create the bridge instance
|
|
81
|
+
const bridge: RuVectorBridge = createRuVectorBridge({
|
|
82
|
+
connectionString: `postgresql://${config.connection.user}:${config.connection.password}@${config.connection.host}:${config.connection.port}/${config.connection.database}`,
|
|
83
|
+
poolSize: 5,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
// ========================================================================
|
|
88
|
+
// 1. Connect to PostgreSQL
|
|
89
|
+
// ========================================================================
|
|
90
|
+
console.log('1. Connecting to PostgreSQL...');
|
|
91
|
+
await bridge.connect();
|
|
92
|
+
console.log(' Connected successfully!\n');
|
|
93
|
+
|
|
94
|
+
// ========================================================================
|
|
95
|
+
// 2. Create a Collection
|
|
96
|
+
// ========================================================================
|
|
97
|
+
console.log('2. Creating collection "documents"...');
|
|
98
|
+
await bridge.createCollection('documents', {
|
|
99
|
+
dimensions: config.dimensions,
|
|
100
|
+
distanceMetric: 'cosine',
|
|
101
|
+
indexType: 'hnsw',
|
|
102
|
+
indexParams: {
|
|
103
|
+
m: 16, // Number of connections per layer
|
|
104
|
+
efConstruction: 64, // Size of dynamic candidate list during construction
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
console.log(' Collection created!\n');
|
|
108
|
+
|
|
109
|
+
// ========================================================================
|
|
110
|
+
// 3. Insert Vectors
|
|
111
|
+
// ========================================================================
|
|
112
|
+
console.log('3. Inserting vectors...');
|
|
113
|
+
|
|
114
|
+
// Sample documents with embeddings
|
|
115
|
+
const documents = [
|
|
116
|
+
{ id: 'doc-1', content: 'Introduction to machine learning', category: 'ML' },
|
|
117
|
+
{ id: 'doc-2', content: 'Deep learning fundamentals', category: 'DL' },
|
|
118
|
+
{ id: 'doc-3', content: 'Natural language processing', category: 'NLP' },
|
|
119
|
+
{ id: 'doc-4', content: 'Computer vision basics', category: 'CV' },
|
|
120
|
+
{ id: 'doc-5', content: 'Reinforcement learning guide', category: 'RL' },
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
// Insert each document with its embedding
|
|
124
|
+
for (const doc of documents) {
|
|
125
|
+
const embedding = generateRandomEmbedding(config.dimensions);
|
|
126
|
+
await bridge.insert('documents', {
|
|
127
|
+
id: doc.id,
|
|
128
|
+
embedding,
|
|
129
|
+
metadata: {
|
|
130
|
+
content: doc.content,
|
|
131
|
+
category: doc.category,
|
|
132
|
+
createdAt: new Date().toISOString(),
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
console.log(` Inserted: ${doc.id}`);
|
|
136
|
+
}
|
|
137
|
+
console.log(' All vectors inserted!\n');
|
|
138
|
+
|
|
139
|
+
// ========================================================================
|
|
140
|
+
// 4. Basic Similarity Search
|
|
141
|
+
// ========================================================================
|
|
142
|
+
console.log('4. Performing similarity search...');
|
|
143
|
+
|
|
144
|
+
// Generate a query vector (in production, embed your query text)
|
|
145
|
+
const queryVector = generateRandomEmbedding(config.dimensions);
|
|
146
|
+
|
|
147
|
+
const searchOptions: VectorSearchOptions = {
|
|
148
|
+
k: 3, // Return top 3 results
|
|
149
|
+
includeMetadata: true,
|
|
150
|
+
includeDistance: true,
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const searchResults = await bridge.search('documents', queryVector, searchOptions);
|
|
154
|
+
printResults('Top 3 Similar Documents', searchResults);
|
|
155
|
+
|
|
156
|
+
// ========================================================================
|
|
157
|
+
// 5. Filtered Search
|
|
158
|
+
// ========================================================================
|
|
159
|
+
console.log('\n5. Performing filtered search (category = "ML")...');
|
|
160
|
+
|
|
161
|
+
const filteredResults = await bridge.search('documents', queryVector, {
|
|
162
|
+
...searchOptions,
|
|
163
|
+
filter: {
|
|
164
|
+
category: 'ML',
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
printResults('Filtered Results (ML category)', filteredResults);
|
|
168
|
+
|
|
169
|
+
// ========================================================================
|
|
170
|
+
// 6. Range Search (by distance threshold)
|
|
171
|
+
// ========================================================================
|
|
172
|
+
console.log('\n6. Performing range search (distance < 0.8)...');
|
|
173
|
+
|
|
174
|
+
const rangeResults = await bridge.search('documents', queryVector, {
|
|
175
|
+
k: 10,
|
|
176
|
+
includeMetadata: true,
|
|
177
|
+
includeDistance: true,
|
|
178
|
+
distanceThreshold: 0.8, // Only return results within this distance
|
|
179
|
+
});
|
|
180
|
+
printResults('Range Search Results', rangeResults);
|
|
181
|
+
|
|
182
|
+
// ========================================================================
|
|
183
|
+
// 7. Update a Vector
|
|
184
|
+
// ========================================================================
|
|
185
|
+
console.log('\n7. Updating vector "doc-1"...');
|
|
186
|
+
|
|
187
|
+
const newEmbedding = generateRandomEmbedding(config.dimensions);
|
|
188
|
+
await bridge.update('documents', 'doc-1', {
|
|
189
|
+
embedding: newEmbedding,
|
|
190
|
+
metadata: {
|
|
191
|
+
content: 'Introduction to machine learning (Updated)',
|
|
192
|
+
category: 'ML',
|
|
193
|
+
updatedAt: new Date().toISOString(),
|
|
194
|
+
},
|
|
195
|
+
});
|
|
196
|
+
console.log(' Vector updated!');
|
|
197
|
+
|
|
198
|
+
// Verify the update
|
|
199
|
+
const updatedDoc = await bridge.get('documents', 'doc-1');
|
|
200
|
+
if (updatedDoc) {
|
|
201
|
+
console.log(` Verified: ${JSON.stringify(updatedDoc.metadata)}`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ========================================================================
|
|
205
|
+
// 8. Batch Insert
|
|
206
|
+
// ========================================================================
|
|
207
|
+
console.log('\n8. Batch inserting 100 vectors...');
|
|
208
|
+
|
|
209
|
+
const batchRecords: VectorRecord[] = [];
|
|
210
|
+
for (let i = 0; i < 100; i++) {
|
|
211
|
+
batchRecords.push({
|
|
212
|
+
id: `batch-${i}`,
|
|
213
|
+
embedding: generateRandomEmbedding(config.dimensions),
|
|
214
|
+
metadata: {
|
|
215
|
+
batchIndex: i,
|
|
216
|
+
createdAt: new Date().toISOString(),
|
|
217
|
+
},
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const startTime = performance.now();
|
|
222
|
+
await bridge.insertBatch('documents', batchRecords);
|
|
223
|
+
const duration = performance.now() - startTime;
|
|
224
|
+
|
|
225
|
+
console.log(` Inserted 100 vectors in ${duration.toFixed(2)}ms`);
|
|
226
|
+
console.log(` Throughput: ${(100 / (duration / 1000)).toFixed(0)} vectors/second`);
|
|
227
|
+
|
|
228
|
+
// ========================================================================
|
|
229
|
+
// 9. Get Collection Statistics
|
|
230
|
+
// ========================================================================
|
|
231
|
+
console.log('\n9. Collection statistics...');
|
|
232
|
+
|
|
233
|
+
const stats = await bridge.getCollectionStats('documents');
|
|
234
|
+
console.log(` Total vectors: ${stats.vectorCount}`);
|
|
235
|
+
console.log(` Dimensions: ${stats.dimensions}`);
|
|
236
|
+
console.log(` Index type: ${stats.indexType}`);
|
|
237
|
+
console.log(` Index size: ${(stats.indexSizeBytes / 1024).toFixed(2)} KB`);
|
|
238
|
+
|
|
239
|
+
// ========================================================================
|
|
240
|
+
// 10. Delete Vectors
|
|
241
|
+
// ========================================================================
|
|
242
|
+
console.log('\n10. Deleting vectors...');
|
|
243
|
+
|
|
244
|
+
// Delete a single vector
|
|
245
|
+
await bridge.delete('documents', 'doc-5');
|
|
246
|
+
console.log(' Deleted: doc-5');
|
|
247
|
+
|
|
248
|
+
// Delete multiple vectors
|
|
249
|
+
const idsToDelete = ['batch-0', 'batch-1', 'batch-2'];
|
|
250
|
+
for (const id of idsToDelete) {
|
|
251
|
+
await bridge.delete('documents', id);
|
|
252
|
+
}
|
|
253
|
+
console.log(` Deleted: ${idsToDelete.join(', ')}`);
|
|
254
|
+
|
|
255
|
+
// Verify deletion
|
|
256
|
+
const deletedDoc = await bridge.get('documents', 'doc-5');
|
|
257
|
+
console.log(` Verification - doc-5 exists: ${deletedDoc !== null}`);
|
|
258
|
+
|
|
259
|
+
// ========================================================================
|
|
260
|
+
// 11. Cleanup (Optional)
|
|
261
|
+
// ========================================================================
|
|
262
|
+
console.log('\n11. Cleanup...');
|
|
263
|
+
|
|
264
|
+
// Uncomment to drop the collection when done
|
|
265
|
+
// await bridge.dropCollection('documents');
|
|
266
|
+
// console.log(' Collection dropped!');
|
|
267
|
+
|
|
268
|
+
console.log(' Skipping collection drop (uncomment to enable)');
|
|
269
|
+
|
|
270
|
+
// ========================================================================
|
|
271
|
+
// Done
|
|
272
|
+
// ========================================================================
|
|
273
|
+
console.log('\n' + '='.repeat(50));
|
|
274
|
+
console.log('Basic usage example completed successfully!');
|
|
275
|
+
console.log('='.repeat(50));
|
|
276
|
+
|
|
277
|
+
} catch (error) {
|
|
278
|
+
console.error('Error:', error);
|
|
279
|
+
throw error;
|
|
280
|
+
} finally {
|
|
281
|
+
// Always disconnect
|
|
282
|
+
await bridge.disconnect();
|
|
283
|
+
console.log('\nDisconnected from PostgreSQL.');
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Run the example
|
|
288
|
+
main().catch(console.error);
|