What Is Deduplication?

Deduplication is the process of identifying entities that refer to the same real-world object but appear as separate records in your data, then merging them into a single canonical representation. This process resolves aliases, spelling variations, and formatting differences that occur when data comes from multiple sources. Key deduplication concepts: Canonical entities are the single, authoritative representation of a real-world object after merging all duplicate records. The canonical entity becomes the node that all relationships point to in your knowledge graph. Aliases are alternative names or identifiers for the same entity. For example, “APT29”, “Cozy Bear”, and “Midnight Blizzard” are all aliases for the same threat actor. Entity resolution is the broader process of determining when different records refer to the same entity, including the similarity calculation, duplicate detection, and merging steps. Similarity algorithms:
  • Jaro-Winkler measures string similarity with higher scores for shared prefixes, ideal for names with common beginnings
  • Levenshtein distance counts character edits needed to transform one string into another, good for catching typos and variations
Clustering groups related duplicates together using algorithms like Union-Find, ensuring that if A matches B and B matches C, all three are grouped together even if A and C don’t directly match.

Why Use Deduplication?

Data quality and consistency. Eliminate duplicate nodes that fragment relationships and create inconsistent query results across different names for the same entity. Accurate analytics and metrics. Get correct counts, centrality measures, and relationship analysis when entities aren’t artificially split across multiple nodes due to naming variations. Relationship consolidation. Merge scattered relationships onto single canonical entities, enabling complete analysis of connections and patterns that would be missed with fragmented data. Source integration. Seamlessly combine data from multiple feeds, systems, and databases where the same entities appear under different identifiers and naming conventions. Graph efficiency. Reduce graph size and improve query performance by eliminating redundant nodes while preserving all information through proper merging strategies. Provenance preservation. Maintain complete audit trails showing which source contributed each piece of information to the final canonical entity.

When To Use / When Not To Use

Use deduplication for:
  • Multi-source data integration where entities appear under different names or identifiers
  • Entity types prone to aliases and variations (organizations, people, products, geographic locations)
  • Knowledge graphs where relationship accuracy depends on entity consolidation
  • Data quality workflows requiring canonical entity management
  • Analytics requiring accurate entity counts and relationship metrics
  • Scenarios where the same real-world objects appear across multiple systems or databases
Do NOT use deduplication for:
  • Single-source data with consistent entity identifiers and naming conventions
  • High-throughput streaming scenarios where deduplication latency is unacceptable
  • Data with reliable primary keys where duplicates are impossible by design
  • Cases where entity variations should be preserved as separate nodes (different product versions, time-based entity states)
  • Simple exact-match scenarios where basic database constraints handle uniqueness
Be cautious with:
  • Large datasets where O(n²) pairwise comparison becomes computationally expensive
  • Fuzzy matching when deterministic primary keys (LEI, CVE-ID, ISIN) are available
  • Very low similarity thresholds that may merge genuinely different entities

Typical Workflow

The deduplication workflow follows a systematic process from detection through merging: 1. Detect → Use detect_duplicates() or DuplicateDetector to identify potential matches using multi-factor similarity scoring 2. Group → Apply clustering algorithms to collect transitively related duplicates into groups (A matches B, B matches C → group A,B,C) 3. Select Canonical → Choose representative entity for each group based on completeness, source authority, or confidence scores 4. Merge → Combine duplicate entities using strategies like keep_most_complete or merge_all while preserving provenance 5. Validate → Review merge results and adjust thresholds or strategies based on precision/recall analysis 6. Update Graph → Replace duplicate nodes with canonical entities and transfer all relationships This pipeline transforms fragmented multi-source data into clean, consolidated knowledge graphs ready for analytics and reasoning.

API Patterns: Functional vs Class-Based

Semantica provides both simple functional wrappers and comprehensive class APIs for different use cases: Functional wrappers for simple workflows:
  • detect_duplicates() — one-shot duplicate detection with minimal configuration
  • calculate_similarity() — compare two entities with detailed similarity breakdown
  • merge_entities() — convenience wrapper around merge_duplicates() for quick merging
