@danielsimonjr/memoryjs 1.0.0
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/LICENSE +22 -0
- package/README.md +266 -0
- package/dist/core/EntityManager.d.ts +268 -0
- package/dist/core/EntityManager.d.ts.map +1 -0
- package/dist/core/EntityManager.js +512 -0
- package/dist/core/EntityManager.js.map +1 -0
- package/dist/core/GraphEventEmitter.d.ts +202 -0
- package/dist/core/GraphEventEmitter.d.ts.map +1 -0
- package/dist/core/GraphEventEmitter.js +347 -0
- package/dist/core/GraphEventEmitter.js.map +1 -0
- package/dist/core/GraphStorage.d.ts +395 -0
- package/dist/core/GraphStorage.d.ts.map +1 -0
- package/dist/core/GraphStorage.js +786 -0
- package/dist/core/GraphStorage.js.map +1 -0
- package/dist/core/GraphTraversal.d.ts +141 -0
- package/dist/core/GraphTraversal.d.ts.map +1 -0
- package/dist/core/GraphTraversal.js +574 -0
- package/dist/core/GraphTraversal.js.map +1 -0
- package/dist/core/HierarchyManager.d.ts +111 -0
- package/dist/core/HierarchyManager.d.ts.map +1 -0
- package/dist/core/HierarchyManager.js +225 -0
- package/dist/core/HierarchyManager.js.map +1 -0
- package/dist/core/ManagerContext.d.ts +76 -0
- package/dist/core/ManagerContext.d.ts.map +1 -0
- package/dist/core/ManagerContext.js +129 -0
- package/dist/core/ManagerContext.js.map +1 -0
- package/dist/core/ObservationManager.d.ts +85 -0
- package/dist/core/ObservationManager.d.ts.map +1 -0
- package/dist/core/ObservationManager.js +124 -0
- package/dist/core/ObservationManager.js.map +1 -0
- package/dist/core/RelationManager.d.ts +131 -0
- package/dist/core/RelationManager.d.ts.map +1 -0
- package/dist/core/RelationManager.js +212 -0
- package/dist/core/RelationManager.js.map +1 -0
- package/dist/core/SQLiteStorage.d.ts +354 -0
- package/dist/core/SQLiteStorage.d.ts.map +1 -0
- package/dist/core/SQLiteStorage.js +919 -0
- package/dist/core/SQLiteStorage.js.map +1 -0
- package/dist/core/StorageFactory.d.ts +45 -0
- package/dist/core/StorageFactory.d.ts.map +1 -0
- package/dist/core/StorageFactory.js +65 -0
- package/dist/core/StorageFactory.js.map +1 -0
- package/dist/core/TransactionManager.d.ts +464 -0
- package/dist/core/TransactionManager.d.ts.map +1 -0
- package/dist/core/TransactionManager.js +869 -0
- package/dist/core/TransactionManager.js.map +1 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +20 -0
- package/dist/core/index.js.map +1 -0
- package/dist/features/AnalyticsManager.d.ts +44 -0
- package/dist/features/AnalyticsManager.d.ts.map +1 -0
- package/dist/features/AnalyticsManager.js +224 -0
- package/dist/features/AnalyticsManager.js.map +1 -0
- package/dist/features/ArchiveManager.d.ts +133 -0
- package/dist/features/ArchiveManager.d.ts.map +1 -0
- package/dist/features/ArchiveManager.js +282 -0
- package/dist/features/ArchiveManager.js.map +1 -0
- package/dist/features/CompressionManager.d.ts +119 -0
- package/dist/features/CompressionManager.d.ts.map +1 -0
- package/dist/features/CompressionManager.js +470 -0
- package/dist/features/CompressionManager.js.map +1 -0
- package/dist/features/IOManager.d.ts +225 -0
- package/dist/features/IOManager.d.ts.map +1 -0
- package/dist/features/IOManager.js +1093 -0
- package/dist/features/IOManager.js.map +1 -0
- package/dist/features/KeywordExtractor.d.ts +61 -0
- package/dist/features/KeywordExtractor.d.ts.map +1 -0
- package/dist/features/KeywordExtractor.js +127 -0
- package/dist/features/KeywordExtractor.js.map +1 -0
- package/dist/features/ObservationNormalizer.d.ts +90 -0
- package/dist/features/ObservationNormalizer.d.ts.map +1 -0
- package/dist/features/ObservationNormalizer.js +194 -0
- package/dist/features/ObservationNormalizer.js.map +1 -0
- package/dist/features/StreamingExporter.d.ts +128 -0
- package/dist/features/StreamingExporter.d.ts.map +1 -0
- package/dist/features/StreamingExporter.js +212 -0
- package/dist/features/StreamingExporter.js.map +1 -0
- package/dist/features/TagManager.d.ts +147 -0
- package/dist/features/TagManager.d.ts.map +1 -0
- package/dist/features/TagManager.js +211 -0
- package/dist/features/TagManager.js.map +1 -0
- package/dist/features/index.d.ts +14 -0
- package/dist/features/index.d.ts.map +1 -0
- package/dist/features/index.js +15 -0
- package/dist/features/index.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/search/BM25Search.d.ts +148 -0
- package/dist/search/BM25Search.d.ts.map +1 -0
- package/dist/search/BM25Search.js +340 -0
- package/dist/search/BM25Search.js.map +1 -0
- package/dist/search/BasicSearch.d.ts +51 -0
- package/dist/search/BasicSearch.d.ts.map +1 -0
- package/dist/search/BasicSearch.js +138 -0
- package/dist/search/BasicSearch.js.map +1 -0
- package/dist/search/BooleanSearch.d.ts +98 -0
- package/dist/search/BooleanSearch.d.ts.map +1 -0
- package/dist/search/BooleanSearch.js +431 -0
- package/dist/search/BooleanSearch.js.map +1 -0
- package/dist/search/EarlyTerminationManager.d.ts +140 -0
- package/dist/search/EarlyTerminationManager.d.ts.map +1 -0
- package/dist/search/EarlyTerminationManager.js +280 -0
- package/dist/search/EarlyTerminationManager.js.map +1 -0
- package/dist/search/EmbeddingCache.d.ts +175 -0
- package/dist/search/EmbeddingCache.d.ts.map +1 -0
- package/dist/search/EmbeddingCache.js +247 -0
- package/dist/search/EmbeddingCache.js.map +1 -0
- package/dist/search/EmbeddingService.d.ts +277 -0
- package/dist/search/EmbeddingService.d.ts.map +1 -0
- package/dist/search/EmbeddingService.js +531 -0
- package/dist/search/EmbeddingService.js.map +1 -0
- package/dist/search/FuzzySearch.d.ts +118 -0
- package/dist/search/FuzzySearch.d.ts.map +1 -0
- package/dist/search/FuzzySearch.js +313 -0
- package/dist/search/FuzzySearch.js.map +1 -0
- package/dist/search/HybridScorer.d.ts +181 -0
- package/dist/search/HybridScorer.d.ts.map +1 -0
- package/dist/search/HybridScorer.js +258 -0
- package/dist/search/HybridScorer.js.map +1 -0
- package/dist/search/HybridSearchManager.d.ts +80 -0
- package/dist/search/HybridSearchManager.d.ts.map +1 -0
- package/dist/search/HybridSearchManager.js +188 -0
- package/dist/search/HybridSearchManager.js.map +1 -0
- package/dist/search/IncrementalIndexer.d.ts +201 -0
- package/dist/search/IncrementalIndexer.d.ts.map +1 -0
- package/dist/search/IncrementalIndexer.js +343 -0
- package/dist/search/IncrementalIndexer.js.map +1 -0
- package/dist/search/OptimizedInvertedIndex.d.ts +163 -0
- package/dist/search/OptimizedInvertedIndex.d.ts.map +1 -0
- package/dist/search/OptimizedInvertedIndex.js +359 -0
- package/dist/search/OptimizedInvertedIndex.js.map +1 -0
- package/dist/search/ParallelSearchExecutor.d.ts +172 -0
- package/dist/search/ParallelSearchExecutor.d.ts.map +1 -0
- package/dist/search/ParallelSearchExecutor.js +310 -0
- package/dist/search/ParallelSearchExecutor.js.map +1 -0
- package/dist/search/QuantizedVectorStore.d.ts +171 -0
- package/dist/search/QuantizedVectorStore.d.ts.map +1 -0
- package/dist/search/QuantizedVectorStore.js +308 -0
- package/dist/search/QuantizedVectorStore.js.map +1 -0
- package/dist/search/QueryAnalyzer.d.ts +76 -0
- package/dist/search/QueryAnalyzer.d.ts.map +1 -0
- package/dist/search/QueryAnalyzer.js +228 -0
- package/dist/search/QueryAnalyzer.js.map +1 -0
- package/dist/search/QueryCostEstimator.d.ts +244 -0
- package/dist/search/QueryCostEstimator.d.ts.map +1 -0
- package/dist/search/QueryCostEstimator.js +653 -0
- package/dist/search/QueryCostEstimator.js.map +1 -0
- package/dist/search/QueryPlanCache.d.ts +220 -0
- package/dist/search/QueryPlanCache.d.ts.map +1 -0
- package/dist/search/QueryPlanCache.js +380 -0
- package/dist/search/QueryPlanCache.js.map +1 -0
- package/dist/search/QueryPlanner.d.ts +58 -0
- package/dist/search/QueryPlanner.d.ts.map +1 -0
- package/dist/search/QueryPlanner.js +138 -0
- package/dist/search/QueryPlanner.js.map +1 -0
- package/dist/search/RankedSearch.d.ts +71 -0
- package/dist/search/RankedSearch.d.ts.map +1 -0
- package/dist/search/RankedSearch.js +239 -0
- package/dist/search/RankedSearch.js.map +1 -0
- package/dist/search/ReflectionManager.d.ts +120 -0
- package/dist/search/ReflectionManager.d.ts.map +1 -0
- package/dist/search/ReflectionManager.js +232 -0
- package/dist/search/ReflectionManager.js.map +1 -0
- package/dist/search/SavedSearchManager.d.ts +79 -0
- package/dist/search/SavedSearchManager.d.ts.map +1 -0
- package/dist/search/SavedSearchManager.js +147 -0
- package/dist/search/SavedSearchManager.js.map +1 -0
- package/dist/search/SearchFilterChain.d.ts +120 -0
- package/dist/search/SearchFilterChain.d.ts.map +1 -0
- package/dist/search/SearchFilterChain.js +186 -0
- package/dist/search/SearchFilterChain.js.map +1 -0
- package/dist/search/SearchManager.d.ts +326 -0
- package/dist/search/SearchManager.d.ts.map +1 -0
- package/dist/search/SearchManager.js +454 -0
- package/dist/search/SearchManager.js.map +1 -0
- package/dist/search/SearchSuggestions.d.ts +27 -0
- package/dist/search/SearchSuggestions.d.ts.map +1 -0
- package/dist/search/SearchSuggestions.js +58 -0
- package/dist/search/SearchSuggestions.js.map +1 -0
- package/dist/search/SemanticSearch.d.ts +149 -0
- package/dist/search/SemanticSearch.d.ts.map +1 -0
- package/dist/search/SemanticSearch.js +324 -0
- package/dist/search/SemanticSearch.js.map +1 -0
- package/dist/search/SymbolicSearch.d.ts +61 -0
- package/dist/search/SymbolicSearch.d.ts.map +1 -0
- package/dist/search/SymbolicSearch.js +164 -0
- package/dist/search/SymbolicSearch.js.map +1 -0
- package/dist/search/TFIDFEventSync.d.ts +85 -0
- package/dist/search/TFIDFEventSync.d.ts.map +1 -0
- package/dist/search/TFIDFEventSync.js +134 -0
- package/dist/search/TFIDFEventSync.js.map +1 -0
- package/dist/search/TFIDFIndexManager.d.ts +151 -0
- package/dist/search/TFIDFIndexManager.d.ts.map +1 -0
- package/dist/search/TFIDFIndexManager.js +433 -0
- package/dist/search/TFIDFIndexManager.js.map +1 -0
- package/dist/search/VectorStore.d.ts +235 -0
- package/dist/search/VectorStore.d.ts.map +1 -0
- package/dist/search/VectorStore.js +312 -0
- package/dist/search/VectorStore.js.map +1 -0
- package/dist/search/index.d.ts +35 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +53 -0
- package/dist/search/index.js.map +1 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +13 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/types.d.ts +1811 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/types.js +10 -0
- package/dist/types/types.js.map +1 -0
- package/dist/utils/BatchProcessor.d.ts +271 -0
- package/dist/utils/BatchProcessor.d.ts.map +1 -0
- package/dist/utils/BatchProcessor.js +377 -0
- package/dist/utils/BatchProcessor.js.map +1 -0
- package/dist/utils/MemoryMonitor.d.ts +176 -0
- package/dist/utils/MemoryMonitor.d.ts.map +1 -0
- package/dist/utils/MemoryMonitor.js +306 -0
- package/dist/utils/MemoryMonitor.js.map +1 -0
- package/dist/utils/WorkerPoolManager.d.ts +233 -0
- package/dist/utils/WorkerPoolManager.d.ts.map +1 -0
- package/dist/utils/WorkerPoolManager.js +421 -0
- package/dist/utils/WorkerPoolManager.js.map +1 -0
- package/dist/utils/compressedCache.d.ts +221 -0
- package/dist/utils/compressedCache.d.ts.map +1 -0
- package/dist/utils/compressedCache.js +349 -0
- package/dist/utils/compressedCache.js.map +1 -0
- package/dist/utils/compressionUtil.d.ts +214 -0
- package/dist/utils/compressionUtil.d.ts.map +1 -0
- package/dist/utils/compressionUtil.js +248 -0
- package/dist/utils/compressionUtil.js.map +1 -0
- package/dist/utils/constants.d.ts +245 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +253 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/entityUtils.d.ts +379 -0
- package/dist/utils/entityUtils.d.ts.map +1 -0
- package/dist/utils/entityUtils.js +649 -0
- package/dist/utils/entityUtils.js.map +1 -0
- package/dist/utils/errors.d.ts +95 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +146 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/formatters.d.ts +145 -0
- package/dist/utils/formatters.d.ts.map +1 -0
- package/dist/utils/formatters.js +133 -0
- package/dist/utils/formatters.js.map +1 -0
- package/dist/utils/index.d.ts +26 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +88 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/indexes.d.ts +270 -0
- package/dist/utils/indexes.d.ts.map +1 -0
- package/dist/utils/indexes.js +527 -0
- package/dist/utils/indexes.js.map +1 -0
- package/dist/utils/logger.d.ts +31 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +41 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/operationUtils.d.ts +124 -0
- package/dist/utils/operationUtils.d.ts.map +1 -0
- package/dist/utils/operationUtils.js +176 -0
- package/dist/utils/operationUtils.js.map +1 -0
- package/dist/utils/parallelUtils.d.ts +76 -0
- package/dist/utils/parallelUtils.d.ts.map +1 -0
- package/dist/utils/parallelUtils.js +192 -0
- package/dist/utils/parallelUtils.js.map +1 -0
- package/dist/utils/schemas.d.ts +556 -0
- package/dist/utils/schemas.d.ts.map +1 -0
- package/dist/utils/schemas.js +485 -0
- package/dist/utils/schemas.js.map +1 -0
- package/dist/utils/searchAlgorithms.d.ts +99 -0
- package/dist/utils/searchAlgorithms.d.ts.map +1 -0
- package/dist/utils/searchAlgorithms.js +168 -0
- package/dist/utils/searchAlgorithms.js.map +1 -0
- package/dist/utils/searchCache.d.ts +108 -0
- package/dist/utils/searchCache.d.ts.map +1 -0
- package/dist/utils/searchCache.js +210 -0
- package/dist/utils/searchCache.js.map +1 -0
- package/dist/utils/taskScheduler.d.ts +294 -0
- package/dist/utils/taskScheduler.d.ts.map +1 -0
- package/dist/utils/taskScheduler.js +487 -0
- package/dist/utils/taskScheduler.js.map +1 -0
- package/dist/workers/index.d.ts +12 -0
- package/dist/workers/index.d.ts.map +1 -0
- package/dist/workers/index.js +10 -0
- package/dist/workers/index.js.map +1 -0
- package/dist/workers/levenshteinWorker.d.ts +60 -0
- package/dist/workers/levenshteinWorker.d.ts.map +1 -0
- package/dist/workers/levenshteinWorker.js +99 -0
- package/dist/workers/levenshteinWorker.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hybrid Scorer
|
|
3
|
+
*
|
|
4
|
+
* Combines semantic, lexical, and symbolic search scores with
|
|
5
|
+
* min-max normalization and configurable weights.
|
|
6
|
+
*
|
|
7
|
+
* Phase 12 Sprint 3: Search Algorithm Optimization
|
|
8
|
+
*
|
|
9
|
+
* @module search/HybridScorer
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Default weights for hybrid search.
|
|
13
|
+
*/
|
|
14
|
+
export const DEFAULT_SCORER_WEIGHTS = {
|
|
15
|
+
semantic: 0.4,
|
|
16
|
+
lexical: 0.4,
|
|
17
|
+
symbolic: 0.2,
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* HybridScorer combines multiple search signals using min-max normalization.
|
|
21
|
+
*
|
|
22
|
+
* Features:
|
|
23
|
+
* 1. Min-max normalization brings all scores to 0-1 range
|
|
24
|
+
* 2. Configurable weights for each layer
|
|
25
|
+
* 3. Handles missing layers gracefully (redistributes weights)
|
|
26
|
+
* 4. Tracks which layers contributed to each result
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const scorer = new HybridScorer({
|
|
31
|
+
* weights: { semantic: 0.5, lexical: 0.3, symbolic: 0.2 }
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* const results = scorer.combine(
|
|
35
|
+
* semanticResults,
|
|
36
|
+
* lexicalResults,
|
|
37
|
+
* symbolicResults,
|
|
38
|
+
* entityMap
|
|
39
|
+
* );
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export class HybridScorer {
|
|
43
|
+
weights;
|
|
44
|
+
minScore;
|
|
45
|
+
normalizeWeights;
|
|
46
|
+
constructor(options = {}) {
|
|
47
|
+
this.weights = {
|
|
48
|
+
...DEFAULT_SCORER_WEIGHTS,
|
|
49
|
+
...options.weights,
|
|
50
|
+
};
|
|
51
|
+
this.minScore = options.minScore ?? 0;
|
|
52
|
+
this.normalizeWeights = options.normalizeWeights ?? true;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get current weights configuration.
|
|
56
|
+
*/
|
|
57
|
+
getWeights() {
|
|
58
|
+
return { ...this.weights };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Update weights configuration.
|
|
62
|
+
*/
|
|
63
|
+
setWeights(weights) {
|
|
64
|
+
this.weights = { ...this.weights, ...weights };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Perform min-max normalization on scores.
|
|
68
|
+
*
|
|
69
|
+
* Formula: normalized = (x - min) / (max - min)
|
|
70
|
+
*
|
|
71
|
+
* @param scores - Map of entity name to raw score
|
|
72
|
+
* @returns Map of entity name to normalized score (0-1)
|
|
73
|
+
*/
|
|
74
|
+
minMaxNormalize(scores) {
|
|
75
|
+
if (scores.size === 0) {
|
|
76
|
+
return new Map();
|
|
77
|
+
}
|
|
78
|
+
// Find min and max
|
|
79
|
+
let min = Infinity;
|
|
80
|
+
let max = -Infinity;
|
|
81
|
+
for (const score of scores.values()) {
|
|
82
|
+
if (score < min)
|
|
83
|
+
min = score;
|
|
84
|
+
if (score > max)
|
|
85
|
+
max = score;
|
|
86
|
+
}
|
|
87
|
+
// Handle edge case where all scores are the same
|
|
88
|
+
if (max === min) {
|
|
89
|
+
const normalized = new Map();
|
|
90
|
+
for (const name of scores.keys()) {
|
|
91
|
+
// If all scores are zero, keep them zero; otherwise normalize to 1
|
|
92
|
+
normalized.set(name, max === 0 ? 0 : 1);
|
|
93
|
+
}
|
|
94
|
+
return normalized;
|
|
95
|
+
}
|
|
96
|
+
// Normalize
|
|
97
|
+
const range = max - min;
|
|
98
|
+
const normalized = new Map();
|
|
99
|
+
for (const [name, score] of scores) {
|
|
100
|
+
normalized.set(name, (score - min) / range);
|
|
101
|
+
}
|
|
102
|
+
return normalized;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Combine results from all three search layers.
|
|
106
|
+
*
|
|
107
|
+
* @param semanticResults - Results from semantic search
|
|
108
|
+
* @param lexicalResults - Results from lexical search
|
|
109
|
+
* @param symbolicResults - Results from symbolic search
|
|
110
|
+
* @param entityMap - Map of entity names to Entity objects
|
|
111
|
+
* @returns Array of combined results sorted by score
|
|
112
|
+
*/
|
|
113
|
+
combine(semanticResults, lexicalResults, symbolicResults, entityMap) {
|
|
114
|
+
// Build score maps
|
|
115
|
+
const semanticScores = new Map();
|
|
116
|
+
for (const result of semanticResults) {
|
|
117
|
+
semanticScores.set(result.entityName, result.similarity);
|
|
118
|
+
}
|
|
119
|
+
const lexicalScores = new Map();
|
|
120
|
+
for (const result of lexicalResults) {
|
|
121
|
+
lexicalScores.set(result.entityName, result.score);
|
|
122
|
+
}
|
|
123
|
+
const symbolicScores = new Map();
|
|
124
|
+
for (const result of symbolicResults) {
|
|
125
|
+
symbolicScores.set(result.entityName, result.score);
|
|
126
|
+
}
|
|
127
|
+
// Normalize scores
|
|
128
|
+
const normalizedSemantic = this.minMaxNormalize(semanticScores);
|
|
129
|
+
const normalizedLexical = this.minMaxNormalize(lexicalScores);
|
|
130
|
+
const normalizedSymbolic = this.minMaxNormalize(symbolicScores);
|
|
131
|
+
// Calculate effective weights
|
|
132
|
+
let effectiveWeights = { ...this.weights };
|
|
133
|
+
if (this.normalizeWeights) {
|
|
134
|
+
effectiveWeights = this.getNormalizedWeights(semanticResults.length > 0, lexicalResults.length > 0, symbolicResults.length > 0);
|
|
135
|
+
}
|
|
136
|
+
// Collect all unique entity names
|
|
137
|
+
const allNames = new Set([
|
|
138
|
+
...normalizedSemantic.keys(),
|
|
139
|
+
...normalizedLexical.keys(),
|
|
140
|
+
...normalizedSymbolic.keys(),
|
|
141
|
+
]);
|
|
142
|
+
// Calculate combined scores
|
|
143
|
+
const results = [];
|
|
144
|
+
for (const entityName of allNames) {
|
|
145
|
+
const entity = entityMap.get(entityName);
|
|
146
|
+
if (!entity)
|
|
147
|
+
continue;
|
|
148
|
+
const semanticScore = normalizedSemantic.get(entityName) ?? 0;
|
|
149
|
+
const lexicalScore = normalizedLexical.get(entityName) ?? 0;
|
|
150
|
+
const symbolicScore = normalizedSymbolic.get(entityName) ?? 0;
|
|
151
|
+
// Calculate weighted combination
|
|
152
|
+
const combined = semanticScore * effectiveWeights.semantic +
|
|
153
|
+
lexicalScore * effectiveWeights.lexical +
|
|
154
|
+
symbolicScore * effectiveWeights.symbolic;
|
|
155
|
+
// Track matched layers
|
|
156
|
+
const matchedLayers = [];
|
|
157
|
+
const rawScores = {};
|
|
158
|
+
if (semanticScores.has(entityName)) {
|
|
159
|
+
matchedLayers.push('semantic');
|
|
160
|
+
rawScores.semantic = semanticScores.get(entityName);
|
|
161
|
+
}
|
|
162
|
+
if (lexicalScores.has(entityName)) {
|
|
163
|
+
matchedLayers.push('lexical');
|
|
164
|
+
rawScores.lexical = lexicalScores.get(entityName);
|
|
165
|
+
}
|
|
166
|
+
if (symbolicScores.has(entityName)) {
|
|
167
|
+
matchedLayers.push('symbolic');
|
|
168
|
+
rawScores.symbolic = symbolicScores.get(entityName);
|
|
169
|
+
}
|
|
170
|
+
// Skip if below minimum score or no layers matched
|
|
171
|
+
if (combined < this.minScore || matchedLayers.length === 0) {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
results.push({
|
|
175
|
+
entityName,
|
|
176
|
+
entity,
|
|
177
|
+
scores: {
|
|
178
|
+
semantic: semanticScore,
|
|
179
|
+
lexical: lexicalScore,
|
|
180
|
+
symbolic: symbolicScore,
|
|
181
|
+
combined,
|
|
182
|
+
},
|
|
183
|
+
matchedLayers,
|
|
184
|
+
rawScores,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
// Sort by combined score descending
|
|
188
|
+
return results.sort((a, b) => b.scores.combined - a.scores.combined);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get weights normalized to sum to 1, redistributing for missing layers.
|
|
192
|
+
*
|
|
193
|
+
* @param hasSemantic - Whether semantic results are available
|
|
194
|
+
* @param hasLexical - Whether lexical results are available
|
|
195
|
+
* @param hasSymbolic - Whether symbolic results are available
|
|
196
|
+
* @returns Normalized weights
|
|
197
|
+
*/
|
|
198
|
+
getNormalizedWeights(hasSemantic, hasLexical, hasSymbolic) {
|
|
199
|
+
let totalActiveWeight = 0;
|
|
200
|
+
if (hasSemantic)
|
|
201
|
+
totalActiveWeight += this.weights.semantic;
|
|
202
|
+
if (hasLexical)
|
|
203
|
+
totalActiveWeight += this.weights.lexical;
|
|
204
|
+
if (hasSymbolic)
|
|
205
|
+
totalActiveWeight += this.weights.symbolic;
|
|
206
|
+
// If no layers are active, return zero weights
|
|
207
|
+
if (totalActiveWeight === 0) {
|
|
208
|
+
return { semantic: 0, lexical: 0, symbolic: 0 };
|
|
209
|
+
}
|
|
210
|
+
// Normalize active weights to sum to 1
|
|
211
|
+
return {
|
|
212
|
+
semantic: hasSemantic ? this.weights.semantic / totalActiveWeight : 0,
|
|
213
|
+
lexical: hasLexical ? this.weights.lexical / totalActiveWeight : 0,
|
|
214
|
+
symbolic: hasSymbolic ? this.weights.symbolic / totalActiveWeight : 0,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Combine scores from maps directly (alternative interface).
|
|
219
|
+
*
|
|
220
|
+
* @param semanticScores - Map of entity name to semantic score
|
|
221
|
+
* @param lexicalScores - Map of entity name to lexical score
|
|
222
|
+
* @param symbolicScores - Map of entity name to symbolic score
|
|
223
|
+
* @param entityMap - Map of entity names to Entity objects
|
|
224
|
+
* @returns Array of combined results sorted by score
|
|
225
|
+
*/
|
|
226
|
+
combineFromMaps(semanticScores, lexicalScores, symbolicScores, entityMap) {
|
|
227
|
+
// Convert maps to result arrays
|
|
228
|
+
const semanticResults = [];
|
|
229
|
+
for (const [entityName, similarity] of semanticScores) {
|
|
230
|
+
semanticResults.push({ entityName, similarity });
|
|
231
|
+
}
|
|
232
|
+
const lexicalResults = [];
|
|
233
|
+
for (const [entityName, score] of lexicalScores) {
|
|
234
|
+
lexicalResults.push({ entityName, score });
|
|
235
|
+
}
|
|
236
|
+
const symbolicResults = [];
|
|
237
|
+
for (const [entityName, score] of symbolicScores) {
|
|
238
|
+
symbolicResults.push({ entityName, score });
|
|
239
|
+
}
|
|
240
|
+
return this.combine(semanticResults, lexicalResults, symbolicResults, entityMap);
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Calculate combined score for a single entity.
|
|
244
|
+
*
|
|
245
|
+
* Useful for scoring individual results without full normalization.
|
|
246
|
+
*
|
|
247
|
+
* @param semanticScore - Normalized semantic score (0-1)
|
|
248
|
+
* @param lexicalScore - Normalized lexical score (0-1)
|
|
249
|
+
* @param symbolicScore - Normalized symbolic score (0-1)
|
|
250
|
+
* @returns Combined weighted score
|
|
251
|
+
*/
|
|
252
|
+
calculateScore(semanticScore, lexicalScore, symbolicScore) {
|
|
253
|
+
return (semanticScore * this.weights.semantic +
|
|
254
|
+
lexicalScore * this.weights.lexical +
|
|
255
|
+
symbolicScore * this.weights.symbolic);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=HybridScorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HybridScorer.js","sourceRoot":"","sources":["../../src/search/HybridScorer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hybrid Search Manager
|
|
3
|
+
*
|
|
4
|
+
* Phase 11: Orchestrates three-layer hybrid search combining
|
|
5
|
+
* semantic, lexical, and symbolic signals.
|
|
6
|
+
*
|
|
7
|
+
* @module search/HybridSearchManager
|
|
8
|
+
*/
|
|
9
|
+
import type { HybridSearchOptions, HybridSearchResult, ReadonlyKnowledgeGraph } from '../types/index.js';
|
|
10
|
+
import type { SemanticSearch } from './SemanticSearch.js';
|
|
11
|
+
import type { RankedSearch } from './RankedSearch.js';
|
|
12
|
+
import { SymbolicSearch } from './SymbolicSearch.js';
|
|
13
|
+
/**
|
|
14
|
+
* Default weights for hybrid search layers.
|
|
15
|
+
*/
|
|
16
|
+
export declare const DEFAULT_HYBRID_WEIGHTS: {
|
|
17
|
+
semantic: number;
|
|
18
|
+
lexical: number;
|
|
19
|
+
symbolic: number;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Hybrid Search Manager
|
|
23
|
+
*
|
|
24
|
+
* Combines three search layers:
|
|
25
|
+
* 1. Semantic: Vector similarity via embeddings
|
|
26
|
+
* 2. Lexical: Keyword matching via TF-IDF/BM25
|
|
27
|
+
* 3. Symbolic: Structured metadata filtering
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const hybrid = new HybridSearchManager(semanticSearch, rankedSearch);
|
|
32
|
+
* const results = await hybrid.search(graph, 'machine learning', {
|
|
33
|
+
* semanticWeight: 0.5,
|
|
34
|
+
* lexicalWeight: 0.3,
|
|
35
|
+
* symbolicWeight: 0.2,
|
|
36
|
+
* symbolic: { tags: ['ai'] }
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare class HybridSearchManager {
|
|
41
|
+
private semanticSearch;
|
|
42
|
+
private rankedSearch;
|
|
43
|
+
private symbolicSearch;
|
|
44
|
+
constructor(semanticSearch: SemanticSearch | null, rankedSearch: RankedSearch);
|
|
45
|
+
/**
|
|
46
|
+
* Perform hybrid search combining all three layers.
|
|
47
|
+
*
|
|
48
|
+
* @param graph - Knowledge graph to search
|
|
49
|
+
* @param query - Search query text
|
|
50
|
+
* @param options - Hybrid search options with weights
|
|
51
|
+
* @returns Combined and ranked results
|
|
52
|
+
*/
|
|
53
|
+
search(graph: ReadonlyKnowledgeGraph, query: string, options?: Partial<HybridSearchOptions>): Promise<HybridSearchResult[]>;
|
|
54
|
+
/**
|
|
55
|
+
* Execute semantic search layer.
|
|
56
|
+
*/
|
|
57
|
+
private executeSemanticSearch;
|
|
58
|
+
/**
|
|
59
|
+
* Execute lexical search layer (TF-IDF/BM25).
|
|
60
|
+
*/
|
|
61
|
+
private executeLexicalSearch;
|
|
62
|
+
/**
|
|
63
|
+
* Execute symbolic search layer.
|
|
64
|
+
*/
|
|
65
|
+
private executeSymbolicSearch;
|
|
66
|
+
/**
|
|
67
|
+
* Merge results from all three layers.
|
|
68
|
+
*/
|
|
69
|
+
private mergeResults;
|
|
70
|
+
/**
|
|
71
|
+
* Search with full entity resolution.
|
|
72
|
+
* Alias for search() since we now always resolve entities.
|
|
73
|
+
*/
|
|
74
|
+
searchWithEntities(graph: ReadonlyKnowledgeGraph, query: string, options?: Partial<HybridSearchOptions>): Promise<HybridSearchResult[]>;
|
|
75
|
+
/**
|
|
76
|
+
* Get the symbolic search instance for direct access.
|
|
77
|
+
*/
|
|
78
|
+
getSymbolicSearch(): SymbolicSearch;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=HybridSearchManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HybridSearchManager.d.ts","sourceRoot":"","sources":["../../src/search/HybridSearchManager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAEV,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EAEvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD;;GAEG;AACH,eAAO,MAAM,sBAAsB;;;;CAIlC,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,mBAAmB;IAI5B,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,YAAY;IAJtB,OAAO,CAAC,cAAc,CAAiB;gBAG7B,cAAc,EAAE,cAAc,GAAG,IAAI,EACrC,YAAY,EAAE,YAAY;IAKpC;;;;;;;OAOG;IACG,MAAM,CACV,KAAK,EAAE,sBAAsB,EAC7B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,OAAO,CAAC,mBAAmB,CAAM,GACzC,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAuChC;;OAEG;YACW,qBAAqB;IA8BnC;;OAEG;YACW,oBAAoB;IA4BlC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAsB7B;;OAEG;IACH,OAAO,CAAC,YAAY;IAkDpB;;;OAGG;IACG,kBAAkB,CACtB,KAAK,EAAE,sBAAsB,EAC7B,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,OAAO,CAAC,mBAAmB,CAAM,GACzC,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAIhC;;OAEG;IACH,iBAAiB,IAAI,cAAc;CAGpC"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hybrid Search Manager
|
|
3
|
+
*
|
|
4
|
+
* Phase 11: Orchestrates three-layer hybrid search combining
|
|
5
|
+
* semantic, lexical, and symbolic signals.
|
|
6
|
+
*
|
|
7
|
+
* @module search/HybridSearchManager
|
|
8
|
+
*/
|
|
9
|
+
import { SymbolicSearch } from './SymbolicSearch.js';
|
|
10
|
+
import { SEMANTIC_SEARCH_LIMITS } from '../utils/constants.js';
|
|
11
|
+
/**
|
|
12
|
+
* Default weights for hybrid search layers.
|
|
13
|
+
*/
|
|
14
|
+
export const DEFAULT_HYBRID_WEIGHTS = {
|
|
15
|
+
semantic: 0.5,
|
|
16
|
+
lexical: 0.3,
|
|
17
|
+
symbolic: 0.2,
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Hybrid Search Manager
|
|
21
|
+
*
|
|
22
|
+
* Combines three search layers:
|
|
23
|
+
* 1. Semantic: Vector similarity via embeddings
|
|
24
|
+
* 2. Lexical: Keyword matching via TF-IDF/BM25
|
|
25
|
+
* 3. Symbolic: Structured metadata filtering
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const hybrid = new HybridSearchManager(semanticSearch, rankedSearch);
|
|
30
|
+
* const results = await hybrid.search(graph, 'machine learning', {
|
|
31
|
+
* semanticWeight: 0.5,
|
|
32
|
+
* lexicalWeight: 0.3,
|
|
33
|
+
* symbolicWeight: 0.2,
|
|
34
|
+
* symbolic: { tags: ['ai'] }
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export class HybridSearchManager {
|
|
39
|
+
semanticSearch;
|
|
40
|
+
rankedSearch;
|
|
41
|
+
symbolicSearch;
|
|
42
|
+
constructor(semanticSearch, rankedSearch) {
|
|
43
|
+
this.semanticSearch = semanticSearch;
|
|
44
|
+
this.rankedSearch = rankedSearch;
|
|
45
|
+
this.symbolicSearch = new SymbolicSearch();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Perform hybrid search combining all three layers.
|
|
49
|
+
*
|
|
50
|
+
* @param graph - Knowledge graph to search
|
|
51
|
+
* @param query - Search query text
|
|
52
|
+
* @param options - Hybrid search options with weights
|
|
53
|
+
* @returns Combined and ranked results
|
|
54
|
+
*/
|
|
55
|
+
async search(graph, query, options = {}) {
|
|
56
|
+
const { semanticWeight = DEFAULT_HYBRID_WEIGHTS.semantic, lexicalWeight = DEFAULT_HYBRID_WEIGHTS.lexical, symbolicWeight = DEFAULT_HYBRID_WEIGHTS.symbolic, semantic = {}, lexical = {}, symbolic = {}, limit = SEMANTIC_SEARCH_LIMITS.DEFAULT_LIMIT, } = options;
|
|
57
|
+
// Normalize weights
|
|
58
|
+
const totalWeight = semanticWeight + lexicalWeight + symbolicWeight;
|
|
59
|
+
const normSemantic = semanticWeight / totalWeight;
|
|
60
|
+
const normLexical = lexicalWeight / totalWeight;
|
|
61
|
+
const normSymbolic = symbolicWeight / totalWeight;
|
|
62
|
+
// Execute searches in parallel
|
|
63
|
+
const [semanticResults, lexicalResults, symbolicResults] = await Promise.all([
|
|
64
|
+
this.executeSemanticSearch(graph, query, semantic, limit * 2),
|
|
65
|
+
this.executeLexicalSearch(query, lexical, limit * 2),
|
|
66
|
+
this.executeSymbolicSearch(graph.entities, symbolic),
|
|
67
|
+
]);
|
|
68
|
+
// Merge results
|
|
69
|
+
const merged = this.mergeResults(graph.entities, semanticResults, lexicalResults, symbolicResults, { semantic: normSemantic, lexical: normLexical, symbolic: normSymbolic });
|
|
70
|
+
// Sort by combined score and limit
|
|
71
|
+
return merged
|
|
72
|
+
.sort((a, b) => b.scores.combined - a.scores.combined)
|
|
73
|
+
.slice(0, limit);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Execute semantic search layer.
|
|
77
|
+
*/
|
|
78
|
+
async executeSemanticSearch(graph, query, options, limit) {
|
|
79
|
+
const results = new Map();
|
|
80
|
+
if (!this.semanticSearch) {
|
|
81
|
+
return results; // Semantic search not available
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const semanticResults = await this.semanticSearch.search(graph, query, options.topK ?? limit, options.minSimilarity ?? 0);
|
|
85
|
+
for (const result of semanticResults) {
|
|
86
|
+
results.set(result.entity.name, result.similarity);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Semantic search may fail if not indexed
|
|
91
|
+
}
|
|
92
|
+
return results;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Execute lexical search layer (TF-IDF/BM25).
|
|
96
|
+
*/
|
|
97
|
+
async executeLexicalSearch(query, _options, limit) {
|
|
98
|
+
const results = new Map();
|
|
99
|
+
try {
|
|
100
|
+
const lexicalResults = await this.rankedSearch.searchNodesRanked(query, undefined, // tags
|
|
101
|
+
undefined, // minImportance
|
|
102
|
+
undefined, // maxImportance
|
|
103
|
+
limit);
|
|
104
|
+
// Normalize scores to 0-1 range
|
|
105
|
+
const maxScore = Math.max(...lexicalResults.map(r => r.score), 1);
|
|
106
|
+
for (const result of lexicalResults) {
|
|
107
|
+
results.set(result.entity.name, result.score / maxScore);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
// Lexical search may fail
|
|
112
|
+
}
|
|
113
|
+
return results;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Execute symbolic search layer.
|
|
117
|
+
*/
|
|
118
|
+
executeSymbolicSearch(entities, filters) {
|
|
119
|
+
const results = new Map();
|
|
120
|
+
if (!filters || Object.keys(filters).length === 0) {
|
|
121
|
+
// No symbolic filters, give all entities base score
|
|
122
|
+
for (const entity of entities) {
|
|
123
|
+
results.set(entity.name, 0.5);
|
|
124
|
+
}
|
|
125
|
+
return results;
|
|
126
|
+
}
|
|
127
|
+
const symbolicResults = this.symbolicSearch.search(entities, filters);
|
|
128
|
+
for (const result of symbolicResults) {
|
|
129
|
+
results.set(result.entity.name, result.score);
|
|
130
|
+
}
|
|
131
|
+
return results;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Merge results from all three layers.
|
|
135
|
+
*/
|
|
136
|
+
mergeResults(entities, semanticScores, lexicalScores, symbolicScores, weights) {
|
|
137
|
+
// Collect all unique entity names that have at least one non-zero score
|
|
138
|
+
const allNames = new Set([
|
|
139
|
+
...semanticScores.keys(),
|
|
140
|
+
...lexicalScores.keys(),
|
|
141
|
+
...symbolicScores.keys(),
|
|
142
|
+
]);
|
|
143
|
+
// Create entity lookup map
|
|
144
|
+
const entityMap = new Map(entities.map(e => [e.name, e]));
|
|
145
|
+
const results = [];
|
|
146
|
+
for (const name of allNames) {
|
|
147
|
+
const entity = entityMap.get(name);
|
|
148
|
+
if (!entity)
|
|
149
|
+
continue;
|
|
150
|
+
const semantic = semanticScores.get(name) ?? 0;
|
|
151
|
+
const lexical = lexicalScores.get(name) ?? 0;
|
|
152
|
+
const symbolic = symbolicScores.get(name) ?? 0;
|
|
153
|
+
const combined = semantic * weights.semantic +
|
|
154
|
+
lexical * weights.lexical +
|
|
155
|
+
symbolic * weights.symbolic;
|
|
156
|
+
const matchedLayers = [];
|
|
157
|
+
if (semantic > 0)
|
|
158
|
+
matchedLayers.push('semantic');
|
|
159
|
+
if (lexical > 0)
|
|
160
|
+
matchedLayers.push('lexical');
|
|
161
|
+
if (symbolic > 0)
|
|
162
|
+
matchedLayers.push('symbolic');
|
|
163
|
+
// Skip if no layers matched meaningfully
|
|
164
|
+
if (matchedLayers.length === 0)
|
|
165
|
+
continue;
|
|
166
|
+
results.push({
|
|
167
|
+
entity,
|
|
168
|
+
scores: { semantic, lexical, symbolic, combined },
|
|
169
|
+
matchedLayers,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return results;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Search with full entity resolution.
|
|
176
|
+
* Alias for search() since we now always resolve entities.
|
|
177
|
+
*/
|
|
178
|
+
async searchWithEntities(graph, query, options = {}) {
|
|
179
|
+
return this.search(graph, query, options);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get the symbolic search instance for direct access.
|
|
183
|
+
*/
|
|
184
|
+
getSymbolicSearch() {
|
|
185
|
+
return this.symbolicSearch;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=HybridSearchManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HybridSearchManager.js","sourceRoot":"","sources":["../../src/search/HybridSearchManager.ts"],"names":[],"mappings":"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"}
|