@natlibfi/melinda-record-matching 2.2.1-alpha.2 → 2.2.1-alpha.3
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/dist/candidate-search/candidate-search-utils.js +3 -6
- package/dist/candidate-search/candidate-search-utils.js.map +1 -1
- package/dist/candidate-search/index.js +18 -33
- package/dist/candidate-search/index.js.map +1 -1
- package/dist/candidate-search/index.spec.js +17 -30
- package/dist/candidate-search/index.spec.js.map +1 -1
- package/dist/candidate-search/query-list/bib.js +27 -49
- package/dist/candidate-search/query-list/bib.js.map +1 -1
- package/dist/candidate-search/query-list/bib.spec.js +1 -10
- package/dist/candidate-search/query-list/bib.spec.js.map +1 -1
- package/dist/candidate-search/query-list/index.js +3 -9
- package/dist/candidate-search/query-list/index.js.map +1 -1
- package/dist/index.js +46 -65
- package/dist/index.js.map +1 -1
- package/dist/index.spec.js +13 -21
- package/dist/index.spec.js.map +1 -1
- package/dist/match-detection/features/bib/all-source-ids.js +10 -16
- package/dist/match-detection/features/bib/all-source-ids.js.map +1 -1
- package/dist/match-detection/features/bib/authors.js +2 -15
- package/dist/match-detection/features/bib/authors.js.map +1 -1
- package/dist/match-detection/features/bib/bibliographic-level.js +1 -4
- package/dist/match-detection/features/bib/bibliographic-level.js.map +1 -1
- package/dist/match-detection/features/bib/host-component.js +1 -4
- package/dist/match-detection/features/bib/host-component.js.map +1 -1
- package/dist/match-detection/features/bib/index.js +0 -13
- package/dist/match-detection/features/bib/index.js.map +1 -1
- package/dist/match-detection/features/bib/index.spec.js +1 -11
- package/dist/match-detection/features/bib/index.spec.js.map +1 -1
- package/dist/match-detection/features/bib/isbn.js +1 -6
- package/dist/match-detection/features/bib/isbn.js.map +1 -1
- package/dist/match-detection/features/bib/issn.js +1 -6
- package/dist/match-detection/features/bib/issn.js.map +1 -1
- package/dist/match-detection/features/bib/language.js +4 -19
- package/dist/match-detection/features/bib/language.js.map +1 -1
- package/dist/match-detection/features/bib/melinda-id.js +1 -6
- package/dist/match-detection/features/bib/melinda-id.js.map +1 -1
- package/dist/match-detection/features/bib/melinda-identifier-factory.js +2 -14
- package/dist/match-detection/features/bib/melinda-identifier-factory.js.map +1 -1
- package/dist/match-detection/features/bib/other-standard-identifier.js +1 -6
- package/dist/match-detection/features/bib/other-standard-identifier.js.map +1 -1
- package/dist/match-detection/features/bib/publication-time.js +0 -4
- package/dist/match-detection/features/bib/publication-time.js.map +1 -1
- package/dist/match-detection/features/bib/record-type.js +0 -2
- package/dist/match-detection/features/bib/record-type.js.map +1 -1
- package/dist/match-detection/features/bib/standard-identifier-factory.js +1 -16
- package/dist/match-detection/features/bib/standard-identifier-factory.js.map +1 -1
- package/dist/match-detection/features/bib/title.js +1 -18
- package/dist/match-detection/features/bib/title.js.map +1 -1
- package/dist/match-detection/features/index.js +0 -4
- package/dist/match-detection/features/index.js.map +1 -1
- package/dist/match-detection/index.js +0 -22
- package/dist/match-detection/index.js.map +1 -1
- package/dist/match-detection/index.spec.js +3 -14
- package/dist/match-detection/index.spec.js.map +1 -1
- package/dist/matching-utils.js +3 -12
- package/dist/matching-utils.js.map +1 -1
- package/package.json +17 -17
package/dist/index.js
CHANGED
|
@@ -4,23 +4,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.matchDetection = exports.default = exports.candidateSearch = void 0;
|
|
7
|
-
|
|
8
7
|
var _debug = _interopRequireDefault(require("debug"));
|
|
9
|
-
|
|
10
8
|
var candidateSearch = _interopRequireWildcard(require("./candidate-search"));
|
|
11
|
-
|
|
12
9
|
exports.candidateSearch = candidateSearch;
|
|
13
|
-
|
|
14
10
|
var matchDetection = _interopRequireWildcard(require("./match-detection"));
|
|
15
|
-
|
|
16
11
|
exports.matchDetection = matchDetection;
|
|
17
|
-
|
|
18
12
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
19
|
-
|
|
20
13
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
21
|
-
|
|
22
14
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
|
-
|
|
24
15
|
/**
|
|
25
16
|
*
|
|
26
17
|
* @licstart The following is the entire license notice for the JavaScript code in this file.
|
|
@@ -71,14 +62,18 @@ var _default = ({
|
|
|
71
62
|
debugData(`ReturnFailures: ${JSON.stringify(returnFailures)}`);
|
|
72
63
|
const detect = (0, matchDetection.default)(detectionOptions, returnStrategy);
|
|
73
64
|
return record => {
|
|
74
|
-
const search = (0, candidateSearch.default)({
|
|
65
|
+
const search = (0, candidateSearch.default)({
|
|
66
|
+
...searchOptions,
|
|
75
67
|
record,
|
|
76
68
|
maxCandidates
|
|
77
69
|
});
|
|
78
|
-
return iterate({});
|
|
70
|
+
return iterate({});
|
|
71
|
+
|
|
72
|
+
// candidateCount : amount of candidate records retrived from SRU for matching, NOT including current record set
|
|
79
73
|
// matches : candidates that have been detected as matches by current matcher job
|
|
80
74
|
// nonMatches : candidates that have been detected as non-matches by current matcher job (only if returnNonMatches is 'true')
|
|
81
75
|
// duplicateCount : amount of candidate records that were retrieved from the SRU but not handled further because they were already found in the matches/nonMatches
|
|
76
|
+
|
|
82
77
|
// state.totalRecords : amount of candidate records available to the current query (undefined, if there was no queries left)
|
|
83
78
|
// state.query : current query (undefined if there was no queries left)
|
|
84
79
|
// state.searchCounter : sequence for current search for current query (undefined, if there we no queries left)
|
|
@@ -109,11 +104,9 @@ var _default = ({
|
|
|
109
104
|
const newCandidateCount = candidateCount + recordSetSize + failureSetSize;
|
|
110
105
|
const newConversionFailures = conversionFailures.concat(failures);
|
|
111
106
|
debugData(`Failures: ${failures.length}, ConversionFailures: ${conversionFailures.length}, NewConversionFailures: ${newConversionFailures.length}`);
|
|
112
|
-
|
|
113
107
|
if (recordSetSize > 0) {
|
|
114
108
|
return handleRecordSet();
|
|
115
109
|
}
|
|
116
|
-
|
|
117
110
|
if (state.queriesLeft > 0) {
|
|
118
111
|
debug(`Empty record set ${state.searchCounter} for ${state.query}, but there are ${state.queriesLeft} queries left`);
|
|
119
112
|
return iterate({
|
|
@@ -127,7 +120,6 @@ var _default = ({
|
|
|
127
120
|
matchErrors
|
|
128
121
|
});
|
|
129
122
|
}
|
|
130
|
-
|
|
131
123
|
debug(`No (more) candidate records to check, no more queries left, matches: ${matches.length}`);
|
|
132
124
|
return returnResult({
|
|
133
125
|
matches,
|
|
@@ -140,7 +132,6 @@ var _default = ({
|
|
|
140
132
|
conversionFailures: newConversionFailures,
|
|
141
133
|
matchErrors
|
|
142
134
|
});
|
|
143
|
-
|
|
144
135
|
function handleRecordSet() {
|
|
145
136
|
debug(`Checking record set of ${recordSetSize} candidate records for possible matches, found by ${state.searchCounter} search for ${state.query}`);
|
|
146
137
|
const matchResult = iterateRecords({
|
|
@@ -158,7 +149,6 @@ var _default = ({
|
|
|
158
149
|
newNonMatches,
|
|
159
150
|
newMatchErrors
|
|
160
151
|
} = handleMatchResult(matchResult, matches, nonMatches, matchErrors);
|
|
161
|
-
|
|
162
152
|
if (maxMatchesFound({
|
|
163
153
|
matches: newMatches,
|
|
164
154
|
maxMatches
|
|
@@ -175,7 +165,6 @@ var _default = ({
|
|
|
175
165
|
matchErrors: newMatchErrors
|
|
176
166
|
});
|
|
177
167
|
}
|
|
178
|
-
|
|
179
168
|
if (maxCandidatesRetrieved(newCandidateCount, maxCandidates)) {
|
|
180
169
|
return returnResult({
|
|
181
170
|
matches: newMatches,
|
|
@@ -189,7 +178,6 @@ var _default = ({
|
|
|
189
178
|
matchErrors: newMatchErrors
|
|
190
179
|
});
|
|
191
180
|
}
|
|
192
|
-
|
|
193
181
|
return iterate({
|
|
194
182
|
initialState: state,
|
|
195
183
|
matches: newMatches,
|
|
@@ -201,23 +189,20 @@ var _default = ({
|
|
|
201
189
|
matchErrors: newMatchErrors
|
|
202
190
|
});
|
|
203
191
|
}
|
|
204
|
-
|
|
205
192
|
function handleMatchResult(matchResult, matches, nonMatches, matchErrors) {
|
|
206
|
-
debugData(`- Amount of new matches from record set: ${matchResult.matches.length}`);
|
|
207
|
-
|
|
193
|
+
debugData(`- Amount of new matches from record set: ${matchResult.matches.length}`);
|
|
194
|
+
// eslint-disable-next-line functional/no-conditional-statement
|
|
208
195
|
if (returnNonMatches) {
|
|
209
196
|
debugData(`- Amount of new nonMatches from record set: ${matchResult.nonMatches.length}`);
|
|
210
197
|
}
|
|
211
|
-
|
|
212
198
|
const newMatches = matches.concat(returnQuery ? addQuery(matchResult.matches) : matchResult.matches);
|
|
213
199
|
const newNonMatches = returnNonMatches ? nonMatches.concat(returnQuery ? addQuery(matchResult.nonMatches) : matchResult.nonMatches) : [];
|
|
214
200
|
const newMatchErrors = matchErrors.concat(matchResult.matchErrors);
|
|
215
|
-
debugData(`- Total amount of matches: ${newMatches.length}`);
|
|
216
|
-
|
|
201
|
+
debugData(`- Total amount of matches: ${newMatches.length}`);
|
|
202
|
+
// eslint-disable-next-line functional/no-conditional-statement
|
|
217
203
|
if (returnNonMatches) {
|
|
218
204
|
debugData(`- Total amount of nonMatches: ${newNonMatches.length}`);
|
|
219
205
|
}
|
|
220
|
-
|
|
221
206
|
debugData(`MatchResult: ${JSON.stringify(matchResult)}`);
|
|
222
207
|
debugData(`Old matchErrors: ${JSON.stringify(matchErrors)}, matchErrors from matchResult: ${JSON.stringify(matchResult.matchErrors)}, New matchErrors: ${JSON.stringify(newMatchErrors)}`);
|
|
223
208
|
debugData(`- Total amount of matchErrors: ${newMatchErrors.length}`);
|
|
@@ -227,23 +212,23 @@ var _default = ({
|
|
|
227
212
|
newMatchErrors
|
|
228
213
|
};
|
|
229
214
|
}
|
|
230
|
-
|
|
231
215
|
function addQuery(matches) {
|
|
232
216
|
debugData(`Adding query ${state.query} to matches`);
|
|
233
|
-
return matches.map(match => ({
|
|
217
|
+
return matches.map(match => ({
|
|
218
|
+
...match,
|
|
234
219
|
matchQuery: state.query
|
|
235
220
|
}));
|
|
236
221
|
}
|
|
237
|
-
|
|
238
222
|
function maxCandidatesRetrieved(candidateCount, maxCandidates) {
|
|
239
223
|
debugData(`Total amount of candidate records retrieved: ${newCandidateCount} (max: ${maxCandidates})`);
|
|
240
|
-
|
|
241
224
|
if (maxCandidates && candidateCount >= maxCandidates) {
|
|
242
225
|
debug(`Stopped matching because maximum number of candidate records ${candidateCount} / ${maxCandidates} have been retrieved`);
|
|
243
226
|
return true;
|
|
244
227
|
}
|
|
245
228
|
}
|
|
246
|
-
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// matches : array of matching candidate records
|
|
247
232
|
// nonMatches : array of nonMatching candidate records (if returnNonMatches option is true, otherwise empty array)
|
|
248
233
|
// - candidate.id
|
|
249
234
|
// - candidate.record
|
|
@@ -252,13 +237,14 @@ var _default = ({
|
|
|
252
237
|
// - treshold (if returnStrategy option is true)
|
|
253
238
|
// - matchQuery (if returnQuery option is true)
|
|
254
239
|
// failures: array of conversionFailures from candidate-search and matchErrors from matchDetection in error format {status, payload: {message, id}} if returnFailures is true
|
|
240
|
+
|
|
255
241
|
// we could have here also returnRecords/returnMatchRecords/returnNonMatchRecord options that could be turned false for not to return actual record data
|
|
242
|
+
|
|
256
243
|
// matchStatus.status: boolean, true if matcher retrieved and handled all found candidate records, false if it did not
|
|
257
244
|
// matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records
|
|
258
245
|
// - only one stopReason is returned (if there would be several possible stopReasons, stopReason is picked in the above order)
|
|
259
246
|
// - currently stopReason can be non-empty also in cases where status is true, if matcher hit the stop reason when handling the last available candidate record
|
|
260
247
|
|
|
261
|
-
|
|
262
248
|
function returnResult({
|
|
263
249
|
matches,
|
|
264
250
|
state,
|
|
@@ -281,8 +267,8 @@ var _default = ({
|
|
|
281
267
|
conversionFailureCount,
|
|
282
268
|
matchErrorCount
|
|
283
269
|
});
|
|
284
|
-
const matchStatus = getMatchState(state, stopReason, conversionFailureCount, matchErrorCount);
|
|
285
|
-
|
|
270
|
+
const matchStatus = getMatchState(state, stopReason, conversionFailureCount, matchErrorCount);
|
|
271
|
+
// add nonMatches to result only if returnNonMatches is 'true', otherwise nonMatches have not been gathered
|
|
286
272
|
const matchesResult = returnNonMatches ? {
|
|
287
273
|
matches,
|
|
288
274
|
matchStatus,
|
|
@@ -292,12 +278,15 @@ var _default = ({
|
|
|
292
278
|
matchStatus
|
|
293
279
|
};
|
|
294
280
|
const failures = [...conversionFailures, ...matchErrors];
|
|
295
|
-
const result = returnFailures ? {
|
|
281
|
+
const result = returnFailures ? {
|
|
282
|
+
...matchesResult,
|
|
296
283
|
conversionFailures: failures
|
|
297
284
|
} : matchesResult;
|
|
298
285
|
debugData(`ReturnFailures ${returnFailures}`);
|
|
299
286
|
debugData(`${JSON.stringify(result)}`);
|
|
300
|
-
return result;
|
|
287
|
+
return result;
|
|
288
|
+
|
|
289
|
+
// note that in cases where the matching has been stopped because of maxMatches checkCounts won't (in most cases) match
|
|
301
290
|
|
|
302
291
|
function checkCounts({
|
|
303
292
|
matches,
|
|
@@ -314,16 +303,14 @@ var _default = ({
|
|
|
314
303
|
const totalHandled = matchCount + chosenNonMatchCount + duplicateCount;
|
|
315
304
|
debug(`candidateCount: ${candidateCount}, matches: ${matchCount}, nonMatches: ${chosenNonMatchCount}, duplicateCount: ${duplicateCount}, conversionFailureCount: ${conversionFailureCount}, matchErrorCount: ${matchErrorCount}`);
|
|
316
305
|
debug(`We got result for ${totalHandled} / ${candidateCount} retrieved candidates`);
|
|
317
|
-
|
|
318
306
|
if (totalHandled !== candidateCount) {
|
|
319
307
|
debug(`WARNING: Missing results for ${candidateCount - totalHandled} candidates`);
|
|
320
308
|
return;
|
|
321
309
|
}
|
|
322
|
-
|
|
323
310
|
return;
|
|
324
|
-
}
|
|
325
|
-
|
|
311
|
+
}
|
|
326
312
|
|
|
313
|
+
// eslint-disable-next-line max-statements
|
|
327
314
|
function getMatchState(state, stopReason, conversionFailuresCount, matchErrorCount) {
|
|
328
315
|
debugData(`${JSON.stringify(state)}`);
|
|
329
316
|
debug(`We had ${conversionFailuresCount} retrieved candidates that could not be converted.`);
|
|
@@ -332,7 +319,9 @@ var _default = ({
|
|
|
332
319
|
debugData(`StopReason: <${stopReason}>`);
|
|
333
320
|
const searchesLeft = state.resultSetOffset && state.resultSetOffset <= state.totalRecords;
|
|
334
321
|
const nonRetrieved = searchesLeft ? state.totalRecords - state.queryCandidateCounter : 0;
|
|
335
|
-
debugData(`nonRetrieved: ${nonRetrieved}`);
|
|
322
|
+
debugData(`nonRetrieved: ${nonRetrieved}`);
|
|
323
|
+
|
|
324
|
+
// matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records
|
|
336
325
|
// 'maxMatches' and 'maxCandidates' are in stopReason, 'maxedQueries', 'conversionFailures' and 'matchErrors' are created here
|
|
337
326
|
|
|
338
327
|
if (state.queriesLeft > 0 || nonRetrieved > 0 || state.maxedQueries.length > 0 || conversionFailureCount > 0 || matchErrorCount > 0) {
|
|
@@ -350,20 +339,20 @@ var _default = ({
|
|
|
350
339
|
stopReason: newStopReason
|
|
351
340
|
};
|
|
352
341
|
}
|
|
353
|
-
|
|
354
342
|
debug(`Match status: true`);
|
|
355
343
|
return {
|
|
356
344
|
status: true,
|
|
357
345
|
stopReason
|
|
358
346
|
};
|
|
359
347
|
}
|
|
360
|
-
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// NOTES:
|
|
361
351
|
// - we could optimize by creating the featureSet for the incoming record once and using it for all database/candidateRecords
|
|
362
352
|
// - if creating the featureSet for the incoming record fails we have an unprocessable entity
|
|
363
353
|
// - if creating the featureSet for a candidate record fails we could skip that candidate - but list the case as a detectionFailure, same as conversionFailures
|
|
364
|
-
// eslint-disable-next-line max-statements
|
|
365
|
-
|
|
366
354
|
|
|
355
|
+
// eslint-disable-next-line max-statements
|
|
367
356
|
function iterateRecords({
|
|
368
357
|
records,
|
|
369
358
|
recordSetSize,
|
|
@@ -382,13 +371,17 @@ var _default = ({
|
|
|
382
371
|
// maxMatches : setting for maximum amount found by current matcher job before the matcher job is stopped
|
|
383
372
|
// recordDuplicateCount : amount of records from the current record set that are already included in matches/nonMatches results
|
|
384
373
|
// recordNonMatchCount: amount of records from the current record set that are nonMatches (only is returnNonMatches setting is false)
|
|
374
|
+
|
|
385
375
|
// records : non-handled records in the current record set
|
|
386
376
|
// matches : found matches in the current matcher job
|
|
387
377
|
// recordMatches : found matches in the current record set
|
|
388
378
|
// recordNonMatches : found nonMatches in the current record set (only if returnNonMatches setting is true)
|
|
389
379
|
// recordMatchErrors: errored matchDetection in the current record set
|
|
380
|
+
|
|
390
381
|
const [candidate] = records;
|
|
391
|
-
const newRecordCount = candidate ? recordCount + 1 : recordCount;
|
|
382
|
+
const newRecordCount = candidate ? recordCount + 1 : recordCount;
|
|
383
|
+
|
|
384
|
+
// The matcher uses same matchDetection strategy for candidates from all candidate-searches -> matchDetection result for the same candidate is always same
|
|
392
385
|
// Exceptions would happen if the candidate would have been updated in the database between candidate searches
|
|
393
386
|
// Note that if returnNonMatches is false, matcher won't remember candidates that didn't match, so they will be matched again everytime they are retrieved by
|
|
394
387
|
// different candidate search queries. Same candidate search query won't have duplicate records.
|
|
@@ -408,10 +401,9 @@ var _default = ({
|
|
|
408
401
|
record: candidateRecord,
|
|
409
402
|
id: candidateId
|
|
410
403
|
} = candidate;
|
|
411
|
-
|
|
412
404
|
try {
|
|
413
|
-
debug(`Running matchDetection for record ${candidateId} (${newRecordCount}/${recordSetSize})`);
|
|
414
|
-
|
|
405
|
+
debug(`Running matchDetection for record ${candidateId} (${newRecordCount}/${recordSetSize})`);
|
|
406
|
+
// we should handle errors from detection somehow - ie. cases where either record or candidateRecord errors
|
|
415
407
|
const detectionResult = detect(record, candidateRecord);
|
|
416
408
|
return handleDetectionResult(detectionResult, candidateId, candidateRecord);
|
|
417
409
|
} catch (error) {
|
|
@@ -438,7 +430,6 @@ var _default = ({
|
|
|
438
430
|
});
|
|
439
431
|
}
|
|
440
432
|
}
|
|
441
|
-
|
|
442
433
|
return iterateRecords({
|
|
443
434
|
records: records.slice(1),
|
|
444
435
|
recordSetSize,
|
|
@@ -452,7 +443,6 @@ var _default = ({
|
|
|
452
443
|
recordMatchErrors
|
|
453
444
|
});
|
|
454
445
|
}
|
|
455
|
-
|
|
456
446
|
debug(`No more candidates, record set (${recordCount}/${recordSetSize}) done, ${recordMatches.length} matches found, ${recordDuplicateCount} candidates already handled, ${returnNonMatches ? `${recordNonMatches.length}` : `${recordNonMatchCount}`} nonMatches found.`);
|
|
457
447
|
return {
|
|
458
448
|
matches: recordMatches,
|
|
@@ -461,10 +451,8 @@ var _default = ({
|
|
|
461
451
|
nonMatchCount: recordNonMatchCount,
|
|
462
452
|
matchErrors: recordMatchErrors
|
|
463
453
|
};
|
|
464
|
-
|
|
465
454
|
function handleDetectionResult(detectionResult, candidateId, candidateRecord) {
|
|
466
455
|
debugData(`MatchDetection results for ${candidateId} (${newRecordCount}/${recordSetSize}): ${JSON.stringify(detectionResult)}`);
|
|
467
|
-
|
|
468
456
|
if (detectionResult.match || returnNonMatches) {
|
|
469
457
|
debug(`${detectionResult.match ? `Record ${candidateId} (${newRecordCount}/${recordSetSize}) is a match!` : `Record ${candidateId} (${newRecordCount}/${recordSetSize}) is NOT a match!`}`);
|
|
470
458
|
debugData(`Strategy: ${JSON.stringify(detectionResult.strategy)}, Treshold: ${JSON.stringify(detectionResult.treshold)}`);
|
|
@@ -479,14 +467,15 @@ var _default = ({
|
|
|
479
467
|
strategy: detectionResult.strategy,
|
|
480
468
|
treshold: detectionResult.treshold
|
|
481
469
|
};
|
|
482
|
-
const newMatch = returnStrategy ? {
|
|
470
|
+
const newMatch = returnStrategy ? {
|
|
471
|
+
...matchResult,
|
|
483
472
|
...strategyResult
|
|
484
|
-
} : {
|
|
473
|
+
} : {
|
|
474
|
+
...matchResult
|
|
485
475
|
};
|
|
486
476
|
debugData(`${JSON.stringify(newMatch)}`);
|
|
487
477
|
return handleRecordMatch(detectionResult.match, newMatch);
|
|
488
478
|
}
|
|
489
|
-
|
|
490
479
|
const newRecordNonMatchCount = recordNonMatchCount + 1;
|
|
491
480
|
debugData(`- Total nonMatches after this detection: ${newRecordNonMatchCount}`);
|
|
492
481
|
return iterateRecords({
|
|
@@ -502,19 +491,17 @@ var _default = ({
|
|
|
502
491
|
recordMatchErrors
|
|
503
492
|
});
|
|
504
493
|
}
|
|
505
|
-
|
|
506
494
|
function handleRecordMatch(isMatch, newMatch) {
|
|
507
495
|
const newRecordMatches = isMatch ? recordMatches.concat(newMatch) : recordMatches;
|
|
508
496
|
const newRecordNonMatches = isMatch ? recordNonMatches : recordNonMatches.concat(newMatch);
|
|
509
497
|
const newRecordNonMatchCount = isMatch ? recordNonMatchCount : recordNonMatchCount + 1;
|
|
510
|
-
debugData(`- Total matches after this detection: ${matches.concat(newRecordMatches).length} (max: ${maxMatches})`);
|
|
498
|
+
debugData(`- Total matches after this detection: ${matches.concat(newRecordMatches).length} (max: ${maxMatches})`);
|
|
511
499
|
|
|
500
|
+
// eslint-disable-next-line functional/no-conditional-statement
|
|
512
501
|
if (returnNonMatches) {
|
|
513
502
|
debugData(`- Total nonMatches after this detection: ${nonMatches.concat(newRecordNonMatches).length}`);
|
|
514
503
|
}
|
|
515
|
-
|
|
516
504
|
debugData(`- Total nonMatchCount after this detection: ${recordNonMatchCount}`);
|
|
517
|
-
|
|
518
505
|
if (maxMatchesFound({
|
|
519
506
|
matches: matches.concat(newRecordMatches),
|
|
520
507
|
maxMatches
|
|
@@ -528,7 +515,6 @@ var _default = ({
|
|
|
528
515
|
matchErrors: recordMatchErrors
|
|
529
516
|
};
|
|
530
517
|
}
|
|
531
|
-
|
|
532
518
|
return iterateRecords({
|
|
533
519
|
records: records.slice(1),
|
|
534
520
|
recordSetSize,
|
|
@@ -542,7 +528,6 @@ var _default = ({
|
|
|
542
528
|
matchErrors: recordMatchErrors
|
|
543
529
|
});
|
|
544
530
|
}
|
|
545
|
-
|
|
546
531
|
function candidateNotInMatches(matches, candidate) {
|
|
547
532
|
debug(`Checking that record ${candidate.id} is not already included in ${matches.length} matches/nonMatches`);
|
|
548
533
|
const newCandidateId = candidate.id;
|
|
@@ -551,17 +536,14 @@ var _default = ({
|
|
|
551
536
|
candidate
|
|
552
537
|
}) => candidate.id === newCandidateId);
|
|
553
538
|
debugData(`Result: ${result}`);
|
|
554
|
-
|
|
555
539
|
if (result) {
|
|
556
540
|
debug(`${candidate.id} was already handled.`);
|
|
557
541
|
return false;
|
|
558
542
|
}
|
|
559
|
-
|
|
560
543
|
debug(`${candidate.id} not found in matches/nonMatches`);
|
|
561
544
|
return true;
|
|
562
545
|
}
|
|
563
546
|
}
|
|
564
|
-
|
|
565
547
|
function maxMatchesFound({
|
|
566
548
|
matches,
|
|
567
549
|
maxMatches
|
|
@@ -573,6 +555,5 @@ var _default = ({
|
|
|
573
555
|
}
|
|
574
556
|
};
|
|
575
557
|
};
|
|
576
|
-
|
|
577
558
|
exports.default = _default;
|
|
578
559
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["detection","detectionOptions","search","searchOptions","maxMatches","maxCandidates","returnStrategy","returnQuery","returnNonMatches","returnFailures","debug","createDebugLogger","debugData","extend","JSON","stringify","detect","createDetectionInterface","record","createSearchInterface","iterate","initialState","matches","candidateCount","nonMatches","duplicateCount","nonMatchCount","conversionFailures","matchErrors","records","failures","state","length","recordSetSize","failureSetSize","newCandidateCount","newConversionFailures","concat","handleRecordSet","queriesLeft","searchCounter","query","returnResult","stopReason","matchResult","iterateRecords","newDuplicateCount","newNonMatchCount","newMatches","newNonMatches","newMatchErrors","handleMatchResult","maxMatchesFound","maxCandidatesRetrieved","addQuery","map","match","matchQuery","conversionFailureCount","matchErrorCount","checkCounts","matchStatus","getMatchState","matchesResult","result","matchCount","chosenNonMatchCount","totalHandled","conversionFailuresCount","resultSetOffset","totalRecords","queryCandidateCounter","maxedQueries","searchesLeft","nonRetrieved","maxedQueriesStopReason","undefined","conversionFailuresStopReason","matchErrorsStopReason","newStopReason","status","recordMatches","recordNonMatches","recordCount","recordDuplicateCount","recordNonMatchCount","recordMatchErrors","candidate","newRecordCount","candidateNotInMatches","candidateRecord","id","candidateId","detectionResult","handleDetectionResult","error","matchError","payload","message","newRecordMatchErrors","slice","strategy","treshold","probability","strategyResult","newMatch","handleRecordMatch","newRecordNonMatchCount","isMatch","newRecordMatches","newRecordNonMatches","newCandidateId","find"],"sources":["../src/index.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Melinda record matching modules for Javascript\n*\n* Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-record-matching-js\n*\n* melinda-record-matching-js program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-record-matching-js is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport createDebugLogger from 'debug';\nimport createSearchInterface, * as candidateSearch from './candidate-search';\nimport createDetectionInterface, * as matchDetection from './match-detection';\n//import inspect from 'util';\n\nexport {candidateSearch, matchDetection};\n\nexport default ({detection: detectionOptions, search: searchOptions, maxMatches = 1, maxCandidates = 25, returnStrategy = false, returnQuery = false, returnNonMatches = false, returnFailures = false}) => {\n const debug = createDebugLogger('@natlibfi/melinda-record-matching:index');\n const debugData = debug.extend('data');\n\n debugData(`DetectionOptions: ${JSON.stringify(detectionOptions)}`);\n debugData(`SearchOptions: ${JSON.stringify(searchOptions)}`);\n debugData(`MaxMatches: ${JSON.stringify(maxMatches)}`);\n debugData(`MaxCandidates: ${JSON.stringify(maxCandidates)}`);\n debugData(`ReturnStrategy: ${JSON.stringify(returnStrategy)}`);\n debugData(`ReturnQuery: ${JSON.stringify(returnQuery)}`);\n debugData(`ReturnNonMatches: ${JSON.stringify(returnNonMatches)}`);\n debugData(`ReturnFailures: ${JSON.stringify(returnFailures)}`);\n\n\n const detect = createDetectionInterface(detectionOptions, returnStrategy);\n\n return record => {\n const search = createSearchInterface({...searchOptions, record, maxCandidates});\n return iterate({});\n\n // candidateCount : amount of candidate records retrived from SRU for matching, NOT including current record set\n // matches : candidates that have been detected as matches by current matcher job\n // nonMatches : candidates that have been detected as non-matches by current matcher job (only if returnNonMatches is 'true')\n // duplicateCount : amount of candidate records that were retrieved from the SRU but not handled further because they were already found in the matches/nonMatches\n\n // state.totalRecords : amount of candidate records available to the current query (undefined, if there was no queries left)\n // state.query : current query (undefined if there was no queries left)\n // state.searchCounter : sequence for current search for current query (undefined, if there we no queries left)\n // state.queryCandidateCounter: amount of candidate records retrieved from SRU for matching for current query, including the current record set (undefined if there were no queries left)\n // state.queriesLeft : amount of queries left\n // state.queryCounter : sequence for current query\n // state.maxedQueries : queries that resulted in more than serverMaxResults hits\n\n async function iterate({initialState = {}, matches = [], candidateCount = 0, nonMatches = [], duplicateCount = 0, nonMatchCount = 0, conversionFailures = [], matchErrors = []}) {\n debugData(`Starting next matcher iteration.`);\n const {records, failures, ...state} = await search(initialState);\n\n debugData(`Current state: ${JSON.stringify(state)}, matches: ${matches.length}, candidateCount: ${candidateCount}, nonMatches: ${nonMatches.length}, nonMatchCount: ${nonMatchCount}, conversionFailures: ${conversionFailures}, matchErrors: ${matchErrors.length}`);\n const recordSetSize = records.length;\n const failureSetSize = failures.length;\n const newCandidateCount = candidateCount + recordSetSize + failureSetSize;\n\n const newConversionFailures = conversionFailures.concat(failures);\n debugData(`Failures: ${failures.length}, ConversionFailures: ${conversionFailures.length}, NewConversionFailures: ${newConversionFailures.length}`);\n\n if (recordSetSize > 0) {\n return handleRecordSet();\n }\n\n if (state.queriesLeft > 0) {\n debug(`Empty record set ${state.searchCounter} for ${state.query}, but there are ${state.queriesLeft} queries left`);\n return iterate({initialState: state, matches, candidateCount: newCandidateCount, nonMatches, nonMatchCount, duplicateCount, conversionFailures: newConversionFailures, matchErrors});\n }\n\n debug(`No (more) candidate records to check, no more queries left, matches: ${matches.length}`);\n return returnResult({matches, state, stopReason: '', nonMatches, nonMatchCount, candidateCount: newCandidateCount, duplicateCount, conversionFailures: newConversionFailures, matchErrors});\n\n function handleRecordSet() {\n debug(`Checking record set of ${recordSetSize} candidate records for possible matches, found by ${state.searchCounter} search for ${state.query}`);\n\n const matchResult = iterateRecords({records, recordSetSize, maxMatches, matches, nonMatches, nonMatchCount});\n\n const newDuplicateCount = duplicateCount + matchResult.duplicateCount;\n const newNonMatchCount = nonMatchCount + matchResult.nonMatchCount;\n const {newMatches, newNonMatches, newMatchErrors} = handleMatchResult(matchResult, matches, nonMatches, matchErrors);\n\n if (maxMatchesFound({matches: newMatches, maxMatches})) {\n return returnResult({matches: newMatches, state, stopReason: 'maxMatches', nonMatches: newNonMatches, duplicateCount: newDuplicateCount, candidateCount: newCandidateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures, matchErrors: newMatchErrors});\n }\n\n if (maxCandidatesRetrieved(newCandidateCount, maxCandidates)) {\n return returnResult({matches: newMatches, state, stopReason: 'maxCandidates', nonMatches: newNonMatches, duplicateCount: newDuplicateCount, candidateCount: newCandidateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures, matchErrors: newMatchErrors});\n }\n\n return iterate({initialState: state, matches: newMatches, candidateCount: newCandidateCount, nonMatches: newNonMatches, duplicateCount: newDuplicateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures, matchErrors: newMatchErrors});\n }\n\n function handleMatchResult(matchResult, matches, nonMatches, matchErrors) {\n debugData(`- Amount of new matches from record set: ${matchResult.matches.length}`);\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Amount of new nonMatches from record set: ${matchResult.nonMatches.length}`);\n }\n\n const newMatches = matches.concat(returnQuery ? addQuery(matchResult.matches) : matchResult.matches);\n const newNonMatches = returnNonMatches ? nonMatches.concat(returnQuery ? addQuery(matchResult.nonMatches) : matchResult.nonMatches) : [];\n const newMatchErrors = matchErrors.concat(matchResult.matchErrors);\n\n debugData(`- Total amount of matches: ${newMatches.length}`);\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Total amount of nonMatches: ${newNonMatches.length}`);\n }\n\n debugData(`MatchResult: ${JSON.stringify(matchResult)}`);\n debugData(`Old matchErrors: ${JSON.stringify(matchErrors)}, matchErrors from matchResult: ${JSON.stringify(matchResult.matchErrors)}, New matchErrors: ${JSON.stringify(newMatchErrors)}`);\n\n debugData(`- Total amount of matchErrors: ${newMatchErrors.length}`);\n\n return {newMatches, newNonMatches, newMatchErrors};\n }\n\n function addQuery(matches) {\n debugData(`Adding query ${state.query} to matches`);\n return matches.map((match) => ({...match, matchQuery: state.query}));\n }\n\n function maxCandidatesRetrieved(candidateCount, maxCandidates) {\n debugData(`Total amount of candidate records retrieved: ${newCandidateCount} (max: ${maxCandidates})`);\n if (maxCandidates && candidateCount >= maxCandidates) {\n debug(`Stopped matching because maximum number of candidate records ${candidateCount} / ${maxCandidates} have been retrieved`);\n return true;\n }\n }\n }\n\n // matches : array of matching candidate records\n // nonMatches : array of nonMatching candidate records (if returnNonMatches option is true, otherwise empty array)\n // - candidate.id\n // - candidate.record\n // - probability\n // - strategy (if returnStrategy option is true)\n // - treshold (if returnStrategy option is true)\n // - matchQuery (if returnQuery option is true)\n // failures: array of conversionFailures from candidate-search and matchErrors from matchDetection in error format {status, payload: {message, id}} if returnFailures is true\n\n // we could have here also returnRecords/returnMatchRecords/returnNonMatchRecord options that could be turned false for not to return actual record data\n\n // matchStatus.status: boolean, true if matcher retrieved and handled all found candidate records, false if it did not\n // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records\n // - only one stopReason is returned (if there would be several possible stopReasons, stopReason is picked in the above order)\n // - currently stopReason can be non-empty also in cases where status is true, if matcher hit the stop reason when handling the last available candidate record\n\n function returnResult({matches, state, stopReason, nonMatches, duplicateCount, candidateCount, nonMatchCount, conversionFailures, matchErrors}) {\n const conversionFailureCount = conversionFailures.length;\n const matchErrorCount = matchErrors.length;\n checkCounts({matches, nonMatches, candidateCount, duplicateCount, nonMatchCount, conversionFailureCount, matchErrorCount});\n const matchStatus = getMatchState(state, stopReason, conversionFailureCount, matchErrorCount);\n // add nonMatches to result only if returnNonMatches is 'true', otherwise nonMatches have not been gathered\n const matchesResult = returnNonMatches ? {matches, matchStatus, nonMatches} : {matches, matchStatus};\n const failures = [...conversionFailures, ...matchErrors];\n const result = returnFailures ? {...matchesResult, conversionFailures: failures} : matchesResult;\n debugData(`ReturnFailures ${returnFailures}`);\n debugData(`${JSON.stringify(result)}`);\n return result;\n\n // note that in cases where the matching has been stopped because of maxMatches checkCounts won't (in most cases) match\n\n function checkCounts({matches, nonMatches, candidateCount, duplicateCount, nonMatchCount, conversionFailureCount, matchErrorCount}) {\n const matchCount = matches.length;\n debugData(`Return nonMatches: ${returnNonMatches}`);\n const chosenNonMatchCount = returnNonMatches ? nonMatches.length : nonMatchCount;\n const totalHandled = matchCount + chosenNonMatchCount + duplicateCount;\n debug(`candidateCount: ${candidateCount}, matches: ${matchCount}, nonMatches: ${chosenNonMatchCount}, duplicateCount: ${duplicateCount}, conversionFailureCount: ${conversionFailureCount}, matchErrorCount: ${matchErrorCount}`);\n debug(`We got result for ${totalHandled} / ${candidateCount} retrieved candidates`);\n if (totalHandled !== candidateCount) {\n debug(`WARNING: Missing results for ${candidateCount - totalHandled} candidates`);\n return;\n }\n return;\n }\n\n // eslint-disable-next-line max-statements\n function getMatchState(state, stopReason, conversionFailuresCount, matchErrorCount) {\n debugData(`${JSON.stringify(state)}`);\n debug(`We had ${conversionFailuresCount} retrieved candidates that could not be converted.`);\n debug(`We had ${matchErrorCount} retrieved candidates that errored in matchDetection.`);\n debug(`Queries left ${state.queriesLeft}, Searches for current query left: ${state.resultSetOffset && state.resultSetOffset <= state.totalRecords}, non-retrieved records: ${state.totalRecords - state.queryCandidateCounter}, maxedQueries (${state.maxedQueries.length}): ${state.maxedQueries}`);\n\n debugData(`StopReason: <${stopReason}>`);\n\n const searchesLeft = state.resultSetOffset && state.resultSetOffset <= state.totalRecords;\n const nonRetrieved = searchesLeft ? state.totalRecords - state.queryCandidateCounter : 0;\n debugData(`nonRetrieved: ${nonRetrieved}`);\n\n // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records\n // 'maxMatches' and 'maxCandidates' are in stopReason, 'maxedQueries', 'conversionFailures' and 'matchErrors' are created here\n\n if (state.queriesLeft > 0 || nonRetrieved > 0 || state.maxedQueries.length > 0 || conversionFailureCount > 0 || matchErrorCount > 0) {\n const maxedQueriesStopReason = state.maxedQueries.length > 0 ? 'maxedQueries' : undefined;\n const conversionFailuresStopReason = conversionFailureCount > 0 ? 'conversionFailures' : undefined;\n const matchErrorsStopReason = matchErrorCount > 0 ? 'matchErrors' : undefined;\n const newStopReason = stopReason === '' || stopReason === undefined ? maxedQueriesStopReason || conversionFailuresStopReason || matchErrorsStopReason : stopReason;\n debugData(`MaxedQueriesStopReason: <${maxedQueriesStopReason}>`);\n debugData(`ConversionFailureStopReason <${conversionFailuresStopReason}>`);\n debugData(`MatchErrorsStopReason <${matchErrorsStopReason}>`);\n debugData(`NewStopReason: <${newStopReason}>`);\n debug(`Match status: false`);\n return {status: false, stopReason: newStopReason};\n }\n\n debug(`Match status: true`);\n return {status: true, stopReason};\n }\n }\n\n // NOTES:\n // - we could optimize by creating the featureSet for the incoming record once and using it for all database/candidateRecords\n // - if creating the featureSet for the incoming record fails we have an unprocessable entity\n // - if creating the featureSet for a candidate record fails we could skip that candidate - but list the case as a detectionFailure, same as conversionFailures\n\n // eslint-disable-next-line max-statements\n function iterateRecords({records, recordSetSize, maxMatches, matches = [], nonMatches = [], recordMatches = [], recordNonMatches = [], recordCount = 0, recordDuplicateCount = 0, recordNonMatchCount = 0, recordMatchErrors = []}) {\n\n // recordSetSize : total amount of records in the current record set\n // recordCount : amount of records from the current record set that have been handled\n // maxMatches : setting for maximum amount found by current matcher job before the matcher job is stopped\n // recordDuplicateCount : amount of records from the current record set that are already included in matches/nonMatches results\n // recordNonMatchCount: amount of records from the current record set that are nonMatches (only is returnNonMatches setting is false)\n\n // records : non-handled records in the current record set\n // matches : found matches in the current matcher job\n // recordMatches : found matches in the current record set\n // recordNonMatches : found nonMatches in the current record set (only if returnNonMatches setting is true)\n // recordMatchErrors: errored matchDetection in the current record set\n\n const [candidate] = records;\n const newRecordCount = candidate ? recordCount + 1 : recordCount;\n\n // The matcher uses same matchDetection strategy for candidates from all candidate-searches -> matchDetection result for the same candidate is always same\n // Exceptions would happen if the candidate would have been updated in the database between candidate searches\n // Note that if returnNonMatches is false, matcher won't remember candidates that didn't match, so they will be matched again everytime they are retrieved by\n // different candidate search queries. Same candidate search query won't have duplicate records.\n\n /* We could optimize and detect all retrieved candidates at once\n const candidateRecords = records.map(record => record.record);\n const recordsIsArray = Array.isArray(candidateRecords);\n debug(`records is an array: ${recordsIsArray}`);\n const result = detect(record, candidateRecords);\n debug(`${JSON.stringify(result)}`);\n */\n\n if (candidate) {\n\n // eslint-disable-next-line functional/no-conditional-statement\n if (candidateNotInMatches(matches.concat(nonMatches), candidate)) {\n const {record: candidateRecord, id: candidateId} = candidate;\n try {\n debug(`Running matchDetection for record ${candidateId} (${newRecordCount}/${recordSetSize})`);\n // we should handle errors from detection somehow - ie. cases where either record or candidateRecord errors\n const detectionResult = detect(record, candidateRecord);\n\n return handleDetectionResult(detectionResult, candidateId, candidateRecord);\n } catch (error) {\n debug(`MatchDetection errored: database record ${candidateId}: ${error}`);\n\n const matchError = {status: 422, payload: {message: `Matching errored for database record ${candidateId}. ${error.message}.`, id: candidateId}};\n const newRecordMatchErrors = recordMatchErrors.concat(matchError);\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount, recordNonMatchCount, recordMatchErrors: newRecordMatchErrors});\n }\n }\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount: recordDuplicateCount + 1, recordNonMatchCount, recordMatchErrors});\n }\n\n debug(`No more candidates, record set (${recordCount}/${recordSetSize}) done, ${recordMatches.length} matches found, ${recordDuplicateCount} candidates already handled, ${returnNonMatches ? `${recordNonMatches.length}` : `${recordNonMatchCount}`} nonMatches found.`);\n return {matches: recordMatches, nonMatches: returnNonMatches ? recordNonMatches : [], duplicateCount: recordDuplicateCount, nonMatchCount: recordNonMatchCount, matchErrors: recordMatchErrors};\n\n function handleDetectionResult(detectionResult, candidateId, candidateRecord) {\n debugData(`MatchDetection results for ${candidateId} (${newRecordCount}/${recordSetSize}): ${JSON.stringify(detectionResult)}`);\n\n if (detectionResult.match || returnNonMatches) {\n debug(`${detectionResult.match ? `Record ${candidateId} (${newRecordCount}/${recordSetSize}) is a match!` : `Record ${candidateId} (${newRecordCount}/${recordSetSize}) is NOT a match!`}`);\n debugData(`Strategy: ${JSON.stringify(detectionResult.strategy)}, Treshold: ${JSON.stringify(detectionResult.treshold)}`);\n\n const matchResult = {\n probability: detectionResult.probability,\n candidate: {\n id: candidateId,\n record: candidateRecord\n }\n };\n const strategyResult = {\n strategy: detectionResult.strategy,\n treshold: detectionResult.treshold\n };\n const newMatch = returnStrategy ? {...matchResult, ...strategyResult} : {...matchResult};\n\n debugData(`${JSON.stringify(newMatch)}`);\n\n return handleRecordMatch(detectionResult.match, newMatch);\n }\n\n const newRecordNonMatchCount = recordNonMatchCount + 1;\n debugData(`- Total nonMatches after this detection: ${newRecordNonMatchCount}`);\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount, recordNonMatchCount: newRecordNonMatchCount, recordMatchErrors});\n }\n\n function handleRecordMatch(isMatch, newMatch) {\n const newRecordMatches = isMatch ? recordMatches.concat(newMatch) : recordMatches;\n const newRecordNonMatches = isMatch ? recordNonMatches : recordNonMatches.concat(newMatch);\n const newRecordNonMatchCount = isMatch ? recordNonMatchCount : recordNonMatchCount + 1;\n\n debugData(`- Total matches after this detection: ${matches.concat(newRecordMatches).length} (max: ${maxMatches})`);\n\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Total nonMatches after this detection: ${nonMatches.concat(newRecordNonMatches).length}`);\n }\n debugData(`- Total nonMatchCount after this detection: ${recordNonMatchCount}`);\n\n if (maxMatchesFound({matches: matches.concat(newRecordMatches), maxMatches})) {\n debug(`MaxMatches (${maxMatches}) reached, handled candidates in record set: ${newRecordCount} non-handled candidates in record set ${recordSetSize - newRecordCount}`);\n return {matches: newRecordMatches, nonMatches: returnNonMatches ? newRecordNonMatches : [], duplicateCount: recordDuplicateCount, nonMatchCount: newRecordNonMatchCount, matchErrors: recordMatchErrors};\n }\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches: newRecordMatches, recordCount: newRecordCount, recordNonMatches: returnNonMatches ? newRecordNonMatches : [], duplicateCount: recordDuplicateCount, recordNonMatchCount: newRecordNonMatchCount, matchErrors: recordMatchErrors});\n }\n\n function candidateNotInMatches(matches, candidate) {\n debug(`Checking that record ${candidate.id} is not already included in ${matches.length} matches/nonMatches`);\n const newCandidateId = candidate.id;\n debugData(`newCandidateId: ${newCandidateId}`);\n const result = matches.find(({candidate}) => candidate.id === newCandidateId);\n debugData(`Result: ${result}`);\n if (result) {\n debug(`${candidate.id} was already handled.`);\n return false;\n }\n debug(`${candidate.id} not found in matches/nonMatches`);\n return true;\n }\n }\n\n function maxMatchesFound({matches, maxMatches}) {\n if (maxMatches && matches.length >= maxMatches) {\n debug(`Stopping recordSet iteration: maxMatches (${maxMatches}) for matcher job found.`);\n return true;\n }\n }\n };\n};\n"],"mappings":";;;;;;;AA4BA;;AACA;;;;AACA;;;;;;;;;;AA9BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAKA;eAIe,CAAC;EAACA,SAAS,EAAEC,gBAAZ;EAA8BC,MAAM,EAAEC,aAAtC;EAAqDC,UAAU,GAAG,CAAlE;EAAqEC,aAAa,GAAG,EAArF;EAAyFC,cAAc,GAAG,KAA1G;EAAiHC,WAAW,GAAG,KAA/H;EAAsIC,gBAAgB,GAAG,KAAzJ;EAAgKC,cAAc,GAAG;AAAjL,CAAD,KAA6L;EAC1M,MAAMC,KAAK,GAAG,IAAAC,cAAA,EAAkB,yCAAlB,CAAd;EACA,MAAMC,SAAS,GAAGF,KAAK,CAACG,MAAN,CAAa,MAAb,CAAlB;EAEAD,SAAS,CAAE,qBAAoBE,IAAI,CAACC,SAAL,CAAed,gBAAf,CAAiC,EAAvD,CAAT;EACAW,SAAS,CAAE,kBAAiBE,IAAI,CAACC,SAAL,CAAeZ,aAAf,CAA8B,EAAjD,CAAT;EACAS,SAAS,CAAE,eAAcE,IAAI,CAACC,SAAL,CAAeX,UAAf,CAA2B,EAA3C,CAAT;EACAQ,SAAS,CAAE,kBAAiBE,IAAI,CAACC,SAAL,CAAeV,aAAf,CAA8B,EAAjD,CAAT;EACAO,SAAS,CAAE,mBAAkBE,IAAI,CAACC,SAAL,CAAeT,cAAf,CAA+B,EAAnD,CAAT;EACAM,SAAS,CAAE,gBAAeE,IAAI,CAACC,SAAL,CAAeR,WAAf,CAA4B,EAA7C,CAAT;EACAK,SAAS,CAAE,qBAAoBE,IAAI,CAACC,SAAL,CAAeP,gBAAf,CAAiC,EAAvD,CAAT;EACAI,SAAS,CAAE,mBAAkBE,IAAI,CAACC,SAAL,CAAeN,cAAf,CAA+B,EAAnD,CAAT;EAGA,MAAMO,MAAM,GAAG,IAAAC,sBAAA,EAAyBhB,gBAAzB,EAA2CK,cAA3C,CAAf;EAEA,OAAOY,MAAM,IAAI;IACf,MAAMhB,MAAM,GAAG,IAAAiB,uBAAA,EAAsB,EAAC,GAAGhB,aAAJ;MAAmBe,MAAnB;MAA2Bb;IAA3B,CAAtB,CAAf;IACA,OAAOe,OAAO,CAAC,EAAD,CAAd,CAFe,CAIf;IACA;IACA;IACA;IAEA;IACA;IACA;IACA;IACA;IACA;IACA;;IAEA,eAAeA,OAAf,CAAuB;MAACC,YAAY,GAAG,EAAhB;MAAoBC,OAAO,GAAG,EAA9B;MAAkCC,cAAc,GAAG,CAAnD;MAAsDC,UAAU,GAAG,EAAnE;MAAuEC,cAAc,GAAG,CAAxF;MAA2FC,aAAa,GAAG,CAA3G;MAA8GC,kBAAkB,GAAG,EAAnI;MAAuIC,WAAW,GAAG;IAArJ,CAAvB,EAAiL;MAC/KhB,SAAS,CAAE,kCAAF,CAAT;MACA,MAAM;QAACiB,OAAD;QAAUC,QAAV;QAAoB,GAAGC;MAAvB,IAAgC,MAAM7B,MAAM,CAACmB,YAAD,CAAlD;MAEAT,SAAS,CAAE,kBAAiBE,IAAI,CAACC,SAAL,CAAegB,KAAf,CAAsB,cAAaT,OAAO,CAACU,MAAO,qBAAoBT,cAAe,iBAAgBC,UAAU,CAACQ,MAAO,oBAAmBN,aAAc,yBAAwBC,kBAAmB,kBAAiBC,WAAW,CAACI,MAAO,EAA1P,CAAT;MACA,MAAMC,aAAa,GAAGJ,OAAO,CAACG,MAA9B;MACA,MAAME,cAAc,GAAGJ,QAAQ,CAACE,MAAhC;MACA,MAAMG,iBAAiB,GAAGZ,cAAc,GAAGU,aAAjB,GAAiCC,cAA3D;MAEA,MAAME,qBAAqB,GAAGT,kBAAkB,CAACU,MAAnB,CAA0BP,QAA1B,CAA9B;MACAlB,SAAS,CAAE,aAAYkB,QAAQ,CAACE,MAAO,yBAAwBL,kBAAkB,CAACK,MAAO,4BAA2BI,qBAAqB,CAACJ,MAAO,EAAxI,CAAT;;MAEA,IAAIC,aAAa,GAAG,CAApB,EAAuB;QACrB,OAAOK,eAAe,EAAtB;MACD;;MAED,IAAIP,KAAK,CAACQ,WAAN,GAAoB,CAAxB,EAA2B;QACzB7B,KAAK,CAAE,oBAAmBqB,KAAK,CAACS,aAAc,QAAOT,KAAK,CAACU,KAAM,mBAAkBV,KAAK,CAACQ,WAAY,eAAhG,CAAL;QACA,OAAOnB,OAAO,CAAC;UAACC,YAAY,EAAEU,KAAf;UAAsBT,OAAtB;UAA+BC,cAAc,EAAEY,iBAA/C;UAAkEX,UAAlE;UAA8EE,aAA9E;UAA6FD,cAA7F;UAA6GE,kBAAkB,EAAES,qBAAjI;UAAwJR;QAAxJ,CAAD,CAAd;MACD;;MAEDlB,KAAK,CAAE,wEAAuEY,OAAO,CAACU,MAAO,EAAxF,CAAL;MACA,OAAOU,YAAY,CAAC;QAACpB,OAAD;QAAUS,KAAV;QAAiBY,UAAU,EAAE,EAA7B;QAAiCnB,UAAjC;QAA6CE,aAA7C;QAA4DH,cAAc,EAAEY,iBAA5E;QAA+FV,cAA/F;QAA+GE,kBAAkB,EAAES,qBAAnI;QAA0JR;MAA1J,CAAD,CAAnB;;MAEA,SAASU,eAAT,GAA2B;QACzB5B,KAAK,CAAE,0BAAyBuB,aAAc,qDAAoDF,KAAK,CAACS,aAAc,eAAcT,KAAK,CAACU,KAAM,EAA3I,CAAL;QAEA,MAAMG,WAAW,GAAGC,cAAc,CAAC;UAAChB,OAAD;UAAUI,aAAV;UAAyB7B,UAAzB;UAAqCkB,OAArC;UAA8CE,UAA9C;UAA0DE;QAA1D,CAAD,CAAlC;QAEA,MAAMoB,iBAAiB,GAAGrB,cAAc,GAAGmB,WAAW,CAACnB,cAAvD;QACA,MAAMsB,gBAAgB,GAAGrB,aAAa,GAAGkB,WAAW,CAAClB,aAArD;QACA,MAAM;UAACsB,UAAD;UAAaC,aAAb;UAA4BC;QAA5B,IAA8CC,iBAAiB,CAACP,WAAD,EAActB,OAAd,EAAuBE,UAAvB,EAAmCI,WAAnC,CAArE;;QAEA,IAAIwB,eAAe,CAAC;UAAC9B,OAAO,EAAE0B,UAAV;UAAsB5C;QAAtB,CAAD,CAAnB,EAAwD;UACtD,OAAOsC,YAAY,CAAC;YAACpB,OAAO,EAAE0B,UAAV;YAAsBjB,KAAtB;YAA6BY,UAAU,EAAE,YAAzC;YAAuDnB,UAAU,EAAEyB,aAAnE;YAAkFxB,cAAc,EAAEqB,iBAAlG;YAAqHvB,cAAc,EAAEY,iBAArI;YAAwJT,aAAa,EAAEqB,gBAAvK;YAAyLpB,kBAAkB,EAAES,qBAA7M;YAAoOR,WAAW,EAAEsB;UAAjP,CAAD,CAAnB;QACD;;QAED,IAAIG,sBAAsB,CAAClB,iBAAD,EAAoB9B,aAApB,CAA1B,EAA8D;UAC5D,OAAOqC,YAAY,CAAC;YAACpB,OAAO,EAAE0B,UAAV;YAAsBjB,KAAtB;YAA6BY,UAAU,EAAE,eAAzC;YAA0DnB,UAAU,EAAEyB,aAAtE;YAAqFxB,cAAc,EAAEqB,iBAArG;YAAwHvB,cAAc,EAAEY,iBAAxI;YAA2JT,aAAa,EAAEqB,gBAA1K;YAA4LpB,kBAAkB,EAAES,qBAAhN;YAAuOR,WAAW,EAAEsB;UAApP,CAAD,CAAnB;QACD;;QAED,OAAO9B,OAAO,CAAC;UAACC,YAAY,EAAEU,KAAf;UAAsBT,OAAO,EAAE0B,UAA/B;UAA2CzB,cAAc,EAAEY,iBAA3D;UAA8EX,UAAU,EAAEyB,aAA1F;UAAyGxB,cAAc,EAAEqB,iBAAzH;UAA4IpB,aAAa,EAAEqB,gBAA3J;UAA6KpB,kBAAkB,EAAES,qBAAjM;UAAwNR,WAAW,EAAEsB;QAArO,CAAD,CAAd;MACD;;MAED,SAASC,iBAAT,CAA2BP,WAA3B,EAAwCtB,OAAxC,EAAiDE,UAAjD,EAA6DI,WAA7D,EAA0E;QACxEhB,SAAS,CAAE,4CAA2CgC,WAAW,CAACtB,OAAZ,CAAoBU,MAAO,EAAxE,CAAT,CADwE,CAExE;;QACA,IAAIxB,gBAAJ,EAAsB;UACpBI,SAAS,CAAE,+CAA8CgC,WAAW,CAACpB,UAAZ,CAAuBQ,MAAO,EAA9E,CAAT;QACD;;QAED,MAAMgB,UAAU,GAAG1B,OAAO,CAACe,MAAR,CAAe9B,WAAW,GAAG+C,QAAQ,CAACV,WAAW,CAACtB,OAAb,CAAX,GAAmCsB,WAAW,CAACtB,OAAzE,CAAnB;QACA,MAAM2B,aAAa,GAAGzC,gBAAgB,GAAGgB,UAAU,CAACa,MAAX,CAAkB9B,WAAW,GAAG+C,QAAQ,CAACV,WAAW,CAACpB,UAAb,CAAX,GAAsCoB,WAAW,CAACpB,UAA/E,CAAH,GAAgG,EAAtI;QACA,MAAM0B,cAAc,GAAGtB,WAAW,CAACS,MAAZ,CAAmBO,WAAW,CAAChB,WAA/B,CAAvB;QAEAhB,SAAS,CAAE,8BAA6BoC,UAAU,CAAChB,MAAO,EAAjD,CAAT,CAXwE,CAYxE;;QACA,IAAIxB,gBAAJ,EAAsB;UACpBI,SAAS,CAAE,iCAAgCqC,aAAa,CAACjB,MAAO,EAAvD,CAAT;QACD;;QAEDpB,SAAS,CAAE,gBAAeE,IAAI,CAACC,SAAL,CAAe6B,WAAf,CAA4B,EAA7C,CAAT;QACAhC,SAAS,CAAE,oBAAmBE,IAAI,CAACC,SAAL,CAAea,WAAf,CAA4B,mCAAkCd,IAAI,CAACC,SAAL,CAAe6B,WAAW,CAAChB,WAA3B,CAAwC,sBAAqBd,IAAI,CAACC,SAAL,CAAemC,cAAf,CAA+B,EAA/K,CAAT;QAEAtC,SAAS,CAAE,kCAAiCsC,cAAc,CAAClB,MAAO,EAAzD,CAAT;QAEA,OAAO;UAACgB,UAAD;UAAaC,aAAb;UAA4BC;QAA5B,CAAP;MACD;;MAED,SAASI,QAAT,CAAkBhC,OAAlB,EAA2B;QACzBV,SAAS,CAAE,gBAAemB,KAAK,CAACU,KAAM,aAA7B,CAAT;QACA,OAAOnB,OAAO,CAACiC,GAAR,CAAaC,KAAD,KAAY,EAAC,GAAGA,KAAJ;UAAWC,UAAU,EAAE1B,KAAK,CAACU;QAA7B,CAAZ,CAAZ,CAAP;MACD;;MAED,SAASY,sBAAT,CAAgC9B,cAAhC,EAAgDlB,aAAhD,EAA+D;QAC7DO,SAAS,CAAE,gDAA+CuB,iBAAkB,UAAS9B,aAAc,GAA1F,CAAT;;QACA,IAAIA,aAAa,IAAIkB,cAAc,IAAIlB,aAAvC,EAAsD;UACpDK,KAAK,CAAE,gEAA+Da,cAAe,MAAKlB,aAAc,sBAAnG,CAAL;UACA,OAAO,IAAP;QACD;MACF;IACF,CAlGc,CAoGf;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IAEA;IAEA;IACA;IACA;IACA;;;IAEA,SAASqC,YAAT,CAAsB;MAACpB,OAAD;MAAUS,KAAV;MAAiBY,UAAjB;MAA6BnB,UAA7B;MAAyCC,cAAzC;MAAyDF,cAAzD;MAAyEG,aAAzE;MAAwFC,kBAAxF;MAA4GC;IAA5G,CAAtB,EAAgJ;MAC9I,MAAM8B,sBAAsB,GAAG/B,kBAAkB,CAACK,MAAlD;MACA,MAAM2B,eAAe,GAAG/B,WAAW,CAACI,MAApC;MACA4B,WAAW,CAAC;QAACtC,OAAD;QAAUE,UAAV;QAAsBD,cAAtB;QAAsCE,cAAtC;QAAsDC,aAAtD;QAAqEgC,sBAArE;QAA6FC;MAA7F,CAAD,CAAX;MACA,MAAME,WAAW,GAAGC,aAAa,CAAC/B,KAAD,EAAQY,UAAR,EAAoBe,sBAApB,EAA4CC,eAA5C,CAAjC,CAJ8I,CAK9I;;MACA,MAAMI,aAAa,GAAGvD,gBAAgB,GAAG;QAACc,OAAD;QAAUuC,WAAV;QAAuBrC;MAAvB,CAAH,GAAwC;QAACF,OAAD;QAAUuC;MAAV,CAA9E;MACA,MAAM/B,QAAQ,GAAG,CAAC,GAAGH,kBAAJ,EAAwB,GAAGC,WAA3B,CAAjB;MACA,MAAMoC,MAAM,GAAGvD,cAAc,GAAG,EAAC,GAAGsD,aAAJ;QAAmBpC,kBAAkB,EAAEG;MAAvC,CAAH,GAAsDiC,aAAnF;MACAnD,SAAS,CAAE,kBAAiBH,cAAe,EAAlC,CAAT;MACAG,SAAS,CAAE,GAAEE,IAAI,CAACC,SAAL,CAAeiD,MAAf,CAAuB,EAA3B,CAAT;MACA,OAAOA,MAAP,CAX8I,CAa9I;;MAEA,SAASJ,WAAT,CAAqB;QAACtC,OAAD;QAAUE,UAAV;QAAsBD,cAAtB;QAAsCE,cAAtC;QAAsDC,aAAtD;QAAqEgC,sBAArE;QAA6FC;MAA7F,CAArB,EAAoI;QAClI,MAAMM,UAAU,GAAG3C,OAAO,CAACU,MAA3B;QACApB,SAAS,CAAE,sBAAqBJ,gBAAiB,EAAxC,CAAT;QACA,MAAM0D,mBAAmB,GAAG1D,gBAAgB,GAAGgB,UAAU,CAACQ,MAAd,GAAuBN,aAAnE;QACA,MAAMyC,YAAY,GAAGF,UAAU,GAAGC,mBAAb,GAAmCzC,cAAxD;QACAf,KAAK,CAAE,mBAAkBa,cAAe,cAAa0C,UAAW,iBAAgBC,mBAAoB,qBAAoBzC,cAAe,6BAA4BiC,sBAAuB,sBAAqBC,eAAgB,EAA1N,CAAL;QACAjD,KAAK,CAAE,qBAAoByD,YAAa,MAAK5C,cAAe,uBAAvD,CAAL;;QACA,IAAI4C,YAAY,KAAK5C,cAArB,EAAqC;UACnCb,KAAK,CAAE,gCAA+Ba,cAAc,GAAG4C,YAAa,aAA/D,CAAL;UACA;QACD;;QACD;MACD,CA3B6I,CA6B9I;;;MACA,SAASL,aAAT,CAAuB/B,KAAvB,EAA8BY,UAA9B,EAA0CyB,uBAA1C,EAAmET,eAAnE,EAAoF;QAClF/C,SAAS,CAAE,GAAEE,IAAI,CAACC,SAAL,CAAegB,KAAf,CAAsB,EAA1B,CAAT;QACArB,KAAK,CAAE,UAAS0D,uBAAwB,oDAAnC,CAAL;QACA1D,KAAK,CAAE,UAASiD,eAAgB,uDAA3B,CAAL;QACAjD,KAAK,CAAE,gBAAeqB,KAAK,CAACQ,WAAY,sCAAqCR,KAAK,CAACsC,eAAN,IAAyBtC,KAAK,CAACsC,eAAN,IAAyBtC,KAAK,CAACuC,YAAa,4BAA2BvC,KAAK,CAACuC,YAAN,GAAqBvC,KAAK,CAACwC,qBAAsB,mBAAkBxC,KAAK,CAACyC,YAAN,CAAmBxC,MAAO,MAAKD,KAAK,CAACyC,YAAa,EAA7R,CAAL;QAEA5D,SAAS,CAAE,gBAAe+B,UAAW,GAA5B,CAAT;QAEA,MAAM8B,YAAY,GAAG1C,KAAK,CAACsC,eAAN,IAAyBtC,KAAK,CAACsC,eAAN,IAAyBtC,KAAK,CAACuC,YAA7E;QACA,MAAMI,YAAY,GAAGD,YAAY,GAAG1C,KAAK,CAACuC,YAAN,GAAqBvC,KAAK,CAACwC,qBAA9B,GAAsD,CAAvF;QACA3D,SAAS,CAAE,iBAAgB8D,YAAa,EAA/B,CAAT,CAVkF,CAYlF;QACA;;QAEA,IAAI3C,KAAK,CAACQ,WAAN,GAAoB,CAApB,IAAyBmC,YAAY,GAAG,CAAxC,IAA6C3C,KAAK,CAACyC,YAAN,CAAmBxC,MAAnB,GAA4B,CAAzE,IAA8E0B,sBAAsB,GAAG,CAAvG,IAA4GC,eAAe,GAAG,CAAlI,EAAqI;UACnI,MAAMgB,sBAAsB,GAAG5C,KAAK,CAACyC,YAAN,CAAmBxC,MAAnB,GAA4B,CAA5B,GAAgC,cAAhC,GAAiD4C,SAAhF;UACA,MAAMC,4BAA4B,GAAGnB,sBAAsB,GAAG,CAAzB,GAA6B,oBAA7B,GAAoDkB,SAAzF;UACA,MAAME,qBAAqB,GAAGnB,eAAe,GAAG,CAAlB,GAAsB,aAAtB,GAAsCiB,SAApE;UACA,MAAMG,aAAa,GAAGpC,UAAU,KAAK,EAAf,IAAqBA,UAAU,KAAKiC,SAApC,GAAgDD,sBAAsB,IAAIE,4BAA1B,IAA0DC,qBAA1G,GAAkInC,UAAxJ;UACA/B,SAAS,CAAE,4BAA2B+D,sBAAuB,GAApD,CAAT;UACA/D,SAAS,CAAE,gCAA+BiE,4BAA6B,GAA9D,CAAT;UACAjE,SAAS,CAAE,0BAAyBkE,qBAAsB,GAAjD,CAAT;UACAlE,SAAS,CAAE,mBAAkBmE,aAAc,GAAlC,CAAT;UACArE,KAAK,CAAE,qBAAF,CAAL;UACA,OAAO;YAACsE,MAAM,EAAE,KAAT;YAAgBrC,UAAU,EAAEoC;UAA5B,CAAP;QACD;;QAEDrE,KAAK,CAAE,oBAAF,CAAL;QACA,OAAO;UAACsE,MAAM,EAAE,IAAT;UAAerC;QAAf,CAAP;MACD;IACF,CAlLc,CAoLf;IACA;IACA;IACA;IAEA;;;IACA,SAASE,cAAT,CAAwB;MAAChB,OAAD;MAAUI,aAAV;MAAyB7B,UAAzB;MAAqCkB,OAAO,GAAG,EAA/C;MAAmDE,UAAU,GAAG,EAAhE;MAAoEyD,aAAa,GAAG,EAApF;MAAwFC,gBAAgB,GAAG,EAA3G;MAA+GC,WAAW,GAAG,CAA7H;MAAgIC,oBAAoB,GAAG,CAAvJ;MAA0JC,mBAAmB,GAAG,CAAhL;MAAmLC,iBAAiB,GAAG;IAAvM,CAAxB,EAAoO;MAElO;MACA;MACA;MACA;MACA;MAEA;MACA;MACA;MACA;MACA;MAEA,MAAM,CAACC,SAAD,IAAc1D,OAApB;MACA,MAAM2D,cAAc,GAAGD,SAAS,GAAGJ,WAAW,GAAG,CAAjB,GAAqBA,WAArD,CAfkO,CAiBlO;MACA;MACA;MACA;;MAEA;AACN;AACA;AACA;AACA;AACA;AACA;;MAEM,IAAII,SAAJ,EAAe;QAEb;QACA,IAAIE,qBAAqB,CAACnE,OAAO,CAACe,MAAR,CAAeb,UAAf,CAAD,EAA6B+D,SAA7B,CAAzB,EAAkE;UAChE,MAAM;YAACrE,MAAM,EAAEwE,eAAT;YAA0BC,EAAE,EAAEC;UAA9B,IAA6CL,SAAnD;;UACA,IAAI;YACF7E,KAAK,CAAE,qCAAoCkF,WAAY,KAAIJ,cAAe,IAAGvD,aAAc,GAAtF,CAAL,CADE,CAEF;;YACA,MAAM4D,eAAe,GAAG7E,MAAM,CAACE,MAAD,EAASwE,eAAT,CAA9B;YAEA,OAAOI,qBAAqB,CAACD,eAAD,EAAkBD,WAAlB,EAA+BF,eAA/B,CAA5B;UACD,CAND,CAME,OAAOK,KAAP,EAAc;YACdrF,KAAK,CAAE,2CAA0CkF,WAAY,KAAIG,KAAM,EAAlE,CAAL;YAEA,MAAMC,UAAU,GAAG;cAAChB,MAAM,EAAE,GAAT;cAAciB,OAAO,EAAE;gBAACC,OAAO,EAAG,wCAAuCN,WAAY,KAAIG,KAAK,CAACG,OAAQ,GAAhF;gBAAoFP,EAAE,EAAEC;cAAxF;YAAvB,CAAnB;YACA,MAAMO,oBAAoB,GAAGb,iBAAiB,CAACjD,MAAlB,CAAyB2D,UAAzB,CAA7B;YACA,OAAOnD,cAAc,CAAC;cAAChB,OAAO,EAAEA,OAAO,CAACuE,KAAR,CAAc,CAAd,CAAV;cAA4BnE,aAA5B;cAA2C7B,UAA3C;cAAuDkB,OAAvD;cAAgE2D,aAAhE;cAA+EE,WAAW,EAAEK,cAA5F;cAA4GN,gBAA5G;cAA8HE,oBAA9H;cAAoJC,mBAApJ;cAAyKC,iBAAiB,EAAEa;YAA5L,CAAD,CAArB;UACD;QACF;;QAED,OAAOtD,cAAc,CAAC;UAAChB,OAAO,EAAEA,OAAO,CAACuE,KAAR,CAAc,CAAd,CAAV;UAA4BnE,aAA5B;UAA2C7B,UAA3C;UAAuDkB,OAAvD;UAAgE2D,aAAhE;UAA+EE,WAAW,EAAEK,cAA5F;UAA4GN,gBAA5G;UAA8HE,oBAAoB,EAAEA,oBAAoB,GAAG,CAA3K;UAA8KC,mBAA9K;UAAmMC;QAAnM,CAAD,CAArB;MACD;;MAED5E,KAAK,CAAE,mCAAkCyE,WAAY,IAAGlD,aAAc,WAAUgD,aAAa,CAACjD,MAAO,mBAAkBoD,oBAAqB,gCAA+B5E,gBAAgB,GAAI,GAAE0E,gBAAgB,CAAClD,MAAO,EAA9B,GAAmC,GAAEqD,mBAAoB,EAAE,oBAAjP,CAAL;MACA,OAAO;QAAC/D,OAAO,EAAE2D,aAAV;QAAyBzD,UAAU,EAAEhB,gBAAgB,GAAG0E,gBAAH,GAAsB,EAA3E;QAA+EzD,cAAc,EAAE2D,oBAA/F;QAAqH1D,aAAa,EAAE2D,mBAApI;QAAyJzD,WAAW,EAAE0D;MAAtK,CAAP;;MAEA,SAASQ,qBAAT,CAA+BD,eAA/B,EAAgDD,WAAhD,EAA6DF,eAA7D,EAA8E;QAC5E9E,SAAS,CAAE,8BAA6BgF,WAAY,KAAIJ,cAAe,IAAGvD,aAAc,MAAKnB,IAAI,CAACC,SAAL,CAAe8E,eAAf,CAAgC,EAApH,CAAT;;QAEA,IAAIA,eAAe,CAACrC,KAAhB,IAAyBhD,gBAA7B,EAA+C;UAC7CE,KAAK,CAAE,GAAEmF,eAAe,CAACrC,KAAhB,GAAyB,UAASoC,WAAY,KAAIJ,cAAe,IAAGvD,aAAc,eAAlF,GAAoG,UAAS2D,WAAY,KAAIJ,cAAe,IAAGvD,aAAc,mBAAmB,EAApL,CAAL;UACArB,SAAS,CAAE,aAAYE,IAAI,CAACC,SAAL,CAAe8E,eAAe,CAACQ,QAA/B,CAAyC,eAAcvF,IAAI,CAACC,SAAL,CAAe8E,eAAe,CAACS,QAA/B,CAAyC,EAA9G,CAAT;UAEA,MAAM1D,WAAW,GAAG;YAClB2D,WAAW,EAAEV,eAAe,CAACU,WADX;YAElBhB,SAAS,EAAE;cACTI,EAAE,EAAEC,WADK;cAET1E,MAAM,EAAEwE;YAFC;UAFO,CAApB;UAOA,MAAMc,cAAc,GAAG;YACrBH,QAAQ,EAAER,eAAe,CAACQ,QADL;YAErBC,QAAQ,EAAET,eAAe,CAACS;UAFL,CAAvB;UAIA,MAAMG,QAAQ,GAAGnG,cAAc,GAAG,EAAC,GAAGsC,WAAJ;YAAiB,GAAG4D;UAApB,CAAH,GAAyC,EAAC,GAAG5D;UAAJ,CAAxE;UAEAhC,SAAS,CAAE,GAAEE,IAAI,CAACC,SAAL,CAAe0F,QAAf,CAAyB,EAA7B,CAAT;UAEA,OAAOC,iBAAiB,CAACb,eAAe,CAACrC,KAAjB,EAAwBiD,QAAxB,CAAxB;QACD;;QAED,MAAME,sBAAsB,GAAGtB,mBAAmB,GAAG,CAArD;QACAzE,SAAS,CAAE,4CAA2C+F,sBAAuB,EAApE,CAAT;QAEA,OAAO9D,cAAc,CAAC;UAAChB,OAAO,EAAEA,OAAO,CAACuE,KAAR,CAAc,CAAd,CAAV;UAA4BnE,aAA5B;UAA2C7B,UAA3C;UAAuDkB,OAAvD;UAAgE2D,aAAhE;UAA+EE,WAAW,EAAEK,cAA5F;UAA4GN,gBAA5G;UAA8HE,oBAA9H;UAAoJC,mBAAmB,EAAEsB,sBAAzK;UAAiMrB;QAAjM,CAAD,CAArB;MACD;;MAED,SAASoB,iBAAT,CAA2BE,OAA3B,EAAoCH,QAApC,EAA8C;QAC5C,MAAMI,gBAAgB,GAAGD,OAAO,GAAG3B,aAAa,CAAC5C,MAAd,CAAqBoE,QAArB,CAAH,GAAoCxB,aAApE;QACA,MAAM6B,mBAAmB,GAAGF,OAAO,GAAG1B,gBAAH,GAAsBA,gBAAgB,CAAC7C,MAAjB,CAAwBoE,QAAxB,CAAzD;QACA,MAAME,sBAAsB,GAAGC,OAAO,GAAGvB,mBAAH,GAAyBA,mBAAmB,GAAG,CAArF;QAEAzE,SAAS,CAAE,yCAAwCU,OAAO,CAACe,MAAR,CAAewE,gBAAf,EAAiC7E,MAAO,UAAS5B,UAAW,GAAtG,CAAT,CAL4C,CAO5C;;QACA,IAAII,gBAAJ,EAAsB;UACpBI,SAAS,CAAE,4CAA2CY,UAAU,CAACa,MAAX,CAAkByE,mBAAlB,EAAuC9E,MAAO,EAA3F,CAAT;QACD;;QACDpB,SAAS,CAAE,+CAA8CyE,mBAAoB,EAApE,CAAT;;QAEA,IAAIjC,eAAe,CAAC;UAAC9B,OAAO,EAAEA,OAAO,CAACe,MAAR,CAAewE,gBAAf,CAAV;UAA4CzG;QAA5C,CAAD,CAAnB,EAA8E;UAC5EM,KAAK,CAAE,eAAcN,UAAW,gDAA+CoF,cAAe,yCAAwCvD,aAAa,GAAGuD,cAAe,EAAhK,CAAL;UACA,OAAO;YAAClE,OAAO,EAAEuF,gBAAV;YAA4BrF,UAAU,EAAEhB,gBAAgB,GAAGsG,mBAAH,GAAyB,EAAjF;YAAqFrF,cAAc,EAAE2D,oBAArG;YAA2H1D,aAAa,EAAEiF,sBAA1I;YAAkK/E,WAAW,EAAE0D;UAA/K,CAAP;QACD;;QAED,OAAOzC,cAAc,CAAC;UAAChB,OAAO,EAAEA,OAAO,CAACuE,KAAR,CAAc,CAAd,CAAV;UAA4BnE,aAA5B;UAA2C7B,UAA3C;UAAuDkB,OAAvD;UAAgE2D,aAAa,EAAE4B,gBAA/E;UAAiG1B,WAAW,EAAEK,cAA9G;UAA8HN,gBAAgB,EAAE1E,gBAAgB,GAAGsG,mBAAH,GAAyB,EAAzL;UAA6LrF,cAAc,EAAE2D,oBAA7M;UAAmOC,mBAAmB,EAAEsB,sBAAxP;UAAgR/E,WAAW,EAAE0D;QAA7R,CAAD,CAArB;MACD;;MAED,SAASG,qBAAT,CAA+BnE,OAA/B,EAAwCiE,SAAxC,EAAmD;QACjD7E,KAAK,CAAE,wBAAuB6E,SAAS,CAACI,EAAG,+BAA8BrE,OAAO,CAACU,MAAO,qBAAnF,CAAL;QACA,MAAM+E,cAAc,GAAGxB,SAAS,CAACI,EAAjC;QACA/E,SAAS,CAAE,mBAAkBmG,cAAe,EAAnC,CAAT;QACA,MAAM/C,MAAM,GAAG1C,OAAO,CAAC0F,IAAR,CAAa,CAAC;UAACzB;QAAD,CAAD,KAAiBA,SAAS,CAACI,EAAV,KAAiBoB,cAA/C,CAAf;QACAnG,SAAS,CAAE,WAAUoD,MAAO,EAAnB,CAAT;;QACA,IAAIA,MAAJ,EAAY;UACVtD,KAAK,CAAE,GAAE6E,SAAS,CAACI,EAAG,uBAAjB,CAAL;UACA,OAAO,KAAP;QACD;;QACDjF,KAAK,CAAE,GAAE6E,SAAS,CAACI,EAAG,kCAAjB,CAAL;QACA,OAAO,IAAP;MACD;IACF;;IAED,SAASvC,eAAT,CAAyB;MAAC9B,OAAD;MAAUlB;IAAV,CAAzB,EAAgD;MAC9C,IAAIA,UAAU,IAAIkB,OAAO,CAACU,MAAR,IAAkB5B,UAApC,EAAgD;QAC9CM,KAAK,CAAE,6CAA4CN,UAAW,0BAAzD,CAAL;QACA,OAAO,IAAP;MACD;IACF;EACF,CA3TD;AA4TD,C"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["detection","detectionOptions","search","searchOptions","maxMatches","maxCandidates","returnStrategy","returnQuery","returnNonMatches","returnFailures","debug","createDebugLogger","debugData","extend","JSON","stringify","detect","createDetectionInterface","record","createSearchInterface","iterate","initialState","matches","candidateCount","nonMatches","duplicateCount","nonMatchCount","conversionFailures","matchErrors","records","failures","state","length","recordSetSize","failureSetSize","newCandidateCount","newConversionFailures","concat","handleRecordSet","queriesLeft","searchCounter","query","returnResult","stopReason","matchResult","iterateRecords","newDuplicateCount","newNonMatchCount","newMatches","newNonMatches","newMatchErrors","handleMatchResult","maxMatchesFound","maxCandidatesRetrieved","addQuery","map","match","matchQuery","conversionFailureCount","matchErrorCount","checkCounts","matchStatus","getMatchState","matchesResult","result","matchCount","chosenNonMatchCount","totalHandled","conversionFailuresCount","resultSetOffset","totalRecords","queryCandidateCounter","maxedQueries","searchesLeft","nonRetrieved","maxedQueriesStopReason","undefined","conversionFailuresStopReason","matchErrorsStopReason","newStopReason","status","recordMatches","recordNonMatches","recordCount","recordDuplicateCount","recordNonMatchCount","recordMatchErrors","candidate","newRecordCount","candidateNotInMatches","candidateRecord","id","candidateId","detectionResult","handleDetectionResult","error","matchError","payload","message","newRecordMatchErrors","slice","strategy","treshold","probability","strategyResult","newMatch","handleRecordMatch","newRecordNonMatchCount","isMatch","newRecordMatches","newRecordNonMatches","newCandidateId","find"],"sources":["../src/index.js"],"sourcesContent":["/**\n*\n* @licstart The following is the entire license notice for the JavaScript code in this file.\n*\n* Melinda record matching modules for Javascript\n*\n* Copyright (C) 2020-2022 University Of Helsinki (The National Library Of Finland)\n*\n* This file is part of melinda-record-matching-js\n*\n* melinda-record-matching-js program is free software: you can redistribute it and/or modify\n* it under the terms of the GNU Lesser General Public License as\n* published by the Free Software Foundation, either version 3 of the\n* License, or (at your option) any later version.\n*\n* melinda-record-matching-js is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n* GNU Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Affero General Public License\n* along with this program. If not, see <http://www.gnu.org/licenses/>.\n*\n* @licend The above is the entire license notice\n* for the JavaScript code in this file.\n*\n*/\n\nimport createDebugLogger from 'debug';\nimport createSearchInterface, * as candidateSearch from './candidate-search';\nimport createDetectionInterface, * as matchDetection from './match-detection';\n//import inspect from 'util';\n\nexport {candidateSearch, matchDetection};\n\nexport default ({detection: detectionOptions, search: searchOptions, maxMatches = 1, maxCandidates = 25, returnStrategy = false, returnQuery = false, returnNonMatches = false, returnFailures = false}) => {\n const debug = createDebugLogger('@natlibfi/melinda-record-matching:index');\n const debugData = debug.extend('data');\n\n debugData(`DetectionOptions: ${JSON.stringify(detectionOptions)}`);\n debugData(`SearchOptions: ${JSON.stringify(searchOptions)}`);\n debugData(`MaxMatches: ${JSON.stringify(maxMatches)}`);\n debugData(`MaxCandidates: ${JSON.stringify(maxCandidates)}`);\n debugData(`ReturnStrategy: ${JSON.stringify(returnStrategy)}`);\n debugData(`ReturnQuery: ${JSON.stringify(returnQuery)}`);\n debugData(`ReturnNonMatches: ${JSON.stringify(returnNonMatches)}`);\n debugData(`ReturnFailures: ${JSON.stringify(returnFailures)}`);\n\n\n const detect = createDetectionInterface(detectionOptions, returnStrategy);\n\n return record => {\n const search = createSearchInterface({...searchOptions, record, maxCandidates});\n return iterate({});\n\n // candidateCount : amount of candidate records retrived from SRU for matching, NOT including current record set\n // matches : candidates that have been detected as matches by current matcher job\n // nonMatches : candidates that have been detected as non-matches by current matcher job (only if returnNonMatches is 'true')\n // duplicateCount : amount of candidate records that were retrieved from the SRU but not handled further because they were already found in the matches/nonMatches\n\n // state.totalRecords : amount of candidate records available to the current query (undefined, if there was no queries left)\n // state.query : current query (undefined if there was no queries left)\n // state.searchCounter : sequence for current search for current query (undefined, if there we no queries left)\n // state.queryCandidateCounter: amount of candidate records retrieved from SRU for matching for current query, including the current record set (undefined if there were no queries left)\n // state.queriesLeft : amount of queries left\n // state.queryCounter : sequence for current query\n // state.maxedQueries : queries that resulted in more than serverMaxResults hits\n\n async function iterate({initialState = {}, matches = [], candidateCount = 0, nonMatches = [], duplicateCount = 0, nonMatchCount = 0, conversionFailures = [], matchErrors = []}) {\n debugData(`Starting next matcher iteration.`);\n const {records, failures, ...state} = await search(initialState);\n\n debugData(`Current state: ${JSON.stringify(state)}, matches: ${matches.length}, candidateCount: ${candidateCount}, nonMatches: ${nonMatches.length}, nonMatchCount: ${nonMatchCount}, conversionFailures: ${conversionFailures}, matchErrors: ${matchErrors.length}`);\n const recordSetSize = records.length;\n const failureSetSize = failures.length;\n const newCandidateCount = candidateCount + recordSetSize + failureSetSize;\n\n const newConversionFailures = conversionFailures.concat(failures);\n debugData(`Failures: ${failures.length}, ConversionFailures: ${conversionFailures.length}, NewConversionFailures: ${newConversionFailures.length}`);\n\n if (recordSetSize > 0) {\n return handleRecordSet();\n }\n\n if (state.queriesLeft > 0) {\n debug(`Empty record set ${state.searchCounter} for ${state.query}, but there are ${state.queriesLeft} queries left`);\n return iterate({initialState: state, matches, candidateCount: newCandidateCount, nonMatches, nonMatchCount, duplicateCount, conversionFailures: newConversionFailures, matchErrors});\n }\n\n debug(`No (more) candidate records to check, no more queries left, matches: ${matches.length}`);\n return returnResult({matches, state, stopReason: '', nonMatches, nonMatchCount, candidateCount: newCandidateCount, duplicateCount, conversionFailures: newConversionFailures, matchErrors});\n\n function handleRecordSet() {\n debug(`Checking record set of ${recordSetSize} candidate records for possible matches, found by ${state.searchCounter} search for ${state.query}`);\n\n const matchResult = iterateRecords({records, recordSetSize, maxMatches, matches, nonMatches, nonMatchCount});\n\n const newDuplicateCount = duplicateCount + matchResult.duplicateCount;\n const newNonMatchCount = nonMatchCount + matchResult.nonMatchCount;\n const {newMatches, newNonMatches, newMatchErrors} = handleMatchResult(matchResult, matches, nonMatches, matchErrors);\n\n if (maxMatchesFound({matches: newMatches, maxMatches})) {\n return returnResult({matches: newMatches, state, stopReason: 'maxMatches', nonMatches: newNonMatches, duplicateCount: newDuplicateCount, candidateCount: newCandidateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures, matchErrors: newMatchErrors});\n }\n\n if (maxCandidatesRetrieved(newCandidateCount, maxCandidates)) {\n return returnResult({matches: newMatches, state, stopReason: 'maxCandidates', nonMatches: newNonMatches, duplicateCount: newDuplicateCount, candidateCount: newCandidateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures, matchErrors: newMatchErrors});\n }\n\n return iterate({initialState: state, matches: newMatches, candidateCount: newCandidateCount, nonMatches: newNonMatches, duplicateCount: newDuplicateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures, matchErrors: newMatchErrors});\n }\n\n function handleMatchResult(matchResult, matches, nonMatches, matchErrors) {\n debugData(`- Amount of new matches from record set: ${matchResult.matches.length}`);\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Amount of new nonMatches from record set: ${matchResult.nonMatches.length}`);\n }\n\n const newMatches = matches.concat(returnQuery ? addQuery(matchResult.matches) : matchResult.matches);\n const newNonMatches = returnNonMatches ? nonMatches.concat(returnQuery ? addQuery(matchResult.nonMatches) : matchResult.nonMatches) : [];\n const newMatchErrors = matchErrors.concat(matchResult.matchErrors);\n\n debugData(`- Total amount of matches: ${newMatches.length}`);\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Total amount of nonMatches: ${newNonMatches.length}`);\n }\n\n debugData(`MatchResult: ${JSON.stringify(matchResult)}`);\n debugData(`Old matchErrors: ${JSON.stringify(matchErrors)}, matchErrors from matchResult: ${JSON.stringify(matchResult.matchErrors)}, New matchErrors: ${JSON.stringify(newMatchErrors)}`);\n\n debugData(`- Total amount of matchErrors: ${newMatchErrors.length}`);\n\n return {newMatches, newNonMatches, newMatchErrors};\n }\n\n function addQuery(matches) {\n debugData(`Adding query ${state.query} to matches`);\n return matches.map((match) => ({...match, matchQuery: state.query}));\n }\n\n function maxCandidatesRetrieved(candidateCount, maxCandidates) {\n debugData(`Total amount of candidate records retrieved: ${newCandidateCount} (max: ${maxCandidates})`);\n if (maxCandidates && candidateCount >= maxCandidates) {\n debug(`Stopped matching because maximum number of candidate records ${candidateCount} / ${maxCandidates} have been retrieved`);\n return true;\n }\n }\n }\n\n // matches : array of matching candidate records\n // nonMatches : array of nonMatching candidate records (if returnNonMatches option is true, otherwise empty array)\n // - candidate.id\n // - candidate.record\n // - probability\n // - strategy (if returnStrategy option is true)\n // - treshold (if returnStrategy option is true)\n // - matchQuery (if returnQuery option is true)\n // failures: array of conversionFailures from candidate-search and matchErrors from matchDetection in error format {status, payload: {message, id}} if returnFailures is true\n\n // we could have here also returnRecords/returnMatchRecords/returnNonMatchRecord options that could be turned false for not to return actual record data\n\n // matchStatus.status: boolean, true if matcher retrieved and handled all found candidate records, false if it did not\n // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records\n // - only one stopReason is returned (if there would be several possible stopReasons, stopReason is picked in the above order)\n // - currently stopReason can be non-empty also in cases where status is true, if matcher hit the stop reason when handling the last available candidate record\n\n function returnResult({matches, state, stopReason, nonMatches, duplicateCount, candidateCount, nonMatchCount, conversionFailures, matchErrors}) {\n const conversionFailureCount = conversionFailures.length;\n const matchErrorCount = matchErrors.length;\n checkCounts({matches, nonMatches, candidateCount, duplicateCount, nonMatchCount, conversionFailureCount, matchErrorCount});\n const matchStatus = getMatchState(state, stopReason, conversionFailureCount, matchErrorCount);\n // add nonMatches to result only if returnNonMatches is 'true', otherwise nonMatches have not been gathered\n const matchesResult = returnNonMatches ? {matches, matchStatus, nonMatches} : {matches, matchStatus};\n const failures = [...conversionFailures, ...matchErrors];\n const result = returnFailures ? {...matchesResult, conversionFailures: failures} : matchesResult;\n debugData(`ReturnFailures ${returnFailures}`);\n debugData(`${JSON.stringify(result)}`);\n return result;\n\n // note that in cases where the matching has been stopped because of maxMatches checkCounts won't (in most cases) match\n\n function checkCounts({matches, nonMatches, candidateCount, duplicateCount, nonMatchCount, conversionFailureCount, matchErrorCount}) {\n const matchCount = matches.length;\n debugData(`Return nonMatches: ${returnNonMatches}`);\n const chosenNonMatchCount = returnNonMatches ? nonMatches.length : nonMatchCount;\n const totalHandled = matchCount + chosenNonMatchCount + duplicateCount;\n debug(`candidateCount: ${candidateCount}, matches: ${matchCount}, nonMatches: ${chosenNonMatchCount}, duplicateCount: ${duplicateCount}, conversionFailureCount: ${conversionFailureCount}, matchErrorCount: ${matchErrorCount}`);\n debug(`We got result for ${totalHandled} / ${candidateCount} retrieved candidates`);\n if (totalHandled !== candidateCount) {\n debug(`WARNING: Missing results for ${candidateCount - totalHandled} candidates`);\n return;\n }\n return;\n }\n\n // eslint-disable-next-line max-statements\n function getMatchState(state, stopReason, conversionFailuresCount, matchErrorCount) {\n debugData(`${JSON.stringify(state)}`);\n debug(`We had ${conversionFailuresCount} retrieved candidates that could not be converted.`);\n debug(`We had ${matchErrorCount} retrieved candidates that errored in matchDetection.`);\n debug(`Queries left ${state.queriesLeft}, Searches for current query left: ${state.resultSetOffset && state.resultSetOffset <= state.totalRecords}, non-retrieved records: ${state.totalRecords - state.queryCandidateCounter}, maxedQueries (${state.maxedQueries.length}): ${state.maxedQueries}`);\n\n debugData(`StopReason: <${stopReason}>`);\n\n const searchesLeft = state.resultSetOffset && state.resultSetOffset <= state.totalRecords;\n const nonRetrieved = searchesLeft ? state.totalRecords - state.queryCandidateCounter : 0;\n debugData(`nonRetrieved: ${nonRetrieved}`);\n\n // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records\n // 'maxMatches' and 'maxCandidates' are in stopReason, 'maxedQueries', 'conversionFailures' and 'matchErrors' are created here\n\n if (state.queriesLeft > 0 || nonRetrieved > 0 || state.maxedQueries.length > 0 || conversionFailureCount > 0 || matchErrorCount > 0) {\n const maxedQueriesStopReason = state.maxedQueries.length > 0 ? 'maxedQueries' : undefined;\n const conversionFailuresStopReason = conversionFailureCount > 0 ? 'conversionFailures' : undefined;\n const matchErrorsStopReason = matchErrorCount > 0 ? 'matchErrors' : undefined;\n const newStopReason = stopReason === '' || stopReason === undefined ? maxedQueriesStopReason || conversionFailuresStopReason || matchErrorsStopReason : stopReason;\n debugData(`MaxedQueriesStopReason: <${maxedQueriesStopReason}>`);\n debugData(`ConversionFailureStopReason <${conversionFailuresStopReason}>`);\n debugData(`MatchErrorsStopReason <${matchErrorsStopReason}>`);\n debugData(`NewStopReason: <${newStopReason}>`);\n debug(`Match status: false`);\n return {status: false, stopReason: newStopReason};\n }\n\n debug(`Match status: true`);\n return {status: true, stopReason};\n }\n }\n\n // NOTES:\n // - we could optimize by creating the featureSet for the incoming record once and using it for all database/candidateRecords\n // - if creating the featureSet for the incoming record fails we have an unprocessable entity\n // - if creating the featureSet for a candidate record fails we could skip that candidate - but list the case as a detectionFailure, same as conversionFailures\n\n // eslint-disable-next-line max-statements\n function iterateRecords({records, recordSetSize, maxMatches, matches = [], nonMatches = [], recordMatches = [], recordNonMatches = [], recordCount = 0, recordDuplicateCount = 0, recordNonMatchCount = 0, recordMatchErrors = []}) {\n\n // recordSetSize : total amount of records in the current record set\n // recordCount : amount of records from the current record set that have been handled\n // maxMatches : setting for maximum amount found by current matcher job before the matcher job is stopped\n // recordDuplicateCount : amount of records from the current record set that are already included in matches/nonMatches results\n // recordNonMatchCount: amount of records from the current record set that are nonMatches (only is returnNonMatches setting is false)\n\n // records : non-handled records in the current record set\n // matches : found matches in the current matcher job\n // recordMatches : found matches in the current record set\n // recordNonMatches : found nonMatches in the current record set (only if returnNonMatches setting is true)\n // recordMatchErrors: errored matchDetection in the current record set\n\n const [candidate] = records;\n const newRecordCount = candidate ? recordCount + 1 : recordCount;\n\n // The matcher uses same matchDetection strategy for candidates from all candidate-searches -> matchDetection result for the same candidate is always same\n // Exceptions would happen if the candidate would have been updated in the database between candidate searches\n // Note that if returnNonMatches is false, matcher won't remember candidates that didn't match, so they will be matched again everytime they are retrieved by\n // different candidate search queries. Same candidate search query won't have duplicate records.\n\n /* We could optimize and detect all retrieved candidates at once\n const candidateRecords = records.map(record => record.record);\n const recordsIsArray = Array.isArray(candidateRecords);\n debug(`records is an array: ${recordsIsArray}`);\n const result = detect(record, candidateRecords);\n debug(`${JSON.stringify(result)}`);\n */\n\n if (candidate) {\n\n // eslint-disable-next-line functional/no-conditional-statement\n if (candidateNotInMatches(matches.concat(nonMatches), candidate)) {\n const {record: candidateRecord, id: candidateId} = candidate;\n try {\n debug(`Running matchDetection for record ${candidateId} (${newRecordCount}/${recordSetSize})`);\n // we should handle errors from detection somehow - ie. cases where either record or candidateRecord errors\n const detectionResult = detect(record, candidateRecord);\n\n return handleDetectionResult(detectionResult, candidateId, candidateRecord);\n } catch (error) {\n debug(`MatchDetection errored: database record ${candidateId}: ${error}`);\n\n const matchError = {status: 422, payload: {message: `Matching errored for database record ${candidateId}. ${error.message}.`, id: candidateId}};\n const newRecordMatchErrors = recordMatchErrors.concat(matchError);\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount, recordNonMatchCount, recordMatchErrors: newRecordMatchErrors});\n }\n }\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount: recordDuplicateCount + 1, recordNonMatchCount, recordMatchErrors});\n }\n\n debug(`No more candidates, record set (${recordCount}/${recordSetSize}) done, ${recordMatches.length} matches found, ${recordDuplicateCount} candidates already handled, ${returnNonMatches ? `${recordNonMatches.length}` : `${recordNonMatchCount}`} nonMatches found.`);\n return {matches: recordMatches, nonMatches: returnNonMatches ? recordNonMatches : [], duplicateCount: recordDuplicateCount, nonMatchCount: recordNonMatchCount, matchErrors: recordMatchErrors};\n\n function handleDetectionResult(detectionResult, candidateId, candidateRecord) {\n debugData(`MatchDetection results for ${candidateId} (${newRecordCount}/${recordSetSize}): ${JSON.stringify(detectionResult)}`);\n\n if (detectionResult.match || returnNonMatches) {\n debug(`${detectionResult.match ? `Record ${candidateId} (${newRecordCount}/${recordSetSize}) is a match!` : `Record ${candidateId} (${newRecordCount}/${recordSetSize}) is NOT a match!`}`);\n debugData(`Strategy: ${JSON.stringify(detectionResult.strategy)}, Treshold: ${JSON.stringify(detectionResult.treshold)}`);\n\n const matchResult = {\n probability: detectionResult.probability,\n candidate: {\n id: candidateId,\n record: candidateRecord\n }\n };\n const strategyResult = {\n strategy: detectionResult.strategy,\n treshold: detectionResult.treshold\n };\n const newMatch = returnStrategy ? {...matchResult, ...strategyResult} : {...matchResult};\n\n debugData(`${JSON.stringify(newMatch)}`);\n\n return handleRecordMatch(detectionResult.match, newMatch);\n }\n\n const newRecordNonMatchCount = recordNonMatchCount + 1;\n debugData(`- Total nonMatches after this detection: ${newRecordNonMatchCount}`);\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount, recordNonMatchCount: newRecordNonMatchCount, recordMatchErrors});\n }\n\n function handleRecordMatch(isMatch, newMatch) {\n const newRecordMatches = isMatch ? recordMatches.concat(newMatch) : recordMatches;\n const newRecordNonMatches = isMatch ? recordNonMatches : recordNonMatches.concat(newMatch);\n const newRecordNonMatchCount = isMatch ? recordNonMatchCount : recordNonMatchCount + 1;\n\n debugData(`- Total matches after this detection: ${matches.concat(newRecordMatches).length} (max: ${maxMatches})`);\n\n // eslint-disable-next-line functional/no-conditional-statement\n if (returnNonMatches) {\n debugData(`- Total nonMatches after this detection: ${nonMatches.concat(newRecordNonMatches).length}`);\n }\n debugData(`- Total nonMatchCount after this detection: ${recordNonMatchCount}`);\n\n if (maxMatchesFound({matches: matches.concat(newRecordMatches), maxMatches})) {\n debug(`MaxMatches (${maxMatches}) reached, handled candidates in record set: ${newRecordCount} non-handled candidates in record set ${recordSetSize - newRecordCount}`);\n return {matches: newRecordMatches, nonMatches: returnNonMatches ? newRecordNonMatches : [], duplicateCount: recordDuplicateCount, nonMatchCount: newRecordNonMatchCount, matchErrors: recordMatchErrors};\n }\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches: newRecordMatches, recordCount: newRecordCount, recordNonMatches: returnNonMatches ? newRecordNonMatches : [], duplicateCount: recordDuplicateCount, recordNonMatchCount: newRecordNonMatchCount, matchErrors: recordMatchErrors});\n }\n\n function candidateNotInMatches(matches, candidate) {\n debug(`Checking that record ${candidate.id} is not already included in ${matches.length} matches/nonMatches`);\n const newCandidateId = candidate.id;\n debugData(`newCandidateId: ${newCandidateId}`);\n const result = matches.find(({candidate}) => candidate.id === newCandidateId);\n debugData(`Result: ${result}`);\n if (result) {\n debug(`${candidate.id} was already handled.`);\n return false;\n }\n debug(`${candidate.id} not found in matches/nonMatches`);\n return true;\n }\n }\n\n function maxMatchesFound({matches, maxMatches}) {\n if (maxMatches && matches.length >= maxMatches) {\n debug(`Stopping recordSet iteration: maxMatches (${maxMatches}) for matcher job found.`);\n return true;\n }\n }\n };\n};\n"],"mappings":"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"}
|