Member Junction
    Preparing search index...

    Modernized duplicate record detection engine.

    Supports:

    • List-based batch detection (getDuplicateRecords)
    • View/filter/full-entity batch detection (vector-first approach)
    • Single-record duplicate check (CheckSingleRecord)
    • Hybrid search via RRF when vector DB supports it
    • Optional post-retrieval reranking via MJ's BaseReranker
    • Configurable topK, thresholds, and progress reporting

    Hierarchy (View Summary)

    Index

    Constructors

    • Parameters

      • Optionalprovider: IMetadataProvider

        Optional metadata provider to bind this instance (and all of its metadata/view operations) to. Server-side callers servicing per-request connections MUST pass their request-scoped provider (e.g. this.ProviderToUse from a BaseEntity subclass) — relying on the global default silently uses the wrong connection in multi-provider scenarios. Falls back to the global default provider when omitted.

      Returns DuplicateRecordDetector

    Properties

    _currentUser: UserInfo
    _metadata: Metadata
    _runView: RunView

    Accessors

    • get CurrentUser(): UserInfo

      Returns UserInfo

    • set CurrentUser(user: UserInfo): void

      Parameters

      Returns void

    • get Metadata(): IMetadataProvider

      Provider-aware metadata access: returns the explicit provider when one was supplied (constructor or Provider setter), otherwise the global default. All metadata operations in this class hierarchy go through this getter so a bound instance never leaks onto the global provider.

      Returns IMetadataProvider

    • get Provider(): IMetadataProvider

      Optional metadata provider override. Pass the provider to the constructor (preferred) or set instance.Provider = providerToUse before invoking helper methods in multi-provider contexts. Setting it rebinds the internal RunView instance so view execution rides the same provider. Falls back to the global default when unset.

      Returns IMetadataProvider

    • set Provider(value: IMetadataProvider): void

      Parameters

      Returns void

    • get RunView(): RunView

      Returns RunView

    Methods

    • Write the LLM verdict + run id onto a single match row's generated columns. The recommendation / confidence / reasoning are taken from THIS candidate's own verdict (judged independently), so a false-positive candidate reads NotDuplicate even when another candidate in the same set is a confident Merge. Falls back to the set-level summary only when the reasoner returned no per-candidate verdict for this record. The proposed survivor + field map stay set-level (they describe the merge of the set's true duplicates).

      Parameters

      Returns void

    • Builds a SQL filter from composite keys. Values are sanitized to prevent SQL injection.

      Parameters

      Returns string

    • Returns true when PageRecordsByEntityID can serve the given entity via keyset (seek) pagination — i.e. the entity has a single-column PK on a comparable type. Callers iterating large tables should consult this and pass AfterKey when true.

      Parameters

      • entityID: string | number

      Returns boolean

    • Remove matches whose target record no longer exists in the source entity.

      Vector indexes (e.g. Pinecone) retain embeddings keyed by each record's composite key via a deterministic vector ID. When records are deleted — or re-seeded with new primary keys — their old vectors linger as "ghosts". A nearest-neighbour query then happily returns those ghosts, often the record's OWN former vector (identical name, ~0.98 score), which to a user looks exactly like a record matching itself. The per-record self-match filter can't catch these because the ghost carries the OLD id.

      We verify every distinct match key for the batch against the live table in a single batched query and drop any that don't resolve. Single-column primary keys only — the same assumption the rest of this engine makes.

      Mutates queryResults in place.

      Parameters

      • queryResults: RecordQueryResult[]
      • entityInfo: EntityInfo

      Returns Promise<void>

    • Populate a candidate's composite key from a vector match's RecordID, tolerant of the two formats different vector providers emit:

      • Concatenated ("ID|", or "F1|v1||F2|v2" for composite PKs) — e.g. providers that stored the full key. Parsed via CompositeKey.LoadFromConcatenatedString.
      • Bare primary-key value ("") — what the in-process SimpleVectorServiceProvider returns, since it stores MJ: Entity Record Documents.RecordID as the raw PK value. For this form we rebuild the key using the source record's PK field name(s).

      Getting this wrong leaves KeyValuePairs empty (the bare value has no field delimiter, so LoadFromConcatenatedString no-ops), which silently breaks self-match filtering, candidate field-delta loading (the reasoner sees an empty candidate), and MatchRecordID persistence.

      Parameters

      Returns void

    • Return the set of primary key values (normalized for case-insensitive UUID comparison) that actually exist in the entity, for the given candidate IDs. Batches the IN-list to stay within reasonable query sizes.

      Parameters

      • entityInfo: EntityInfo
      • pkField: string
      • ids: string[]

      Returns Promise<Set<string>>

    • Load record IDs directly from the entity, optionally filtered. Uses Fields: ['ID'] and ResultType: 'simple' for efficiency.

      Parameters

      Returns Promise<string[]>

    • Query the vector DB for duplicates of each record, with concurrency control.

      Creates one async task per record, then executes them via RunWithConcurrency with the specified concurrency limit. Each task embeds and queries a single record against the vector index.

      Supports hybrid search (vector + keyword) with RRF fusion when the vector DB provider supports it (checked via SupportsHybridSearch).

      Post-query, results are:

      1. Parsed from raw vector matches into typed PotentialDuplicate objects
      2. Filtered to remove self-matches (same record as source)
      3. Filtered by the potential match threshold (from options or entity document)

      Parameters

      • records: BaseEntity<unknown>[]

        The source records to find duplicates for

      • vectors: number[][]

        Pre-computed embedding vectors, one per record (same index order)

      • templateTexts: string[]

        Rendered template texts for hybrid keyword search

      • entityDocument: MJEntityDocumentEntity

        The entity document providing thresholds and configuration

      • topK: number

        Number of nearest neighbors to retrieve per record

      • options: DuplicateDetectionOptions

        Detection options including threshold overrides

      • concurrency: number

        Max parallel vector queries

      Returns Promise<RecordQueryResult[]>

      One RecordQueryResult per input record

    • Extract a display label from a candidate's vector metadata snapshot, if present.

      Parameters

      • Optionalmetadata: Record<string, string>

      Returns string

    • Resolve a record's display label: prefer the name loaded from the record (via the delta builder), then a secondary fallback (e.g. a candidate's vector-metadata name), then the raw record-id key as a last resort. Guards against the loaded label itself being the record key (the engine's own fallback) so we still try the secondary source.

      Parameters

      • labels: Map<string, string>
      • recordID: string
      • fallback: string

      Returns string

    • Run LLM reasoning for one source record's matched set, ONCE, only when:

      1. the entity document has EnableLLMReasoning = true, AND
      2. the set is non-empty, AND
      3. the set's top MatchProbability >= the (non-null) ReasoningThreshold.

      Returns undefined in every other case — including when reasoning is disabled — so the surrounding persist/merge path stays byte-for-byte identical to the vector-only behavior. A failed reasoning call returns an output with Success = false (never throws), so one bad set never aborts the run.

      Parameters

      Returns Promise<SetReasoning>

    • Type Parameters

      Parameters

      • entityName: string
      • extraFilter: string

      Returns Promise<T>

    • Saving an Entity in any vector related package needs the CurrentUser property to be set on the entity So this is a simple wrapper to set it before saving

      Parameters

      Returns Promise<boolean>