Class APIs for complex workflows:
  • DuplicateDetector — configurable duplicate detection with clustering, incremental processing, and advanced similarity options
  • EntityMerger — sophisticated merging with multiple strategies, provenance tracking, and merge history
Usage guidelines:
  • Use merge_duplicates() when you have a raw collection of entities and need automatic duplicate detection
  • Use merge_entity_group() when you already know which entities are duplicates and just need to merge a pre-determined group
  • Don’t mix functional wrappers with class APIs in the same workflow—choose one approach and stick with it
The deduplication module detects duplicate entities across multi-source knowledge graphs using six complementary similarity algorithms — exact match, Levenshtein, Jaro-Winkler, cosine, property comparison, and vector embedding — then merges them into a single canonical entity while preserving full provenance. Use it to collapse alias clusters (e.g. “APT29”, “Cozy Bear”, “Midnight Blizzard”) before running graph analytics or conflict resolution.
Run deduplication after ingestion and before conflict resolution. Deduplication collapses duplicate nodes into one canonical entity. Conflict resolution then reconciles disagreeing property values on that canonical entity. The pipeline order matters: deduplicate first, then resolve conflicts, then validate with SHACL.

Finding your duplicates: the first scan

Start with detect_duplicates() for straightforward duplicate detection on smaller datasets. Point it at your entities and let the pairwise algorithm compare every pair using multiple similarity signals. Scaling consideration: For datasets of a few thousand nodes, this runs in seconds. The O(n²) pairwise comparison cost only becomes problematic above ten thousand entities—for larger sets, see the clustering section below.
The scores tell a clear story. “APT29” and “APT-29” score 0.89 — the hyphen is the only difference, producing strong string similarity signals. “Cozy Bear” and “The Dukes” score lower (0.61) because the names are completely dissimilar, but the property signal fires because both records carry "APT29" in their aliases list. “APT28” never appears in the results because it shares only the country field — not enough to cross the 0.6 threshold.

Understanding the candidate object

Each DuplicateCandidate carries the two entities, their similarity scores, and a detailed breakdown of which similarity algorithms contributed to the match. This provides full transparency for audit and threshold tuning:
The property component (0.94) is doing most of the work here. “Cozy Bear“‘s record carries aliases: ["APT29"], which creates an almost-definitive signal that these entities refer to the same threat actor. When you see a pattern like this — weak name similarity but strong property matching — you’re typically looking at a genuine alias relationship rather than a false positive.

Grouping duplicates before merging

For small datasets, you can merge candidate pairs directly. For larger graphs where the same entity might appear under six different names across twelve feeds, use duplicate grouping with Union-Find clustering. This ensures that if A matches B and B matches C, all three entities are grouped together even if A and C don’t directly meet the similarity threshold:
The group result shows the consolidation clearly: five separate nodes that should be one canonical entity. The representative field identifies the entity the merger will use as the base — typically the one with the most complete attribute set, in this case “APT29” from the MISP feed.

Merging: collapsing the group without losing data

Once you have identified duplicate groups, the merging process consolidates them into canonical entities. The keep_most_complete strategy selects the entity with the highest property count as the canonical node and enriches it with any missing fields from the other sources:
The five source entities are replaced by one canonical representation. Every relationship those five nodes carried — to campaigns, malware families, TTPs, infrastructure — now attaches to the canonical “APT29” node. The merge operation preserves all information while eliminating redundancy, and the provenance records show exactly which feed contributed each attribute.

Reviewing merge history for audit

After batch merging operations, you can retrieve the complete history to review every decision made. This audit trail is essential for understanding merge decisions and explaining them to stakeholders:
This history provides complete transparency about merge decisions. When a feed owner asks why their entity was merged into another one, you have the documented evidence and reasoning for the decision.

Streaming ingestion: incremental deduplication

When your pipeline processes continuous data streams — new threat intelligence arriving hourly — you don’t want to re-run pairwise comparison over the entire graph on every batch. Use incremental detection to compare only new entities against the existing canonical set:
NOBELIUM gets queued for merging with the existing APT29 canonical entity. Scattered Spider scores below threshold against every existing actor and gets added to the graph as a new, unique node.

