@natlibfi/melinda-record-matching 2.1.0-alpha.1 → 2.2.0-alpha.1

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/index.js CHANGED
@@ -55,7 +55,8 @@ var _default = ({
55
55
  maxCandidates = 25,
56
56
  returnStrategy = false,
57
57
  returnQuery = false,
58
- returnNonMatches = false
58
+ returnNonMatches = false,
59
+ returnFailures
59
60
  }) => {
60
61
  const debug = (0, _debug.default)('@natlibfi/melinda-record-matching:index');
61
62
  const debugData = debug.extend('data');
@@ -66,10 +67,12 @@ var _default = ({
66
67
  debugData(`ReturnStrategy: ${JSON.stringify(returnStrategy)}`);
67
68
  debugData(`ReturnQuery: ${JSON.stringify(returnQuery)}`);
68
69
  debugData(`ReturnNonMatches: ${JSON.stringify(returnNonMatches)}`);
70
+ debugData(`ReturnFailures: ${JSON.stringify(returnFailures)}`);
69
71
  const detect = (0, matchDetection.default)(detectionOptions, returnStrategy);
70
72
  return record => {
71
73
  const search = (0, candidateSearch.default)({ ...searchOptions,
72
- record
74
+ record,
75
+ maxCandidates
73
76
  });
74
77
  return iterate({}); // candidateCount : amount of candidate records retrived from SRU for matching, NOT including current record set
75
78
  // matches : candidates that have been detected as matches by current matcher job
@@ -88,16 +91,22 @@ var _default = ({
88
91
  matches = [],
89
92
  candidateCount = 0,
90
93
  nonMatches = [],
91
- duplicateCount = 0
94
+ duplicateCount = 0,
95
+ nonMatchCount = 0,
96
+ conversionFailures = []
92
97
  }) {
93
98
  debugData(`Starting next matcher iteration.`);
94
99
  const {
95
100
  records,
101
+ failures,
96
102
  ...state
97
103
  } = await search(initialState);
98
- debugData(`Current state: ${JSON.stringify(state)}, matches: ${matches.length}, candidateCount: ${candidateCount}, nonMatches: ${nonMatches.length}`);
104
+ debugData(`Current state: ${JSON.stringify(state)}, matches: ${matches.length}, candidateCount: ${candidateCount}, nonMatches: ${nonMatches.length}, nonMatchCount: ${nonMatchCount}, conversionFailures: ${conversionFailures}`);
99
105
  const recordSetSize = records.length;
100
- const newCandidateCount = candidateCount + recordSetSize;
106
+ const failureSetSize = failures.length;
107
+ const newCandidateCount = candidateCount + recordSetSize + failureSetSize;
108
+ const newConversionFailures = conversionFailures.concat(failures);
109
+ debugData(`Failures: ${failures.length}, ConversionFailures: ${conversionFailures.length}, NewConversionFailures: ${newConversionFailures.length}`);
101
110
 
102
111
  if (recordSetSize > 0) {
103
112
  return handleRecordSet();
@@ -110,7 +119,9 @@ var _default = ({
110
119
  matches,
111
120
  candidateCount: newCandidateCount,
112
121
  nonMatches,
113
- duplicateCount
122
+ nonMatchCount,
123
+ duplicateCount,
124
+ conversionFailures: newConversionFailures
114
125
  });
115
126
  }
116
127
 
@@ -120,8 +131,10 @@ var _default = ({
120
131
  state,
121
132
  stopReason: '',
122
133
  nonMatches,
134
+ nonMatchCount,
123
135
  candidateCount: newCandidateCount,
124
- duplicateCount
136
+ duplicateCount,
137
+ conversionFailures: newConversionFailures
125
138
  });
126
139
 
127
140
  function handleRecordSet() {
@@ -131,9 +144,11 @@ var _default = ({
131
144
  recordSetSize,
132
145
  maxMatches,
133
146
  matches,
134
- nonMatches
147
+ nonMatches,
148
+ nonMatchCount
135
149
  });
136
150
  const newDuplicateCount = duplicateCount + matchResult.duplicateCount;
151
+ const newNonMatchCount = nonMatchCount + matchResult.nonMatchCount;
137
152
  const {
138
153
  newMatches,
139
154
  newNonMatches
@@ -149,7 +164,9 @@ var _default = ({
149
164
  stopReason: 'maxMatches',
150
165
  nonMatches: newNonMatches,
151
166
  duplicateCount: newDuplicateCount,
152
- candidateCount: newCandidateCount
167
+ candidateCount: newCandidateCount,
168
+ nonMatchCount: newNonMatchCount,
169
+ conversionFailures: newConversionFailures
153
170
  });
154
171
  }
155
172
 
@@ -160,7 +177,9 @@ var _default = ({
160
177
  stopReason: 'maxCandidates',
161
178
  nonMatches: newNonMatches,
162
179
  duplicateCount: newDuplicateCount,
163
- candidateCount: newCandidateCount
180
+ candidateCount: newCandidateCount,
181
+ nonMatchCount: newNonMatchCount,
182
+ conversionFailures: newConversionFailures
164
183
  });
165
184
  }
166
185
 
@@ -169,7 +188,9 @@ var _default = ({
169
188
  matches: newMatches,
170
189
  candidateCount: newCandidateCount,
171
190
  nonMatches: newNonMatches,
172
- duplicateCount: newDuplicateCount
191
+ duplicateCount: newDuplicateCount,
192
+ nonMatchCount: newNonMatchCount,
193
+ conversionFailures: newConversionFailures
173
194
  });
174
195
  }
175
196
 
@@ -219,7 +240,7 @@ var _default = ({
219
240
  // - matchQuery (if returnQuery option is true)
220
241
  // we could have here also returnRecords/returnMatchRecords/returnNonMatchRecord options that could be turned false for not to return actual record data
221
242
  // matchStatus.status: boolean, true if matcher retrieved and handled all found candidate records, false if it did not
222
- // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries',empty string/undefined), reason for stopping retrieving or handling the candidate records
243
+ // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records
223
244
  // - only one stopReason is returned (if there would be several possible stopReasons, stopReason is picked in the above order)
224
245
  // - 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
225
246
 
@@ -230,12 +251,22 @@ var _default = ({
230
251
  stopReason,
231
252
  nonMatches,
232
253
  duplicateCount,
233
- candidateCount
254
+ candidateCount,
255
+ nonMatchCount,
256
+ conversionFailures
234
257
  }) {
235
- checkCounts(matches, nonMatches, candidateCount, duplicateCount);
236
- const matchStatus = getMatchState(state, stopReason); // add nonMatches to result only if returnNonMatches is 'true', otherwise nonMatches have not been gathered
258
+ const conversionFailureCount = conversionFailures.length;
259
+ checkCounts({
260
+ matches,
261
+ nonMatches,
262
+ candidateCount,
263
+ duplicateCount,
264
+ nonMatchCount,
265
+ conversionFailureCount
266
+ });
267
+ const matchStatus = getMatchState(state, stopReason, conversionFailureCount); // add nonMatches to result only if returnNonMatches is 'true', otherwise nonMatches have not been gathered
237
268
 
238
- const result = returnNonMatches ? {
269
+ const matchesResult = returnNonMatches ? {
239
270
  matches,
240
271
  matchStatus,
241
272
  nonMatches
@@ -243,15 +274,26 @@ var _default = ({
243
274
  matches,
244
275
  matchStatus
245
276
  };
277
+ const result = returnFailures ? { ...matchesResult,
278
+ conversionFailures
279
+ } : matchesResult;
280
+ debugData(`ReturnFailures ${returnFailures}`);
246
281
  debugData(`${JSON.stringify(result)}`);
247
- return result; // we could have a nonMatchCount even if nonMatches won't be returned so that checkCounts would make sense
248
- // note that in cases where the matching has been stopped because of maxMatches checkCounts won't (in most cases) match
282
+ return result; // note that in cases where the matching has been stopped because of maxMatches checkCounts won't (in most cases) match
249
283
 
250
- function checkCounts(matches, nonMatches, candidateCount, duplicateCount) {
284
+ function checkCounts({
285
+ matches,
286
+ nonMatches,
287
+ candidateCount,
288
+ duplicateCount,
289
+ nonMatchCount,
290
+ conversionFailureCount
291
+ }) {
251
292
  const matchCount = matches.length;
252
- const nonMatchCount = nonMatches.length;
253
- const totalHandled = matchCount + nonMatchCount + duplicateCount;
254
- debug(`candidateCount: ${candidateCount}, matches: ${matchCount}, nonMatches: ${nonMatchCount}, duplicateCount: ${duplicateCount}`);
293
+ debugData(`Return nonMatches: ${returnNonMatches}`);
294
+ const chosenNonMatchCount = returnNonMatches ? nonMatches.length : nonMatchCount;
295
+ const totalHandled = matchCount + chosenNonMatchCount + duplicateCount;
296
+ debug(`candidateCount: ${candidateCount}, matches: ${matchCount}, nonMatches: ${chosenNonMatchCount}, duplicateCount: ${duplicateCount}, conversionFailureCount: ${conversionFailureCount}`);
255
297
  debug(`We got result for ${totalHandled} / ${candidateCount} retrieved candidates`);
256
298
 
257
299
  if (totalHandled !== candidateCount) {
@@ -262,15 +304,22 @@ var _default = ({
262
304
  return;
263
305
  }
264
306
 
265
- function getMatchState(state, stopReason) {
266
- debug(`Queries left ${state.queriesLeft}, Searches for current query left: ${state.resultSetOffset >= state.totalRecords}, non-retrieved records: ${state.totalRecords - state.queryCandidateCounter}, maxedQueries (${state.maxedQueries.length}): ${state.maxedQueries}`);
307
+ function getMatchState(state, stopReason, conversionFailuresCount) {
308
+ debugData(`${JSON.stringify(state)}`);
309
+ debug(`We had ${conversionFailuresCount} retrieved candidates that could not be converted.`);
310
+ 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}`);
267
311
  debugData(`StopReason: <${stopReason}>`);
268
- const nonRetrieved = state.resultSetOffset >= state.totalRecords ? state.totalRecords - state.queryCandidateCounter : 0;
269
-
270
- if (state.queriesLeft > 0 || nonRetrieved > 0 || state.maxedQueries.length > 0) {
271
- const maxedQueriesStopReason = state.maxedQueries.length > 0 ? 'maxedQueries' : '';
272
- const newStopReason = stopReason === '' ? maxedQueriesStopReason : stopReason;
312
+ const searchesLeft = state.resultSetOffset && state.resultSetOffset <= state.totalRecords;
313
+ const nonRetrieved = searchesLeft ? state.totalRecords - state.queryCandidateCounter : 0;
314
+ debugData(`nonRetrieved: ${nonRetrieved}`); // matchStatus.stopReason: string ('maxMatches','maxCandidates','maxedQueries','conversionFailures', empty string/undefined), reason for stopping retrieving or handling the candidate records
315
+ // 'maxMatches' and 'maxCandidates' are in stopReason, 'maxedQueries' and 'conversionFailures' are created here
316
+
317
+ if (state.queriesLeft > 0 || nonRetrieved > 0 || state.maxedQueries.length > 0 || conversionFailureCount > 0) {
318
+ const maxedQueriesStopReason = state.maxedQueries.length > 0 ? 'maxedQueries' : undefined;
319
+ const conversionFailuresStopReason = conversionFailureCount > 0 ? 'conversionFailures' : undefined;
320
+ const newStopReason = stopReason === '' || stopReason === undefined ? maxedQueriesStopReason || conversionFailuresStopReason : stopReason;
273
321
  debugData(`MaxedQueriesStopReason: <${maxedQueriesStopReason}>`);
322
+ debugData(`ConversionFailureStopReason <${conversionFailuresStopReason}>`);
274
323
  debugData(`NewStopReason: <${newStopReason}>`);
275
324
  debug(`Match status: false`);
276
325
  return {
@@ -296,12 +345,14 @@ var _default = ({
296
345
  recordMatches = [],
297
346
  recordNonMatches = [],
298
347
  recordCount = 0,
299
- recordDuplicateCount = 0
348
+ recordDuplicateCount = 0,
349
+ recordNonMatchCount = 0
300
350
  }) {
301
351
  // recordSetSize : total amount of records in the current record set
302
352
  // recordCount : amount of records from the current record set that have been handled
303
353
  // maxMatches : setting for maximum amount found by current matcher job before the matcher job is stopped
304
354
  // recordDuplicateCount : amount of records from the current record set that are already included in matches/nonMatches results
355
+ // recordNonMatchCount: amount of records from the current record set that are nonMatches (only is returnNonMatches setting is false)
305
356
  // records : non-handled records in the current record set
306
357
  // matches : found matches in the current matcher job
307
358
  // recordMatches : found matches in the current record set
@@ -331,15 +382,17 @@ var _default = ({
331
382
  recordMatches,
332
383
  recordCount: newRecordCount,
333
384
  recordNonMatches,
334
- recordDuplicateCount: recordDuplicateCount + 1
385
+ recordDuplicateCount: recordDuplicateCount + 1,
386
+ recordNonMatchCount
335
387
  });
336
388
  }
337
389
 
338
- debug(`No more candidates, record set (${recordCount}/${recordSetSize}) done, ${recordMatches.length} matches found, ${recordDuplicateCount} candidates already handled${returnNonMatches ? `, ${recordNonMatches.length} nonMatches found.` : '.'}`);
390
+ debug(`No more candidates, record set (${recordCount}/${recordSetSize}) done, ${recordMatches.length} matches found, ${recordDuplicateCount} candidates already handled, ${returnNonMatches ? `${recordNonMatches.length}` : `${recordNonMatchCount}`} nonMatches found.`);
339
391
  return {
340
392
  matches: recordMatches,
341
393
  nonMatches: returnNonMatches ? recordNonMatches : [],
342
- duplicateCount: recordDuplicateCount
394
+ duplicateCount: recordDuplicateCount,
395
+ nonMatchCount: recordNonMatchCount
343
396
  };
344
397
 
345
398
  function handleDetectionResult(detectionResult, candidateId, candidateRecord) {
@@ -367,6 +420,8 @@ var _default = ({
367
420
  return handleRecordMatch(detectionResult.match, newMatch);
368
421
  }
369
422
 
423
+ const newRecordNonMatchCount = recordNonMatchCount + 1;
424
+ debugData(`- Total nonMatches after this detection: ${newRecordNonMatchCount}`);
370
425
  return iterateRecords({
371
426
  records: records.slice(1),
372
427
  recordSetSize,
@@ -375,19 +430,23 @@ var _default = ({
375
430
  recordMatches,
376
431
  recordCount: newRecordCount,
377
432
  recordNonMatches,
378
- recordDuplicateCount
433
+ recordDuplicateCount,
434
+ recordNonMatchCount: newRecordNonMatchCount
379
435
  });
380
436
  }
381
437
 
382
438
  function handleRecordMatch(isMatch, newMatch) {
383
439
  const newRecordMatches = isMatch ? recordMatches.concat(newMatch) : recordMatches;
384
440
  const newRecordNonMatches = isMatch ? recordNonMatches : recordNonMatches.concat(newMatch);
441
+ const newRecordNonMatchCount = isMatch ? recordNonMatchCount : recordNonMatchCount + 1;
385
442
  debugData(`- Total matches after this detection: ${matches.concat(newRecordMatches).length} (max: ${maxMatches})`); // eslint-disable-next-line functional/no-conditional-statement
386
443
 
387
444
  if (returnNonMatches) {
388
445
  debugData(`- Total nonMatches after this detection: ${nonMatches.concat(newRecordNonMatches).length}`);
389
446
  }
390
447
 
448
+ debugData(`- Total nonMatchCount after this detection: ${recordNonMatchCount}`);
449
+
391
450
  if (maxMatchesFound({
392
451
  matches: matches.concat(newRecordMatches),
393
452
  maxMatches
@@ -396,7 +455,8 @@ var _default = ({
396
455
  return {
397
456
  matches: newRecordMatches,
398
457
  nonMatches: returnNonMatches ? newRecordNonMatches : [],
399
- duplicateCount: recordDuplicateCount
458
+ duplicateCount: recordDuplicateCount,
459
+ nonMatchCount: newRecordNonMatchCount
400
460
  };
401
461
  }
402
462
 
@@ -408,7 +468,8 @@ var _default = ({
408
468
  recordMatches: newRecordMatches,
409
469
  recordCount: newRecordCount,
410
470
  recordNonMatches: returnNonMatches ? newRecordNonMatches : [],
411
- duplicateCount: recordDuplicateCount
471
+ duplicateCount: recordDuplicateCount,
472
+ recordNonMatchCount: newRecordNonMatchCount
412
473
  });
413
474
  }
414
475
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.js"],"names":["detection","detectionOptions","search","searchOptions","maxMatches","maxCandidates","returnStrategy","returnQuery","returnNonMatches","debug","debugData","extend","JSON","stringify","detect","record","iterate","initialState","matches","candidateCount","nonMatches","duplicateCount","records","state","length","recordSetSize","newCandidateCount","handleRecordSet","queriesLeft","searchCounter","query","returnResult","stopReason","matchResult","iterateRecords","newDuplicateCount","newMatches","newNonMatches","handleMatchResult","maxMatchesFound","maxCandidatesRetrieved","concat","addQuery","map","match","matchQuery","checkCounts","matchStatus","getMatchState","result","matchCount","nonMatchCount","totalHandled","resultSetOffset","totalRecords","queryCandidateCounter","maxedQueries","nonRetrieved","maxedQueriesStopReason","newStopReason","status","recordMatches","recordNonMatches","recordCount","recordDuplicateCount","candidate","newRecordCount","candidateNotInMatches","candidateRecord","id","candidateId","detectionResult","handleDetectionResult","slice","strategy","treshold","probability","strategyResult","newMatch","handleRecordMatch","isMatch","newRecordMatches","newRecordNonMatches","newCandidateId","find"],"mappings":"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","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\nexport {candidateSearch, matchDetection};\n\nexport default ({detection: detectionOptions, search: searchOptions, maxMatches = 1, maxCandidates = 25, returnStrategy = false, returnQuery = false, returnNonMatches = 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\n const detect = createDetectionInterface(detectionOptions, returnStrategy);\n\n return record => {\n const search = createSearchInterface({...searchOptions, record});\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}) {\n debugData(`Starting next matcher iteration.`);\n const {records, ...state} = await search(initialState);\n\n debugData(`Current state: ${JSON.stringify(state)}, matches: ${matches.length}, candidateCount: ${candidateCount}, nonMatches: ${nonMatches.length}`);\n const recordSetSize = records.length;\n const newCandidateCount = candidateCount + recordSetSize;\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, duplicateCount});\n }\n\n debug(`No (more) candidate records to check, no more queries left, matches: ${matches.length}`);\n return returnResult({matches, state, stopReason: '', nonMatches, candidateCount: newCandidateCount, duplicateCount});\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});\n const newDuplicateCount = duplicateCount + matchResult.duplicateCount;\n const {newMatches, newNonMatches} = handleMatchResult(matchResult, matches, nonMatches);\n\n if (maxMatchesFound({matches: newMatches, maxMatches})) {\n return returnResult({matches: newMatches, state, stopReason: 'maxMatches', nonMatches: newNonMatches, duplicateCount: newDuplicateCount, candidateCount: newCandidateCount});\n }\n\n if (maxCandidatesRetrieved(newCandidateCount, maxCandidates)) {\n return returnResult({matches: newMatches, state, stopReason: 'maxCandidates', nonMatches: newNonMatches, duplicateCount: newDuplicateCount, candidateCount: newCandidateCount});\n }\n\n return iterate({initialState: state, matches: newMatches, candidateCount: newCandidateCount, nonMatches: newNonMatches, duplicateCount: newDuplicateCount});\n }\n\n function handleMatchResult(matchResult, matches, nonMatches) {\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\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 return {newMatches, newNonMatches};\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\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',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}) {\n checkCounts(matches, nonMatches, candidateCount, duplicateCount);\n const matchStatus = getMatchState(state, stopReason);\n // add nonMatches to result only if returnNonMatches is 'true', otherwise nonMatches have not been gathered\n const result = returnNonMatches ? {matches, matchStatus, nonMatches} : {matches, matchStatus};\n debugData(`${JSON.stringify(result)}`);\n return result;\n\n // we could have a nonMatchCount even if nonMatches won't be returned so that checkCounts would make sense\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) {\n const matchCount = matches.length;\n const nonMatchCount = nonMatches.length;\n const totalHandled = matchCount + nonMatchCount + duplicateCount;\n debug(`candidateCount: ${candidateCount}, matches: ${matchCount}, nonMatches: ${nonMatchCount}, duplicateCount: ${duplicateCount}`);\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 function getMatchState(state, stopReason) {\n debug(`Queries left ${state.queriesLeft}, Searches for current query left: ${state.resultSetOffset >= state.totalRecords}, non-retrieved records: ${state.totalRecords - state.queryCandidateCounter}, maxedQueries (${state.maxedQueries.length}): ${state.maxedQueries}`);\n debugData(`StopReason: <${stopReason}>`);\n\n const nonRetrieved = state.resultSetOffset >= state.totalRecords ? state.totalRecords - state.queryCandidateCounter : 0;\n\n if (state.queriesLeft > 0 || nonRetrieved > 0 || state.maxedQueries.length > 0) {\n const maxedQueriesStopReason = state.maxedQueries.length > 0 ? 'maxedQueries' : '';\n const newStopReason = stopReason === '' ? maxedQueriesStopReason : stopReason;\n debugData(`MaxedQueriesStopReason: <${maxedQueriesStopReason}>`);\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 function iterateRecords({records, recordSetSize, maxMatches, matches = [], nonMatches = [], recordMatches = [], recordNonMatches = [], recordCount = 0, recordDuplicateCount = 0}) {\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\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\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 if (candidate) {\n\n if (candidateNotInMatches(matches.concat(nonMatches), candidate)) {\n const {record: candidateRecord, id: candidateId} = candidate;\n debug(`Running matchDetection for record ${candidateId} (${newRecordCount}/${recordSetSize})`);\n const detectionResult = detect(record, candidateRecord);\n return handleDetectionResult(detectionResult, candidateId, candidateRecord);\n }\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount: recordDuplicateCount + 1});\n }\n\n debug(`No more candidates, record set (${recordCount}/${recordSetSize}) done, ${recordMatches.length} matches found, ${recordDuplicateCount} candidates already handled${returnNonMatches ? `, ${recordNonMatches.length} nonMatches found.` : '.'}`);\n return {matches: recordMatches, nonMatches: returnNonMatches ? recordNonMatches : [], duplicateCount: recordDuplicateCount};\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 return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount});\n }\n\n function handleRecordMatch(isMatch, newMatch) {\n const newRecordMatches = isMatch ? recordMatches.concat(newMatch) : recordMatches;\n const newRecordNonMatches = isMatch ? recordNonMatches : recordNonMatches.concat(newMatch);\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\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};\n }\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches: newRecordMatches, recordCount: newRecordCount, recordNonMatches: returnNonMatches ? newRecordNonMatches : [], duplicateCount: recordDuplicateCount});\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"],"file":"index.js"}
1
+ {"version":3,"sources":["../src/index.js"],"names":["detection","detectionOptions","search","searchOptions","maxMatches","maxCandidates","returnStrategy","returnQuery","returnNonMatches","returnFailures","debug","debugData","extend","JSON","stringify","detect","record","iterate","initialState","matches","candidateCount","nonMatches","duplicateCount","nonMatchCount","conversionFailures","records","failures","state","length","recordSetSize","failureSetSize","newCandidateCount","newConversionFailures","concat","handleRecordSet","queriesLeft","searchCounter","query","returnResult","stopReason","matchResult","iterateRecords","newDuplicateCount","newNonMatchCount","newMatches","newNonMatches","handleMatchResult","maxMatchesFound","maxCandidatesRetrieved","addQuery","map","match","matchQuery","conversionFailureCount","checkCounts","matchStatus","getMatchState","matchesResult","result","matchCount","chosenNonMatchCount","totalHandled","conversionFailuresCount","resultSetOffset","totalRecords","queryCandidateCounter","maxedQueries","searchesLeft","nonRetrieved","maxedQueriesStopReason","undefined","conversionFailuresStopReason","newStopReason","status","recordMatches","recordNonMatches","recordCount","recordDuplicateCount","recordNonMatchCount","candidate","newRecordCount","candidateNotInMatches","candidateRecord","id","candidateId","detectionResult","handleDetectionResult","slice","strategy","treshold","probability","strategyResult","newMatch","handleRecordMatch","newRecordNonMatchCount","isMatch","newRecordMatches","newRecordNonMatches","newCandidateId","find"],"mappings":"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","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\nexport {candidateSearch, matchDetection};\n\nexport default ({detection: detectionOptions, search: searchOptions, maxMatches = 1, maxCandidates = 25, returnStrategy = false, returnQuery = false, returnNonMatches = false, returnFailures}) => {\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 = []}) {\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}`);\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});\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});\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} = handleMatchResult(matchResult, matches, nonMatches);\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});\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});\n }\n\n return iterate({initialState: state, matches: newMatches, candidateCount: newCandidateCount, nonMatches: newNonMatches, duplicateCount: newDuplicateCount, nonMatchCount: newNonMatchCount, conversionFailures: newConversionFailures});\n }\n\n function handleMatchResult(matchResult, matches, nonMatches) {\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\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 return {newMatches, newNonMatches};\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\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}) {\n const conversionFailureCount = conversionFailures.length;\n checkCounts({matches, nonMatches, candidateCount, duplicateCount, nonMatchCount, conversionFailureCount});\n const matchStatus = getMatchState(state, stopReason, conversionFailureCount);\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 result = returnFailures ? {...matchesResult, conversionFailures} : 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}) {\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}`);\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 function getMatchState(state, stopReason, conversionFailuresCount) {\n debugData(`${JSON.stringify(state)}`);\n debug(`We had ${conversionFailuresCount} retrieved candidates that could not be converted.`);\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' and 'conversionFailures' are created here\n\n if (state.queriesLeft > 0 || nonRetrieved > 0 || state.maxedQueries.length > 0 || conversionFailureCount > 0) {\n const maxedQueriesStopReason = state.maxedQueries.length > 0 ? 'maxedQueries' : undefined;\n const conversionFailuresStopReason = conversionFailureCount > 0 ? 'conversionFailures' : undefined;\n const newStopReason = stopReason === '' || stopReason === undefined ? maxedQueriesStopReason || conversionFailuresStopReason : stopReason;\n debugData(`MaxedQueriesStopReason: <${maxedQueriesStopReason}>`);\n debugData(`ConversionFailureStopReason <${conversionFailuresStopReason}>`);\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 function iterateRecords({records, recordSetSize, maxMatches, matches = [], nonMatches = [], recordMatches = [], recordNonMatches = [], recordCount = 0, recordDuplicateCount = 0, recordNonMatchCount = 0}) {\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\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 if (candidate) {\n\n if (candidateNotInMatches(matches.concat(nonMatches), candidate)) {\n const {record: candidateRecord, id: candidateId} = candidate;\n debug(`Running matchDetection for record ${candidateId} (${newRecordCount}/${recordSetSize})`);\n const detectionResult = detect(record, candidateRecord);\n return handleDetectionResult(detectionResult, candidateId, candidateRecord);\n }\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches, recordCount: newRecordCount, recordNonMatches, recordDuplicateCount: recordDuplicateCount + 1, recordNonMatchCount});\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};\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});\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};\n }\n\n return iterateRecords({records: records.slice(1), recordSetSize, maxMatches, matches, recordMatches: newRecordMatches, recordCount: newRecordCount, recordNonMatches: returnNonMatches ? newRecordNonMatches : [], duplicateCount: recordDuplicateCount, recordNonMatchCount: newRecordNonMatchCount});\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"],"file":"index.js"}
@@ -62,7 +62,8 @@ describe('INDEX', () => {
62
62
  options,
63
63
  enabled = true,
64
64
  expectedMatchStatus,
65
- expectedStopReason
65
+ expectedStopReason,
66
+ expectedFailures
66
67
  }) {
67
68
  if (!enabled) {
68
69
  debug(`Disabled test!`);
@@ -78,15 +79,20 @@ describe('INDEX', () => {
78
79
  const {
79
80
  matches,
80
81
  matchStatus,
81
- nonMatches
82
+ nonMatches,
83
+ conversionFailures
82
84
  } = await match(record);
83
- debugData(`${matches.length}, ${matchStatus.status}/${matchStatus.stopReason}, ${nonMatches ? nonMatches.length : nonMatches}`);
85
+ debugData(`Matches: ${matches.length}, Status: ${matchStatus.status}/${matchStatus.stopReason}, NonMatches: ${nonMatches ? nonMatches.length : 'not returned'}, ConversionFailures: ${conversionFailures ? conversionFailures.length : 'not returned'}`);
86
+ (0, _chai.expect)(matchStatus.status).to.eql(expectedMatchStatus);
87
+ (0, _chai.expect)(matchStatus.stopReason).to.eql(expectedStopReason);
84
88
  const formattedMatchResult = formatRecordResults(matches);
85
89
  (0, _chai.expect)(formattedMatchResult).to.eql(expectedMatches);
86
90
  const formattedNonMatchResult = formatRecordResults(nonMatches);
87
- (0, _chai.expect)(formattedNonMatchResult).to.eql(expectedNonMatches);
88
- (0, _chai.expect)(matchStatus.status).to.eql(expectedMatchStatus);
89
- (0, _chai.expect)(matchStatus.stopReason).to.eql(expectedStopReason);
91
+ (0, _chai.expect)(formattedNonMatchResult).to.eql(expectedNonMatches); // eslint-disable-next-line functional/no-conditional-statement
92
+
93
+ if (expectedFailures) {
94
+ (0, _chai.expect)(conversionFailures).to.eql(expectedFailures);
95
+ }
90
96
 
91
97
  function formatOptions() {
92
98
  const contextFeatures = _.matchDetection.features[options.detection.strategy.type];
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.spec.js"],"names":["debug","debugData","extend","describe","callback","path","__dirname","recurse","fixura","reader","READERS","JSON","getFixture","options","enabled","expectedMatchStatus","expectedStopReason","record","MarcRecord","subfieldValues","expectedMatches","expectedNonMatches","match","formatOptions","matches","matchStatus","nonMatches","length","status","stopReason","formattedMatchResult","formatRecordResults","to","eql","formattedNonMatchResult","contextFeatures","matchDetection","features","detection","strategy","type","search","detect","map","v","stringify","candidate","formatCandidate","id","newId","newRecord","toObject"],"mappings":"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","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 {expect} from 'chai';\nimport {READERS} from '@natlibfi/fixura';\nimport generateTests from '@natlibfi/fixugen-http-client';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport createMatchInterface, {matchDetection} from '.';\nimport createDebugLogger from 'debug';\n\nconst debug = createDebugLogger('@natlibfi/melinda-record-matching:index:test');\nconst debugData = debug.extend('data');\n\ndescribe('INDEX', () => {\n generateTests({\n callback,\n path: [__dirname, '..', 'test-fixtures', 'index'],\n recurse: false,\n fixura: {\n reader: READERS.JSON\n }\n });\n\n async function callback({getFixture, options, enabled = true, expectedMatchStatus, expectedStopReason}) {\n\n if (!enabled) {\n debug(`Disabled test!`);\n return;\n }\n\n const record = new MarcRecord(getFixture('inputRecord.json'), {subfieldValues: false});\n const expectedMatches = getFixture('expectedMatches.json');\n const expectedNonMatches = getFixture('expectedNonMatches.json') || [];\n\n\n const match = createMatchInterface(formatOptions());\n const {matches, matchStatus, nonMatches} = await match(record);\n debugData(`${matches.length}, ${matchStatus.status}/${matchStatus.stopReason}, ${nonMatches ? nonMatches.length : nonMatches}`);\n\n const formattedMatchResult = formatRecordResults(matches);\n expect(formattedMatchResult).to.eql(expectedMatches);\n\n const formattedNonMatchResult = formatRecordResults(nonMatches);\n expect(formattedNonMatchResult).to.eql(expectedNonMatches);\n\n expect(matchStatus.status).to.eql(expectedMatchStatus);\n expect(matchStatus.stopReason).to.eql(expectedStopReason);\n\n\n function formatOptions() {\n const contextFeatures = matchDetection.features[options.detection.strategy.type];\n\n return {\n ...options,\n search: {\n ...options.search\n },\n detection: {\n ...options.detect,\n strategy: options.detection.strategy.features.map(v => contextFeatures[v]())\n }\n };\n }\n\n function formatRecordResults(matches) {\n if (matches) {\n debugData(JSON.stringify(matches));\n return matches.map((match) => ({\n ...match,\n candidate: formatCandidate(match.candidate)\n }));\n }\n return [];\n }\n\n // Format candidate to remove validationOptions from record\n function formatCandidate({id, record}) {\n const newId = id;\n const newRecord = record;\n return {\n id: newId,\n record: newRecord.toObject()\n };\n }\n\n\n }\n\n});\n"],"file":"index.spec.js"}
1
+ {"version":3,"sources":["../src/index.spec.js"],"names":["debug","debugData","extend","describe","callback","path","__dirname","recurse","fixura","reader","READERS","JSON","getFixture","options","enabled","expectedMatchStatus","expectedStopReason","expectedFailures","record","MarcRecord","subfieldValues","expectedMatches","expectedNonMatches","match","formatOptions","matches","matchStatus","nonMatches","conversionFailures","length","status","stopReason","to","eql","formattedMatchResult","formatRecordResults","formattedNonMatchResult","contextFeatures","matchDetection","features","detection","strategy","type","search","detect","map","v","stringify","candidate","formatCandidate","id","newId","newRecord","toObject"],"mappings":"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","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 {expect} from 'chai';\nimport {READERS} from '@natlibfi/fixura';\nimport generateTests from '@natlibfi/fixugen-http-client';\nimport {MarcRecord} from '@natlibfi/marc-record';\nimport createMatchInterface, {matchDetection} from '.';\nimport createDebugLogger from 'debug';\n\nconst debug = createDebugLogger('@natlibfi/melinda-record-matching:index:test');\nconst debugData = debug.extend('data');\n\ndescribe('INDEX', () => {\n generateTests({\n callback,\n path: [__dirname, '..', 'test-fixtures', 'index'],\n recurse: false,\n fixura: {\n reader: READERS.JSON\n }\n });\n\n async function callback({getFixture, options, enabled = true, expectedMatchStatus, expectedStopReason, expectedFailures}) {\n\n if (!enabled) {\n debug(`Disabled test!`);\n return;\n }\n\n const record = new MarcRecord(getFixture('inputRecord.json'), {subfieldValues: false});\n const expectedMatches = getFixture('expectedMatches.json');\n const expectedNonMatches = getFixture('expectedNonMatches.json') || [];\n\n\n const match = createMatchInterface(formatOptions());\n const {matches, matchStatus, nonMatches, conversionFailures} = await match(record);\n debugData(`Matches: ${matches.length}, Status: ${matchStatus.status}/${matchStatus.stopReason}, NonMatches: ${nonMatches ? nonMatches.length : 'not returned'}, ConversionFailures: ${conversionFailures ? conversionFailures.length : 'not returned'}`);\n\n expect(matchStatus.status).to.eql(expectedMatchStatus);\n expect(matchStatus.stopReason).to.eql(expectedStopReason);\n\n const formattedMatchResult = formatRecordResults(matches);\n expect(formattedMatchResult).to.eql(expectedMatches);\n\n const formattedNonMatchResult = formatRecordResults(nonMatches);\n expect(formattedNonMatchResult).to.eql(expectedNonMatches);\n\n // eslint-disable-next-line functional/no-conditional-statement\n if (expectedFailures) {\n expect(conversionFailures).to.eql(expectedFailures);\n }\n\n function formatOptions() {\n const contextFeatures = matchDetection.features[options.detection.strategy.type];\n\n return {\n ...options,\n search: {\n ...options.search\n },\n detection: {\n ...options.detect,\n strategy: options.detection.strategy.features.map(v => contextFeatures[v]())\n }\n };\n }\n\n function formatRecordResults(matches) {\n if (matches) {\n debugData(JSON.stringify(matches));\n return matches.map((match) => ({\n ...match,\n candidate: formatCandidate(match.candidate)\n }));\n }\n return [];\n }\n\n // Format candidate to remove validationOptions from record\n function formatCandidate({id, record}) {\n const newId = id;\n const newRecord = record;\n return {\n id: newId,\n record: newRecord.toObject()\n };\n }\n\n\n }\n\n});\n"],"file":"index.spec.js"}
package/package.json CHANGED
@@ -14,7 +14,7 @@
14
14
  "url": "git@github.com:natlibfi/melinda-record-matching-js.git"
15
15
  },
16
16
  "license": "LGPL-3.0+",
17
- "version": "2.1.0-alpha.1",
17
+ "version": "2.2.0-alpha.1",
18
18
  "main": "./dist/index.js",
19
19
  "engines": {
20
20
  "node": ">=14"
@@ -37,31 +37,32 @@
37
37
  "dependencies": {
38
38
  "@natlibfi/marc-record": "^7.0.0",
39
39
  "@natlibfi/marc-record-serializers": "^8.1.0",
40
- "@natlibfi/sru-client": "^5.0.0",
41
- "debug": "^4.3.3",
42
- "moment": "^2.29.1",
40
+ "@natlibfi/melinda-commons": "^12.0.3",
41
+ "@natlibfi/sru-client": "^5.0.1",
42
+ "debug": "^4.3.4",
43
+ "moment": "^2.29.2",
43
44
  "natural": "^5.1.13",
44
45
  "uuid": "^8.3.2",
45
- "winston": "^3.3.4"
46
+ "winston": "^3.7.2"
46
47
  },
47
48
  "devDependencies": {
48
- "@babel/cli": "^7.16.7",
49
- "@babel/core": "^7.16.7",
50
- "@babel/eslint-parser": "^7.16.5",
51
- "@babel/node": "^7.16.7",
52
- "@babel/preset-env": "^7.16.7",
53
- "@babel/register": "^7.16.7",
49
+ "@babel/cli": "^7.17.6",
50
+ "@babel/core": "^7.17.9",
51
+ "@babel/eslint-parser": "^7.17.0",
52
+ "@babel/node": "^7.16.8",
53
+ "@babel/preset-env": "^7.16.11",
54
+ "@babel/register": "^7.17.7",
54
55
  "@natlibfi/eslint-config-melinda-backend": "^2.0.0",
55
56
  "@natlibfi/fixugen": "^1.0.2",
56
- "@natlibfi/fixugen-http-client": "^1.1.3",
57
+ "@natlibfi/fixugen-http-client": "^2.0.1",
57
58
  "@natlibfi/fixura": "^2.2.1",
58
59
  "babel-plugin-istanbul": "^6.1.1",
59
60
  "babel-plugin-rewire": "^1.2.0",
60
- "chai": "^4.3.4",
61
+ "chai": "^4.3.6",
61
62
  "chai-as-promised": "^7.1.1",
62
63
  "cross-env": "^7.0.3",
63
- "eslint": "^8.6.0",
64
- "mocha": "^9.1.3",
64
+ "eslint": "^8.13.0",
65
+ "mocha": "^9.2.2",
65
66
  "nodemon": "^2.0.15",
66
67
  "nyc": "^15.1.0"
67
68
  },