@futdevpro/nts-dynamo 1.15.70 → 1.15.72
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/.dynamo/logs/cicd-pipeline/output.log +1811 -1741
- package/.dynamo/logs/cicd-pipeline/status.json +38 -38
- package/build/_modules/local-vector-search/_services/lvs-vector-pool.control-service.d.ts +20 -1
- package/build/_modules/local-vector-search/_services/lvs-vector-pool.control-service.d.ts.map +1 -1
- package/build/_modules/local-vector-search/_services/lvs-vector-pool.control-service.js +49 -7
- package/build/_modules/local-vector-search/_services/lvs-vector-pool.control-service.js.map +1 -1
- package/package.json +1 -1
- package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.spec.ts +99 -1
- package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.ts +55 -7
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"pid":
|
|
3
|
-
"startedAt": "2026-06-
|
|
4
|
-
"startedAtMs":
|
|
2
|
+
"pid": 6137,
|
|
3
|
+
"startedAt": "2026-06-21T00:34:15.872Z",
|
|
4
|
+
"startedAtMs": 1782002055872,
|
|
5
5
|
"phase": "npm-publish",
|
|
6
6
|
"pipelineComplete": false,
|
|
7
7
|
"serverRunning": false,
|
|
@@ -10,83 +10,83 @@
|
|
|
10
10
|
"steps": {
|
|
11
11
|
"validate-secrets": {
|
|
12
12
|
"status": "ok",
|
|
13
|
-
"startedAt": "2026-06-
|
|
13
|
+
"startedAt": "2026-06-21T00:34:15.910Z",
|
|
14
14
|
"logLineStart": 2,
|
|
15
15
|
"logLineEnd": 7,
|
|
16
|
-
"durationSec":
|
|
16
|
+
"durationSec": 1.6
|
|
17
17
|
},
|
|
18
18
|
"discord-start": {
|
|
19
19
|
"status": "ok",
|
|
20
|
-
"startedAt": "2026-06-
|
|
20
|
+
"startedAt": "2026-06-21T00:34:18.482Z",
|
|
21
21
|
"logLineStart": 8,
|
|
22
22
|
"logLineEnd": 13,
|
|
23
|
-
"durationSec":
|
|
23
|
+
"durationSec": 4.1
|
|
24
24
|
},
|
|
25
25
|
"pre-flight": {
|
|
26
26
|
"status": "ok",
|
|
27
|
-
"startedAt": "2026-06-
|
|
27
|
+
"startedAt": "2026-06-21T00:34:23.536Z",
|
|
28
28
|
"logLineStart": 14,
|
|
29
29
|
"logLineEnd": 16,
|
|
30
30
|
"durationSec": 0.2
|
|
31
31
|
},
|
|
32
32
|
"install": {
|
|
33
33
|
"status": "ok",
|
|
34
|
-
"startedAt": "2026-06-
|
|
34
|
+
"startedAt": "2026-06-21T00:34:24.765Z",
|
|
35
35
|
"logLineStart": 17,
|
|
36
|
-
"logLineEnd":
|
|
37
|
-
"durationSec":
|
|
36
|
+
"logLineEnd": 154,
|
|
37
|
+
"durationSec": 63.8
|
|
38
38
|
},
|
|
39
39
|
"check-dev-leftovers": {
|
|
40
40
|
"status": "ok",
|
|
41
|
-
"startedAt": "2026-06-
|
|
42
|
-
"logLineStart":
|
|
43
|
-
"logLineEnd":
|
|
44
|
-
"durationSec": 3.
|
|
41
|
+
"startedAt": "2026-06-21T00:35:29.554Z",
|
|
42
|
+
"logLineStart": 155,
|
|
43
|
+
"logLineEnd": 162,
|
|
44
|
+
"durationSec": 3.8
|
|
45
45
|
},
|
|
46
46
|
"build": {
|
|
47
47
|
"status": "ok",
|
|
48
|
-
"startedAt": "2026-06-
|
|
49
|
-
"logLineStart":
|
|
50
|
-
"logLineEnd":
|
|
51
|
-
"durationSec":
|
|
48
|
+
"startedAt": "2026-06-21T00:35:34.359Z",
|
|
49
|
+
"logLineStart": 163,
|
|
50
|
+
"logLineEnd": 164,
|
|
51
|
+
"durationSec": 29.3
|
|
52
52
|
},
|
|
53
53
|
"test": {
|
|
54
54
|
"status": "ok",
|
|
55
|
-
"startedAt": "2026-06-
|
|
56
|
-
"logLineStart":
|
|
57
|
-
"logLineEnd":
|
|
58
|
-
"durationSec":
|
|
55
|
+
"startedAt": "2026-06-21T00:36:04.719Z",
|
|
56
|
+
"logLineStart": 165,
|
|
57
|
+
"logLineEnd": 2869,
|
|
58
|
+
"durationSec": 47.5,
|
|
59
59
|
"testSummary": {
|
|
60
|
-
"totalSpecs":
|
|
60
|
+
"totalSpecs": 1429,
|
|
61
61
|
"failures": 0,
|
|
62
|
-
"passed":
|
|
63
|
-
"testDurationSec":
|
|
62
|
+
"passed": 1429,
|
|
63
|
+
"testDurationSec": 8.566
|
|
64
64
|
},
|
|
65
65
|
"errors": [
|
|
66
66
|
{
|
|
67
|
-
"line":
|
|
67
|
+
"line": 247,
|
|
68
68
|
"text": "❌❌ Error handleMessage: Error: Test error",
|
|
69
|
-
"details": "at UserContext.<anonymous> (/tmp/pipeline-runs/
|
|
70
|
-
"detailLineEnd":
|
|
69
|
+
"details": "at UserContext.<anonymous> (/tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/build/_modules/assistant/_services/ass-io.control-service.spec.js:68:136)\nat QueueRunner.attempt (/tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/node_modules/.pnpm/jasmine-core@5.10.0/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:8414:40)\nat QueueRunner.run (/tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/node_modules/.pnpm/jasmine-core@5.10.0/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:8452:27)\nat runNext (/tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/node_modules/.pnpm/jasmine-core@5.10.0/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:8355:16)\nat /tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/node_modules/.pnpm/jasmine-core@5.10.0/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:8361:11\nat /tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/node_modules/.pnpm/jasmine-core@5.10.0/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:8241:9",
|
|
70
|
+
"detailLineEnd": 253
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
|
-
"line":
|
|
73
|
+
"line": 260,
|
|
74
74
|
"text": "❌❌ Error handleMessage: Error: Test error",
|
|
75
|
-
"details": "at UserContext.<anonymous> (/tmp/pipeline-runs/
|
|
76
|
-
"detailLineEnd":
|
|
75
|
+
"details": "at UserContext.<anonymous> (/tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/build/_modules/assistant/_services/ass-io.control-service.spec.js:92:136)\nat QueueRunner.attempt (/tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/node_modules/.pnpm/jasmine-core@5.10.0/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:8414:40)\nat QueueRunner.run (/tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/node_modules/.pnpm/jasmine-core@5.10.0/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:8452:27)\nat runNext (/tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/node_modules/.pnpm/jasmine-core@5.10.0/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:8355:16)\nat /tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/node_modules/.pnpm/jasmine-core@5.10.0/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:8361:11\nat /tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/node_modules/.pnpm/jasmine-core@5.10.0/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:8241:9",
|
|
76
|
+
"detailLineEnd": 266
|
|
77
77
|
},
|
|
78
78
|
{
|
|
79
|
-
"line":
|
|
80
|
-
"text": "
|
|
81
|
-
"details": "
|
|
82
|
-
"detailLineEnd":
|
|
79
|
+
"line": 1467,
|
|
80
|
+
"text": "...............................❌ getDataByDependencyId failed, dependencyKey is missing from service! (test_data)",
|
|
81
|
+
"details": "'Test API Call' was UNSUCCESSFUL\n📍 /tmp/pipeline-runs/32ad17ba-0cce-4f24-a15f-6679bde2dbfd/build/_services/base/data.service.spec.js:182:87",
|
|
82
|
+
"detailLineEnd": 1468
|
|
83
83
|
}
|
|
84
84
|
]
|
|
85
85
|
},
|
|
86
86
|
"npm-publish": {
|
|
87
87
|
"status": "running",
|
|
88
|
-
"startedAt": "2026-06-
|
|
89
|
-
"logLineStart":
|
|
88
|
+
"startedAt": "2026-06-21T00:36:53.406Z",
|
|
89
|
+
"logLineStart": 2870,
|
|
90
90
|
"logLineEnd": null,
|
|
91
91
|
"durationSec": null
|
|
92
92
|
}
|
|
@@ -16,6 +16,16 @@ export declare class LVS_VectorPool_ControlService {
|
|
|
16
16
|
* Key: vektor ID, Value: L2 normalizált vektor értékek
|
|
17
17
|
*/
|
|
18
18
|
private normalizedVectorPool;
|
|
19
|
+
/**
|
|
20
|
+
* `normalizedOnly` mód: ha `true`, a pool NEM tárolja a nyers vektorokat (`vectorPool`) — CSAK a
|
|
21
|
+
* normalizált másolatot. A kizárólag-cosine fogyasztóknak (pl. RAG-keresés) ez ~50% memória-megtakarítás
|
|
22
|
+
* (a két párhuzamos pool helyett egy). Ekkor az `l2Distance`-keresés és a `getAll()` nyers-érték-olvasása
|
|
23
|
+
* N/A (a `size()` + a `cosineSimilarity`-keresés továbbra is helyes). Default `false` (visszafelé kompatibilis).
|
|
24
|
+
*/
|
|
25
|
+
private readonly normalizedOnly;
|
|
26
|
+
constructor(set?: {
|
|
27
|
+
normalizedOnly?: boolean;
|
|
28
|
+
});
|
|
19
29
|
/**
|
|
20
30
|
* Hozzáad egy vektort a pool-hoz
|
|
21
31
|
* Opcionálisan L2 normalizált másolatot is tárol
|
|
@@ -29,6 +39,11 @@ export declare class LVS_VectorPool_ControlService {
|
|
|
29
39
|
* Frissít egy vektort a pool-ban
|
|
30
40
|
*/
|
|
31
41
|
updateVector(id: string, vector: number[]): void;
|
|
42
|
+
/**
|
|
43
|
+
* A pool elemszáma. Mindkét módban helyes (a `normalizedVectorPool` a forrás), így `normalizedOnly`
|
|
44
|
+
* módban is — szemben a `getAll().size`-szal, ami ott üres (a nyers pool nincs tárolva).
|
|
45
|
+
*/
|
|
46
|
+
size(): number;
|
|
32
47
|
/**
|
|
33
48
|
* Törli az összes vektort a pool-ból
|
|
34
49
|
*/
|
|
@@ -64,8 +79,12 @@ export declare class LVS_VectorPool_ControlService {
|
|
|
64
79
|
* @param query A keresési query vektor
|
|
65
80
|
* @param k A visszaadandó találatok száma (top-K)
|
|
66
81
|
* @param mode A keresési mód (cosine similarity vagy L2 distance)
|
|
82
|
+
* @param candidateIds Opcionális jelölt-ID szűrő: ha meg van adva, a keresés CSAK az ebben a
|
|
83
|
+
* halmazban lévő ID-kra fut (a többit `Set.has` O(1)-gyel kihagyja). Így a hívónak NEM kell külön
|
|
84
|
+
* szűkített pool-t építenie + a vektorokat újra-normalizálnia — a keresés a MÁR előre-normalizált
|
|
85
|
+
* `normalizedVectorPool`-on iterál allokáció-mentesen. Üres halmaz → üres eredmény.
|
|
67
86
|
* @returns A top-K találatok ID-val és score-rel, megfelelő sorrendben
|
|
68
87
|
*/
|
|
69
|
-
search(query: number[], k: number, mode: LVS_Search_Mode): LVS_SearchResult[];
|
|
88
|
+
search(query: number[], k: number, mode: LVS_Search_Mode, candidateIds?: Set<string>): LVS_SearchResult[];
|
|
70
89
|
}
|
|
71
90
|
//# sourceMappingURL=lvs-vector-pool.control-service.d.ts.map
|
package/build/_modules/local-vector-search/_services/lvs-vector-pool.control-service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lvs-vector-pool.control-service.d.ts","sourceRoot":"","sources":["../../../../src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAE1E;;;;GAIG;AACH,qBAAa,6BAA6B;IACxC;;;OAGG;IACH,OAAO,CAAC,UAAU,CAAsD;IAExE;;;OAGG;IACH,OAAO,CAAC,oBAAoB,CAAsD;IAElF;;;OAGG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"lvs-vector-pool.control-service.d.ts","sourceRoot":"","sources":["../../../../src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAE1E;;;;GAIG;AACH,qBAAa,6BAA6B;IACxC;;;OAGG;IACH,OAAO,CAAC,UAAU,CAAsD;IAExE;;;OAGG;IACH,OAAO,CAAC,oBAAoB,CAAsD;IAElF;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;gBAE7B,GAAG,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE;IAI9C;;;OAGG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IA0B7C;;OAEG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAK9B;;OAEG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAShD;;;OAGG;IACH,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,SAAS,IAAI,IAAI;IAKjB;;;OAGG;IACH,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAI/B;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAa1B;;;;;OAKG;IACH,MAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM;IAsBzD;;;;OAIG;IACH,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM;IAiBnD;;;;;;;;;;;;OAYG;IACH,MAAM,CACJ,KAAK,EAAE,MAAM,EAAE,EACf,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,eAAe,EACrB,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GACzB,gBAAgB,EAAE;CA6EtB"}
|
|
@@ -18,6 +18,16 @@ class LVS_VectorPool_ControlService {
|
|
|
18
18
|
* Key: vektor ID, Value: L2 normalizált vektor értékek
|
|
19
19
|
*/
|
|
20
20
|
normalizedVectorPool = new Map();
|
|
21
|
+
/**
|
|
22
|
+
* `normalizedOnly` mód: ha `true`, a pool NEM tárolja a nyers vektorokat (`vectorPool`) — CSAK a
|
|
23
|
+
* normalizált másolatot. A kizárólag-cosine fogyasztóknak (pl. RAG-keresés) ez ~50% memória-megtakarítás
|
|
24
|
+
* (a két párhuzamos pool helyett egy). Ekkor az `l2Distance`-keresés és a `getAll()` nyers-érték-olvasása
|
|
25
|
+
* N/A (a `size()` + a `cosineSimilarity`-keresés továbbra is helyes). Default `false` (visszafelé kompatibilis).
|
|
26
|
+
*/
|
|
27
|
+
normalizedOnly;
|
|
28
|
+
constructor(set) {
|
|
29
|
+
this.normalizedOnly = set?.normalizedOnly ?? false;
|
|
30
|
+
}
|
|
21
31
|
/**
|
|
22
32
|
* Hozzáad egy vektort a pool-hoz
|
|
23
33
|
* Opcionálisan L2 normalizált másolatot is tárol
|
|
@@ -35,8 +45,10 @@ class LVS_VectorPool_ControlService {
|
|
|
35
45
|
throw new Error(`Vector must contain only finite numbers at index ${i}`);
|
|
36
46
|
}
|
|
37
47
|
}
|
|
38
|
-
// Tároljuk az eredeti vektort
|
|
39
|
-
this.
|
|
48
|
+
// Tároljuk az eredeti vektort — KIVÉVE normalizedOnly módban (akkor a nyers pool kihagyva, ~50% memória).
|
|
49
|
+
if (!this.normalizedOnly) {
|
|
50
|
+
this.vectorPool.set(id, vector);
|
|
51
|
+
}
|
|
40
52
|
// L2 normalizált másolatot is tárolunk a cosine similarity számításokhoz
|
|
41
53
|
const normalized = LVS_VectorPool_ControlService.l2Normalize(vector);
|
|
42
54
|
this.normalizedVectorPool.set(id, normalized);
|
|
@@ -52,11 +64,19 @@ class LVS_VectorPool_ControlService {
|
|
|
52
64
|
* Frissít egy vektort a pool-ban
|
|
53
65
|
*/
|
|
54
66
|
updateVector(id, vector) {
|
|
55
|
-
|
|
67
|
+
// A `normalizedVectorPool` a forrás (mindkét módban populált; `normalizedOnly`-ban a `vectorPool` üres).
|
|
68
|
+
if (!this.normalizedVectorPool.has(id)) {
|
|
56
69
|
throw new Error(`Vector with ID "${id}" does not exist`);
|
|
57
70
|
}
|
|
58
71
|
this.addVector(id, vector);
|
|
59
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* A pool elemszáma. Mindkét módban helyes (a `normalizedVectorPool` a forrás), így `normalizedOnly`
|
|
75
|
+
* módban is — szemben a `getAll().size`-szal, ami ott üres (a nyers pool nincs tárolva).
|
|
76
|
+
*/
|
|
77
|
+
size() {
|
|
78
|
+
return this.normalizedVectorPool.size;
|
|
79
|
+
}
|
|
60
80
|
/**
|
|
61
81
|
* Törli az összes vektort a pool-ból
|
|
62
82
|
*/
|
|
@@ -130,20 +150,36 @@ class LVS_VectorPool_ControlService {
|
|
|
130
150
|
* @param query A keresési query vektor
|
|
131
151
|
* @param k A visszaadandó találatok száma (top-K)
|
|
132
152
|
* @param mode A keresési mód (cosine similarity vagy L2 distance)
|
|
153
|
+
* @param candidateIds Opcionális jelölt-ID szűrő: ha meg van adva, a keresés CSAK az ebben a
|
|
154
|
+
* halmazban lévő ID-kra fut (a többit `Set.has` O(1)-gyel kihagyja). Így a hívónak NEM kell külön
|
|
155
|
+
* szűkített pool-t építenie + a vektorokat újra-normalizálnia — a keresés a MÁR előre-normalizált
|
|
156
|
+
* `normalizedVectorPool`-on iterál allokáció-mentesen. Üres halmaz → üres eredmény.
|
|
133
157
|
* @returns A top-K találatok ID-val és score-rel, megfelelő sorrendben
|
|
134
158
|
*/
|
|
135
|
-
search(query, k, mode) {
|
|
159
|
+
search(query, k, mode, candidateIds) {
|
|
160
|
+
// Üres jelölt-halmaz → nincs mit keresni (a `undefined` viszont „nincs szűrés" = teljes pool).
|
|
161
|
+
if (candidateIds && candidateIds.size === 0) {
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
136
164
|
if (!Array.isArray(query) || query.length === 0) {
|
|
137
165
|
throw new Error('Query vector must be a non-empty array');
|
|
138
166
|
}
|
|
139
167
|
if (k <= 0) {
|
|
140
168
|
throw new Error('k must be a positive number');
|
|
141
169
|
}
|
|
142
|
-
|
|
170
|
+
// `normalizedOnly` módban nincs nyers pool → l2Distance nem számolható (csak cosine).
|
|
171
|
+
if (this.normalizedOnly && mode === lvs_search_mode_enum_1.LVS_Search_Mode.l2Distance) {
|
|
172
|
+
throw new Error('l2Distance search is not available in normalizedOnly mode (raw vectors are not stored)');
|
|
173
|
+
}
|
|
174
|
+
// Üres pool → üres eredmény. A `normalizedVectorPool` a forrás (mindkét módban populált; a nyers
|
|
175
|
+
// `vectorPool` `normalizedOnly`-ban üres, ezért NEM azon ellenőrzünk).
|
|
176
|
+
if (this.normalizedVectorPool.size === 0) {
|
|
143
177
|
return [];
|
|
144
178
|
}
|
|
145
|
-
// Validáljuk, hogy minden vektor ugyanolyan dimenziójú-e
|
|
146
|
-
|
|
179
|
+
// Validáljuk, hogy minden vektor ugyanolyan dimenziójú-e. A referencia-pool mód-függő: l2 a nyers,
|
|
180
|
+
// cosine a normalizált (azonos dimenzió, de `normalizedOnly`-ban a nyers pool üres).
|
|
181
|
+
const referencePool = mode === lvs_search_mode_enum_1.LVS_Search_Mode.l2Distance ? this.vectorPool : this.normalizedVectorPool;
|
|
182
|
+
const firstVector = Array.from(referencePool.values())[0];
|
|
147
183
|
if (firstVector && firstVector.length !== query.length) {
|
|
148
184
|
throw new Error(`Query vector dimension (${query.length}) does not match pool vector ` +
|
|
149
185
|
`dimension (${firstVector.length})`);
|
|
@@ -161,6 +197,9 @@ class LVS_VectorPool_ControlService {
|
|
|
161
197
|
// A drágán eltárolt `normalizedVectorPool` korábban SOHA nem volt használva a keresésben.
|
|
162
198
|
const queryNormalized = LVS_VectorPool_ControlService.l2Normalize(query);
|
|
163
199
|
for (const [id, normalizedVector] of this.normalizedVectorPool.entries()) {
|
|
200
|
+
if (candidateIds && !candidateIds.has(id)) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
164
203
|
let dotProduct = 0;
|
|
165
204
|
for (let i = 0; i < queryNormalized.length; i++) {
|
|
166
205
|
dotProduct += queryNormalized[i] * normalizedVector[i];
|
|
@@ -172,6 +211,9 @@ class LVS_VectorPool_ControlService {
|
|
|
172
211
|
}
|
|
173
212
|
else if (mode === lvs_search_mode_enum_1.LVS_Search_Mode.l2Distance) {
|
|
174
213
|
for (const [id, vector] of this.vectorPool.entries()) {
|
|
214
|
+
if (candidateIds && !candidateIds.has(id)) {
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
175
217
|
results.push({ id, score: LVS_VectorPool_ControlService.l2Distance(query, vector) });
|
|
176
218
|
}
|
|
177
219
|
// L2 distance: növekvő sorrend (legkisebb távolság először)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lvs-vector-pool.control-service.js","sourceRoot":"","sources":["../../../../src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.ts"],"names":[],"mappings":";;;AAAA,yEAAiE;AAGjE;;;;GAIG;AACH,MAAa,6BAA6B;IACxC;;;OAGG;IACK,UAAU,GAA0B,IAAI,GAAG,EAAoB,CAAC;IAExE;;;OAGG;IACK,oBAAoB,GAA0B,IAAI,GAAG,EAAoB,CAAC;IAElF;;;OAGG;IACH,SAAS,CAAC,EAAU,EAAE,MAAgB;QACpC,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC3C,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;QACtD,CAAC;QAED,0CAA0C;QAC1C,KAAK,IAAI,CAAC,GAAW,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,IAAI,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1D,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,EAAE,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;QAED,
|
|
1
|
+
{"version":3,"file":"lvs-vector-pool.control-service.js","sourceRoot":"","sources":["../../../../src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -399,11 +399,109 @@ describe('| LVS_VectorPool_ControlService', () => {
|
|
|
399
399
|
);
|
|
400
400
|
|
|
401
401
|
// vec1 should have score = 0 (identical)
|
|
402
|
-
const vec1Result: LVS_SearchResult | undefined =
|
|
402
|
+
const vec1Result: LVS_SearchResult | undefined =
|
|
403
403
|
results.find((r: LVS_SearchResult) => r.id === 'vec1');
|
|
404
404
|
expect(vec1Result).toBeDefined();
|
|
405
405
|
expect(vec1Result!.score).toBe(0);
|
|
406
406
|
});
|
|
407
|
+
|
|
408
|
+
it('| should restrict results to the candidateIds set (cosine)', () => {
|
|
409
|
+
const query: number[] = [1, 0, 0];
|
|
410
|
+
const candidateIds: Set<string> = new Set<string>(['vec2', 'vec3']);
|
|
411
|
+
const results: LVS_SearchResult[] = vectorPool.search(
|
|
412
|
+
query, 10, LVS_Search_Mode.cosineSimilarity, candidateIds
|
|
413
|
+
);
|
|
414
|
+
// CSAK a jelölt-halmaz ID-jai jelenhetnek meg (vec1/vec4 kizárva).
|
|
415
|
+
expect(results.length).toBe(2);
|
|
416
|
+
for (const r of results) {
|
|
417
|
+
expect(candidateIds.has(r.id)).toBe(true);
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('| should restrict results to the candidateIds set (L2)', () => {
|
|
422
|
+
const query: number[] = [1, 0, 0];
|
|
423
|
+
const candidateIds: Set<string> = new Set<string>(['vec1', 'vec4']);
|
|
424
|
+
const results: LVS_SearchResult[] = vectorPool.search(
|
|
425
|
+
query, 10, LVS_Search_Mode.l2Distance, candidateIds
|
|
426
|
+
);
|
|
427
|
+
expect(results.length).toBe(2);
|
|
428
|
+
expect(results.map((r: LVS_SearchResult) => r.id).sort()).toEqual(['vec1', 'vec4']);
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('| should give candidateId-scoped scores IDENTICAL to an unfiltered search filtered post-hoc', () => {
|
|
432
|
+
// A scoped keresés EREDMÉNYE (score-ok + sorrend) bit-azonos a teljes keresés azon
|
|
433
|
+
// részhalmazával, amit utólag a candidate-ID-kra szűrnénk — a szűrés csak SZŰKÍT, nem torzít.
|
|
434
|
+
const query: number[] = [1, 1, 0];
|
|
435
|
+
const candidateIds: Set<string> = new Set<string>(['vec1', 'vec2', 'vec4']);
|
|
436
|
+
const scoped: LVS_SearchResult[] = vectorPool.search(query, 10, LVS_Search_Mode.cosineSimilarity, candidateIds);
|
|
437
|
+
const full: LVS_SearchResult[] = vectorPool
|
|
438
|
+
.search(query, 10, LVS_Search_Mode.cosineSimilarity)
|
|
439
|
+
.filter((r: LVS_SearchResult) => candidateIds.has(r.id));
|
|
440
|
+
expect(scoped.length).toBe(full.length);
|
|
441
|
+
for (let i: number = 0; i < scoped.length; i++) {
|
|
442
|
+
expect(scoped[i].id).toBe(full[i].id);
|
|
443
|
+
expect(scoped[i].score).toBeCloseTo(full[i].score, 12);
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it('| should return empty array for an empty candidateIds set', () => {
|
|
448
|
+
const results: LVS_SearchResult[] = vectorPool.search(
|
|
449
|
+
[1, 0, 0], 10, LVS_Search_Mode.cosineSimilarity, new Set<string>()
|
|
450
|
+
);
|
|
451
|
+
expect(results.length).toBe(0);
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
describe('| normalizedOnly mode (memory-optimized cosine-only pool)', () => {
|
|
456
|
+
let pool: LVS_VectorPool_ControlService;
|
|
457
|
+
|
|
458
|
+
beforeEach(() => {
|
|
459
|
+
pool = new LVS_VectorPool_ControlService({ normalizedOnly: true });
|
|
460
|
+
pool.addVector('vec1', [1, 0, 0]);
|
|
461
|
+
pool.addVector('vec2', [0, 1, 0]);
|
|
462
|
+
pool.addVector('vec3', [1, 1, 0]);
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
it('| should NOT store raw vectors (getAll empty) but size() correct', () => {
|
|
466
|
+
expect(pool.getAll().size).toBe(0);
|
|
467
|
+
expect(pool.size()).toBe(3);
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it('| cosine search works identically to a normal pool', () => {
|
|
471
|
+
const normal: LVS_VectorPool_ControlService = new LVS_VectorPool_ControlService();
|
|
472
|
+
normal.addVector('vec1', [1, 0, 0]);
|
|
473
|
+
normal.addVector('vec2', [0, 1, 0]);
|
|
474
|
+
normal.addVector('vec3', [1, 1, 0]);
|
|
475
|
+
|
|
476
|
+
const query: number[] = [1, 0.2, 0];
|
|
477
|
+
const a: LVS_SearchResult[] = pool.search(query, 3, LVS_Search_Mode.cosineSimilarity);
|
|
478
|
+
const b: LVS_SearchResult[] = normal.search(query, 3, LVS_Search_Mode.cosineSimilarity);
|
|
479
|
+
expect(a.length).toBe(b.length);
|
|
480
|
+
for (let i: number = 0; i < a.length; i++) {
|
|
481
|
+
expect(a[i].id).toBe(b[i].id);
|
|
482
|
+
expect(a[i].score).toBeCloseTo(b[i].score, 12);
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
it('| cosine search honors candidateIds in normalizedOnly mode', () => {
|
|
487
|
+
const results: LVS_SearchResult[] = pool.search(
|
|
488
|
+
[1, 0, 0], 10, LVS_Search_Mode.cosineSimilarity, new Set<string>(['vec2', 'vec3'])
|
|
489
|
+
);
|
|
490
|
+
expect(results.length).toBe(2);
|
|
491
|
+
for (const r of results) {
|
|
492
|
+
expect(['vec2', 'vec3']).toContain(r.id);
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
it('| l2Distance throws in normalizedOnly mode (no raw vectors)', () => {
|
|
497
|
+
expect(() => pool.search([1, 0, 0], 3, LVS_Search_Mode.l2Distance))
|
|
498
|
+
.toThrowError(/normalizedOnly/);
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
it('| updateVector works (checks normalized pool, not raw)', () => {
|
|
502
|
+
expect(() => pool.updateVector('vec1', [0, 0, 1])).not.toThrow();
|
|
503
|
+
expect(() => pool.updateVector('missing', [0, 0, 1])).toThrowError(/does not exist/);
|
|
504
|
+
});
|
|
407
505
|
});
|
|
408
506
|
});
|
|
409
507
|
|
|
@@ -19,6 +19,18 @@ export class LVS_VectorPool_ControlService {
|
|
|
19
19
|
*/
|
|
20
20
|
private normalizedVectorPool: Map<string, number[]> = new Map<string, number[]>();
|
|
21
21
|
|
|
22
|
+
/**
|
|
23
|
+
* `normalizedOnly` mód: ha `true`, a pool NEM tárolja a nyers vektorokat (`vectorPool`) — CSAK a
|
|
24
|
+
* normalizált másolatot. A kizárólag-cosine fogyasztóknak (pl. RAG-keresés) ez ~50% memória-megtakarítás
|
|
25
|
+
* (a két párhuzamos pool helyett egy). Ekkor az `l2Distance`-keresés és a `getAll()` nyers-érték-olvasása
|
|
26
|
+
* N/A (a `size()` + a `cosineSimilarity`-keresés továbbra is helyes). Default `false` (visszafelé kompatibilis).
|
|
27
|
+
*/
|
|
28
|
+
private readonly normalizedOnly: boolean;
|
|
29
|
+
|
|
30
|
+
constructor(set?: { normalizedOnly?: boolean }) {
|
|
31
|
+
this.normalizedOnly = set?.normalizedOnly ?? false;
|
|
32
|
+
}
|
|
33
|
+
|
|
22
34
|
/**
|
|
23
35
|
* Hozzáad egy vektort a pool-hoz
|
|
24
36
|
* Opcionálisan L2 normalizált másolatot is tárol
|
|
@@ -39,8 +51,10 @@ export class LVS_VectorPool_ControlService {
|
|
|
39
51
|
}
|
|
40
52
|
}
|
|
41
53
|
|
|
42
|
-
// Tároljuk az eredeti vektort
|
|
43
|
-
this.
|
|
54
|
+
// Tároljuk az eredeti vektort — KIVÉVE normalizedOnly módban (akkor a nyers pool kihagyva, ~50% memória).
|
|
55
|
+
if (!this.normalizedOnly) {
|
|
56
|
+
this.vectorPool.set(id, vector);
|
|
57
|
+
}
|
|
44
58
|
|
|
45
59
|
// L2 normalizált másolatot is tárolunk a cosine similarity számításokhoz
|
|
46
60
|
const normalized: number[] = LVS_VectorPool_ControlService.l2Normalize(vector);
|
|
@@ -59,13 +73,22 @@ export class LVS_VectorPool_ControlService {
|
|
|
59
73
|
* Frissít egy vektort a pool-ban
|
|
60
74
|
*/
|
|
61
75
|
updateVector(id: string, vector: number[]): void {
|
|
62
|
-
|
|
76
|
+
// A `normalizedVectorPool` a forrás (mindkét módban populált; `normalizedOnly`-ban a `vectorPool` üres).
|
|
77
|
+
if (!this.normalizedVectorPool.has(id)) {
|
|
63
78
|
throw new Error(`Vector with ID "${id}" does not exist`);
|
|
64
79
|
}
|
|
65
80
|
|
|
66
81
|
this.addVector(id, vector);
|
|
67
82
|
}
|
|
68
83
|
|
|
84
|
+
/**
|
|
85
|
+
* A pool elemszáma. Mindkét módban helyes (a `normalizedVectorPool` a forrás), így `normalizedOnly`
|
|
86
|
+
* módban is — szemben a `getAll().size`-szal, ami ott üres (a nyers pool nincs tárolva).
|
|
87
|
+
*/
|
|
88
|
+
size(): number {
|
|
89
|
+
return this.normalizedVectorPool.size;
|
|
90
|
+
}
|
|
91
|
+
|
|
69
92
|
/**
|
|
70
93
|
* Törli az összes vektort a pool-ból
|
|
71
94
|
*/
|
|
@@ -157,13 +180,22 @@ export class LVS_VectorPool_ControlService {
|
|
|
157
180
|
* @param query A keresési query vektor
|
|
158
181
|
* @param k A visszaadandó találatok száma (top-K)
|
|
159
182
|
* @param mode A keresési mód (cosine similarity vagy L2 distance)
|
|
183
|
+
* @param candidateIds Opcionális jelölt-ID szűrő: ha meg van adva, a keresés CSAK az ebben a
|
|
184
|
+
* halmazban lévő ID-kra fut (a többit `Set.has` O(1)-gyel kihagyja). Így a hívónak NEM kell külön
|
|
185
|
+
* szűkített pool-t építenie + a vektorokat újra-normalizálnia — a keresés a MÁR előre-normalizált
|
|
186
|
+
* `normalizedVectorPool`-on iterál allokáció-mentesen. Üres halmaz → üres eredmény.
|
|
160
187
|
* @returns A top-K találatok ID-val és score-rel, megfelelő sorrendben
|
|
161
188
|
*/
|
|
162
189
|
search(
|
|
163
190
|
query: number[],
|
|
164
191
|
k: number,
|
|
165
|
-
mode: LVS_Search_Mode
|
|
192
|
+
mode: LVS_Search_Mode,
|
|
193
|
+
candidateIds?: Set<string>
|
|
166
194
|
): LVS_SearchResult[] {
|
|
195
|
+
// Üres jelölt-halmaz → nincs mit keresni (a `undefined` viszont „nincs szűrés" = teljes pool).
|
|
196
|
+
if (candidateIds && candidateIds.size === 0) {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
167
199
|
if (!Array.isArray(query) || query.length === 0) {
|
|
168
200
|
throw new Error('Query vector must be a non-empty array');
|
|
169
201
|
}
|
|
@@ -172,12 +204,22 @@ export class LVS_VectorPool_ControlService {
|
|
|
172
204
|
throw new Error('k must be a positive number');
|
|
173
205
|
}
|
|
174
206
|
|
|
175
|
-
|
|
207
|
+
// `normalizedOnly` módban nincs nyers pool → l2Distance nem számolható (csak cosine).
|
|
208
|
+
if (this.normalizedOnly && mode === LVS_Search_Mode.l2Distance) {
|
|
209
|
+
throw new Error('l2Distance search is not available in normalizedOnly mode (raw vectors are not stored)');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Üres pool → üres eredmény. A `normalizedVectorPool` a forrás (mindkét módban populált; a nyers
|
|
213
|
+
// `vectorPool` `normalizedOnly`-ban üres, ezért NEM azon ellenőrzünk).
|
|
214
|
+
if (this.normalizedVectorPool.size === 0) {
|
|
176
215
|
return [];
|
|
177
216
|
}
|
|
178
217
|
|
|
179
|
-
// Validáljuk, hogy minden vektor ugyanolyan dimenziójú-e
|
|
180
|
-
|
|
218
|
+
// Validáljuk, hogy minden vektor ugyanolyan dimenziójú-e. A referencia-pool mód-függő: l2 a nyers,
|
|
219
|
+
// cosine a normalizált (azonos dimenzió, de `normalizedOnly`-ban a nyers pool üres).
|
|
220
|
+
const referencePool: Map<string, number[]> =
|
|
221
|
+
mode === LVS_Search_Mode.l2Distance ? this.vectorPool : this.normalizedVectorPool;
|
|
222
|
+
const firstVector: number[] | undefined = Array.from(referencePool.values())[0];
|
|
181
223
|
if (firstVector && firstVector.length !== query.length) {
|
|
182
224
|
throw new Error(
|
|
183
225
|
`Query vector dimension (${query.length}) does not match pool vector ` +
|
|
@@ -199,6 +241,9 @@ export class LVS_VectorPool_ControlService {
|
|
|
199
241
|
// A drágán eltárolt `normalizedVectorPool` korábban SOHA nem volt használva a keresésben.
|
|
200
242
|
const queryNormalized: number[] = LVS_VectorPool_ControlService.l2Normalize(query);
|
|
201
243
|
for (const [id, normalizedVector] of this.normalizedVectorPool.entries()) {
|
|
244
|
+
if (candidateIds && !candidateIds.has(id)) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
202
247
|
let dotProduct: number = 0;
|
|
203
248
|
for (let i: number = 0; i < queryNormalized.length; i++) {
|
|
204
249
|
dotProduct += queryNormalized[i] * normalizedVector[i];
|
|
@@ -209,6 +254,9 @@ export class LVS_VectorPool_ControlService {
|
|
|
209
254
|
results.sort((a: LVS_SearchResult, b: LVS_SearchResult) => b.score - a.score);
|
|
210
255
|
} else if (mode === LVS_Search_Mode.l2Distance) {
|
|
211
256
|
for (const [id, vector] of this.vectorPool.entries()) {
|
|
257
|
+
if (candidateIds && !candidateIds.has(id)) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
212
260
|
results.push({ id, score: LVS_VectorPool_ControlService.l2Distance(query, vector) });
|
|
213
261
|
}
|
|
214
262
|
// L2 distance: növekvő sorrend (legkisebb távolság először)
|