Scaling to large entity sets

For graphs above ten thousand nodes, pairwise comparison becomes computationally expensive due to its O(n²) complexity. Use build_clusters() to run more efficient vectorized batch comparison, then merge each resulting cluster: Performance warning: Always profile your similarity operations on representative data sizes. What works for 1,000 entities may become unacceptably slow at 10,000+ entities without appropriate scaling strategies.
For even larger sets, switch to method="hierarchical" which uses agglomerative bottom-up clustering and scales to hundreds of thousands of entities at the cost of some precision.

A Simple Example: Customer Deduplication

Before exploring domain-specific cases, let’s walk through a straightforward customer deduplication scenario. A company’s CRM system has accumulated duplicate customer records from web signups, sales team entries, and support tickets:
This example demonstrates the core concepts: similarity detection finds related records, and merging consolidates them into canonical entities that preserve all available information.

Common Pitfalls

Threshold tuning without validation. Setting thresholds too low creates false positive merges between genuinely different entities. Always manually review a sample of detected duplicates before running large-scale merging operations. Pairwise scaling problems. The O(n²) cost of comparing every entity pair becomes prohibitive above 10,000 entities. Use clustering methods (build_clusters) or switch to vectorized similarity for large datasets. Using fuzzy matching when primary keys exist. If your entities have reliable unique identifiers (LEI codes, CVE IDs, ISBN numbers), use exact matching on those fields instead of computationally expensive similarity algorithms. Mixing wrapper and class APIs inconsistently. Don’t call detect_duplicates() then manually instantiate EntityMerger—choose either the functional approach or class-based approach and use it consistently throughout your workflow. Ignoring merge strategy implications. keep_first overwrites later records completely, merge_all can introduce conflicting values, and keep_most_complete may not respect source authority. Choose the strategy that matches your data quality requirements. Skipping provenance tracking. Without preserve_provenance=True, you lose visibility into which source contributed each field in the canonical entity, making audit trails impossible. Inadequate similarity algorithm selection. Pure string similarity fails for alias relationships (“APT29” vs “Cozy Bear”), while property matching may be too aggressive for entities with shared attributes but different identities.

Domain examples

A threat intelligence platform ingests actor profiles from Mandiant, CrowdStrike, MITRE ATT&CK, and partner ISAC feeds. The same actors appear under vendor-specific names: “Cozy Bear” (CrowdStrike), “APT29” (MITRE), “Midnight Blizzard” (Microsoft), “The Dukes” (F-Secure). Before any analyst query runs, these aliases must collapse to a single canonical node so that relationships — malware used, infrastructure operated, campaigns attributed — all attach to one place.The alias field is the key signal here. Property-based similarity will fire strongly when any record carries the canonical name in its aliases list. Setting a moderate threshold (0.6) catches alias-based matches that name similarity alone would miss.

Choosing the right threshold

The similarity threshold controls sensitivity. Start at 0.7 and examine false positives before adjusting:
  • 0.95 and above — near-exact string matches only. Use for codes and IDs (LEI, CAS, CVE-ID) where name format is consistent across feeds.
  • 0.80–0.95 — catches typographic variants: “Apple Inc.” vs “Apple, Inc.”, “BlackRock” vs “BlackRock Inc.”
  • 0.65–0.80 — catches abbreviations and short forms. Necessary for organization names that appear in both long and short forms across feeds.
  • 0.50–0.65 — semantic similarity territory. Requires property or embedding signals to compensate for weak name similarity. Use this range for alias-based matching where names may be completely different strings referring to the same entity.

Choosing a merge strategy

  • Ingest Anything — multi-source ingestion creates the duplicates this module resolves
  • Context Graphs — store deduplicated entities directly in the knowledge graph
  • Conflict Resolution — after merging, reconcile disagreeing property values on the canonical entity
  • Provenance — track merge lineage so every canonical entity traces back to its original sources
  • Pipeline — chain ingest, deduplicate, and store as a PipelineBuilder workflow