@memberjunction/ai-vector-dupe 5.21.0 → 5.23.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/README.md +266 -229
- package/dist/duplicateRecordDetector.d.ts +180 -18
- package/dist/duplicateRecordDetector.d.ts.map +1 -1
- package/dist/duplicateRecordDetector.js +746 -267
- package/dist/duplicateRecordDetector.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/scoring/ReciprocalRankFusion.d.ts +45 -0
- package/dist/scoring/ReciprocalRankFusion.d.ts.map +1 -0
- package/dist/scoring/ReciprocalRankFusion.js +63 -0
- package/dist/scoring/ReciprocalRankFusion.js.map +1 -0
- package/package.json +10 -10
- package/dist/config.d.ts +0 -13
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -15
- package/dist/config.js.map +0 -1
- package/dist/generic/vectorSyncBase.d.ts +0 -20
- package/dist/generic/vectorSyncBase.d.ts.map +0 -1
- package/dist/generic/vectorSyncBase.js +0 -42
- package/dist/generic/vectorSyncBase.js.map +0 -1
- package/dist/models/entitySyncConfig.d.ts +0 -36
- package/dist/models/entitySyncConfig.d.ts.map +0 -1
- package/dist/models/entitySyncConfig.js +0 -2
- package/dist/models/entitySyncConfig.js.map +0 -1
|
@@ -1,22 +1,184 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Modernized duplicate record detection engine.
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates the full pipeline: vectorize records, query for similar candidates,
|
|
5
|
+
* optionally apply hybrid search (RRF) and reranking, persist match results,
|
|
6
|
+
* and auto-merge high-confidence duplicates.
|
|
7
|
+
*
|
|
8
|
+
* Supports three record-source modes:
|
|
9
|
+
* 1. List-based batch detection (ListID provided)
|
|
10
|
+
* 2. View-based detection (ViewID provided)
|
|
11
|
+
* 3. Entity-wide detection (no ListID/ViewID — scans all records or applies ExtraFilter)
|
|
12
|
+
*
|
|
13
|
+
* Also supports single-record checks via CheckSingleRecord().
|
|
14
|
+
*
|
|
15
|
+
* @module @memberjunction/ai-vector-dupe
|
|
16
|
+
*/
|
|
17
|
+
import { PotentialDuplicateRequest, PotentialDuplicateResponse, CompositeKey, UserInfo, BaseEntity, PotentialDuplicateResult, EntityInfo, PotentialDuplicate, DuplicateDetectionOptions } from "@memberjunction/core";
|
|
18
|
+
import { BaseResponse } from "@memberjunction/ai-vectordb";
|
|
19
|
+
import { MJDuplicateRunDetailEntity, MJDuplicateRunDetailMatchEntity, MJDuplicateRunEntity, MJEntityDocumentEntity, MJListEntity } from "@memberjunction/core-entities";
|
|
4
20
|
import { VectorBase } from "@memberjunction/ai-vectors";
|
|
21
|
+
import { EntityDocumentTemplateParser } from "@memberjunction/ai-vector-sync";
|
|
22
|
+
import type { MJTemplateEntityExtended } from "@memberjunction/core-entities";
|
|
23
|
+
/**
|
|
24
|
+
* Internal result from querying duplicates for a single source record.
|
|
25
|
+
*/
|
|
26
|
+
interface RecordQueryResult {
|
|
27
|
+
SourceKey: CompositeKey;
|
|
28
|
+
TemplateText: string;
|
|
29
|
+
Duplicates: PotentialDuplicateResult;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Modernized duplicate record detection engine.
|
|
33
|
+
*
|
|
34
|
+
* Supports:
|
|
35
|
+
* - List-based batch detection (getDuplicateRecords)
|
|
36
|
+
* - View/filter/full-entity batch detection (vector-first approach)
|
|
37
|
+
* - Single-record duplicate check (CheckSingleRecord)
|
|
38
|
+
* - Hybrid search via RRF when vector DB supports it
|
|
39
|
+
* - Optional post-retrieval reranking via MJ's BaseReranker
|
|
40
|
+
* - Configurable topK, thresholds, and progress reporting
|
|
41
|
+
*/
|
|
5
42
|
export declare class DuplicateRecordDetector extends VectorBase {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
private
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
43
|
+
private vectorDB;
|
|
44
|
+
private embedding;
|
|
45
|
+
/** The Pinecone/pgvector/Qdrant index name resolved from the entity document's VectorIndex */
|
|
46
|
+
private indexName;
|
|
47
|
+
/**
|
|
48
|
+
* Tracks already-seen source↔match pairs across the entire run to suppress inverse duplicates.
|
|
49
|
+
* If A→B is persisted, B→A is skipped. Key format: "smallerID::largerID" for consistent ordering.
|
|
50
|
+
*/
|
|
51
|
+
private _seenPairs;
|
|
52
|
+
/**
|
|
53
|
+
* Run duplicate detection for records identified by ListID, ViewID, ExtraFilter,
|
|
54
|
+
* or all records in the entity (vector-first approach).
|
|
55
|
+
*
|
|
56
|
+
* Flow: validate -> vectorize -> init providers -> load/create run ->
|
|
57
|
+
* load record IDs -> batch(embed -> query -> persist) -> complete run -> auto-merge
|
|
58
|
+
*/
|
|
59
|
+
GetDuplicateRecords(params: PotentialDuplicateRequest, contextUser?: UserInfo): Promise<PotentialDuplicateResponse>;
|
|
60
|
+
/**
|
|
61
|
+
* Check a single record for duplicates without requiring a list.
|
|
62
|
+
* Embeds the record and queries for matches directly.
|
|
63
|
+
*/
|
|
64
|
+
CheckSingleRecord(EntityDocumentID: string, RecordID: CompositeKey, Options?: DuplicateDetectionOptions, ContextUser?: UserInfo): Promise<PotentialDuplicateResult>;
|
|
65
|
+
/**
|
|
66
|
+
* Result from processing a single batch of records.
|
|
67
|
+
*/
|
|
68
|
+
private ProcessBatch;
|
|
69
|
+
/**
|
|
70
|
+
* Load the IDs of records to check, using the appropriate strategy based on the request.
|
|
71
|
+
* Returns an array of primary key value strings.
|
|
72
|
+
*/
|
|
73
|
+
protected LoadRecordIDsToCheck(params: PotentialDuplicateRequest, entityInfo: EntityInfo): Promise<string[]>;
|
|
74
|
+
/**
|
|
75
|
+
* Load record IDs from a list's detail records.
|
|
76
|
+
*/
|
|
77
|
+
protected LoadRecordIDsFromList(listID: string): Promise<string[]>;
|
|
78
|
+
/**
|
|
79
|
+
* Load record IDs by running a saved view.
|
|
80
|
+
*/
|
|
81
|
+
protected LoadRecordIDsFromView(viewID: string, entityInfo: EntityInfo): Promise<string[]>;
|
|
82
|
+
/**
|
|
83
|
+
* Load record IDs directly from the entity, optionally filtered.
|
|
84
|
+
* Uses Fields: ['ID'] and ResultType: 'simple' for efficiency.
|
|
85
|
+
*/
|
|
86
|
+
protected LoadRecordIDsFromEntity(entityInfo: EntityInfo, extraFilter?: string): Promise<string[]>;
|
|
87
|
+
/**
|
|
88
|
+
* Validate and return an entity document, or null if not found.
|
|
89
|
+
*/
|
|
90
|
+
protected ValidateEntityDocument(entityDocumentID: string): Promise<MJEntityDocumentEntity | null>;
|
|
91
|
+
/**
|
|
92
|
+
* Initialize embedding and vector DB providers via ClassFactory.
|
|
93
|
+
*/
|
|
94
|
+
protected InitializeProviders(entityDocument: MJEntityDocumentEntity): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* Run vectorization for the entity document's records.
|
|
97
|
+
*/
|
|
98
|
+
protected VectorizeSourceRecords(entityDocument: MJEntityDocumentEntity, contextUser: UserInfo): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Read the maxConcurrentRequests from the VectorDatabase entity's Configuration column,
|
|
101
|
+
* falling back to DEFAULT_QUERY_CONCURRENCY if not set.
|
|
102
|
+
*/
|
|
103
|
+
protected GetQueryConcurrency(entityDocument: MJEntityDocumentEntity): number;
|
|
104
|
+
/**
|
|
105
|
+
* Resolve an existing DuplicateRun or create a new one.
|
|
106
|
+
* Supports both list-based and list-free operation.
|
|
107
|
+
*/
|
|
108
|
+
protected ResolveOrCreateDuplicateRun(params: PotentialDuplicateRequest, entityDocument: MJEntityDocumentEntity, options: DuplicateDetectionOptions): Promise<MJDuplicateRunEntity>;
|
|
109
|
+
/**
|
|
110
|
+
* Create a new DuplicateRun record.
|
|
111
|
+
*/
|
|
112
|
+
protected CreateDuplicateRun(entityDocument: MJEntityDocumentEntity, listID?: string): Promise<MJDuplicateRunEntity>;
|
|
113
|
+
protected LoadDuplicateRun(duplicateRunID: string): Promise<MJDuplicateRunEntity>;
|
|
114
|
+
/**
|
|
115
|
+
* Try to find an existing DuplicateRun for a given ListID. Returns null if none found.
|
|
116
|
+
*/
|
|
117
|
+
protected FindDuplicateRunByListID(listID: string): Promise<MJDuplicateRunEntity | null>;
|
|
118
|
+
/**
|
|
119
|
+
* Load full entity objects for a batch of composite keys.
|
|
120
|
+
*/
|
|
121
|
+
protected LoadRecordsByKeys(compositeKeys: CompositeKey[], entityInfo: EntityInfo): Promise<BaseEntity[]>;
|
|
122
|
+
/**
|
|
123
|
+
* Load records from an entity that are members of the specified list.
|
|
124
|
+
* Kept for backward compatibility.
|
|
125
|
+
*/
|
|
126
|
+
protected LoadRecordsByListID(listID: string, entityID: string): Promise<BaseEntity[]>;
|
|
127
|
+
protected LoadListEntity(listID: string): Promise<MJListEntity>;
|
|
128
|
+
/**
|
|
129
|
+
* Generate human-readable template text for each record using the entity document template.
|
|
130
|
+
*
|
|
131
|
+
* Loads the template from TemplateEngineServer and renders it via Nunjucks,
|
|
132
|
+
* matching the same approach used by the vectorization pipeline.
|
|
133
|
+
*/
|
|
134
|
+
protected GenerateTemplateTexts(templateParser: ReturnType<typeof EntityDocumentTemplateParser.CreateInstance>, entityDocument: MJEntityDocumentEntity, records: BaseEntity[], contextUser: UserInfo): Promise<string[]>;
|
|
135
|
+
/**
|
|
136
|
+
* Load the template entity from TemplateEngineServer for the given entity document.
|
|
137
|
+
*/
|
|
138
|
+
protected loadTemplate(entityDocument: MJEntityDocumentEntity): MJTemplateEntityExtended;
|
|
139
|
+
/**
|
|
140
|
+
* Query the vector DB for duplicates of each record, with concurrency control.
|
|
141
|
+
* Supports hybrid search and RRF fusion when the vector DB supports it.
|
|
142
|
+
*/
|
|
143
|
+
protected QueryDuplicatesForRecords(records: BaseEntity[], vectors: number[][], templateTexts: string[], entityDocument: MJEntityDocumentEntity, topK: number, options: DuplicateDetectionOptions, concurrency: number): Promise<RecordQueryResult[]>;
|
|
144
|
+
/**
|
|
145
|
+
* Execute a vector query — uses hybrid search with RRF when the provider supports it.
|
|
146
|
+
*/
|
|
147
|
+
protected executeVectorQuery(vector: number[], templateText: string, topK: number, options: DuplicateDetectionOptions): Promise<BaseResponse>;
|
|
148
|
+
/**
|
|
149
|
+
* Parse raw vector DB matches into a PotentialDuplicateResult.
|
|
150
|
+
*/
|
|
151
|
+
ParseVectorMatches(queryResponse: BaseResponse, sourceKey?: CompositeKey): PotentialDuplicateResult;
|
|
152
|
+
/**
|
|
153
|
+
* Filter out self-matches where the candidate is the same record as the source.
|
|
154
|
+
*/
|
|
155
|
+
/**
|
|
156
|
+
* Build a map of recordID → JSON metadata string from loaded BaseEntity records.
|
|
157
|
+
* Extracts the entity's name field and a few key display fields for rich UI rendering.
|
|
158
|
+
*/
|
|
159
|
+
protected buildSourceMetadataMap(records: BaseEntity[], entityInfo: EntityInfo): Map<string, string>;
|
|
160
|
+
protected FilterSelfMatches(duplicates: PotentialDuplicate[], sourceKey: CompositeKey): PotentialDuplicate[];
|
|
161
|
+
/**
|
|
162
|
+
* Create DuplicateRunDetail records for a batch of record IDs.
|
|
163
|
+
*/
|
|
164
|
+
protected CreateRunDetailRecords(recordIDs: string[], duplicateRunID: string, entityInfo: EntityInfo, metadataMap?: Map<string, string>): Promise<MJDuplicateRunDetailEntity[]>;
|
|
165
|
+
/**
|
|
166
|
+
* Persist match results and update run detail records.
|
|
167
|
+
*/
|
|
168
|
+
protected PersistMatchResults(queryResults: RecordQueryResult[], duplicateRunDetails: MJDuplicateRunDetailEntity[], entityDocument: MJEntityDocumentEntity, options: DuplicateDetectionOptions, startTime: number): Promise<PotentialDuplicateResult[]>;
|
|
169
|
+
/**
|
|
170
|
+
* Create match records for a single run detail, saving in parallel batches.
|
|
171
|
+
*/
|
|
172
|
+
protected CreateMatchRecordsForDetail(duplicateRunDetailID: string, duplicateResult: PotentialDuplicateResult): Promise<MJDuplicateRunDetailMatchEntity[]>;
|
|
173
|
+
/**
|
|
174
|
+
* Automatically merge records that meet the absolute match threshold.
|
|
175
|
+
*/
|
|
176
|
+
protected ProcessAutoMerges(response: PotentialDuplicateResponse, entityDocument: MJEntityDocumentEntity, options?: DuplicateDetectionOptions): Promise<void>;
|
|
177
|
+
/**
|
|
178
|
+
* Update a match record's status after a successful merge.
|
|
179
|
+
*/
|
|
180
|
+
private updateMatchRecordAfterMerge;
|
|
181
|
+
private reportProgress;
|
|
21
182
|
}
|
|
183
|
+
export {};
|
|
22
184
|
//# sourceMappingURL=duplicateRecordDetector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duplicateRecordDetector.d.ts","sourceRoot":"","sources":["../src/duplicateRecordDetector.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"duplicateRecordDetector.d.ts","sourceRoot":"","sources":["../src/duplicateRecordDetector.ts"],"names":[],"mappings":"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"}
|