How GraphBuilder Handles Entity Resolution in Semantica: A Deep Dive into the Source Code
Semantica's GraphBuilder activates an EntityResolver when merge_entities=True to automatically detect, merge, and remap duplicate entities before final graph assembly.
Entity resolution—the process of identifying and merging duplicate real-world entities—is a critical step in knowledge graph construction. In the semantica-agi/semantica repository, the GraphBuilder class orchestrates this workflow through a configurable pipeline that deduplicates entities, updates relationship references, and tracks resolution outcomes in graph metadata.
How Entity Resolution Gets Activated in GraphBuilder
The entity resolution pipeline begins at initialization. In semantica/kg/graph_builder.py, the constructor checks the merge_entities flag and creates a default EntityResolver instance if enabled.
# From graph_builder.py lines 18-25
def __init__(
self,
merge_entities: bool = False,
entity_resolution_strategy: str = "fuzzy",
# ... other parameters
):
self.merge_entities = merge_entities
if self.merge_entities:
from semantica.kg.entity_resolver import EntityResolver
self._default_resolver = EntityResolver(strategy=entity_resolution_strategy)
The EntityResolver receives the resolution strategy—"fuzzy" by default—though alternatives like "exact" can be specified. This strategy controls how DuplicateDetector identifies similar entities later in the pipeline.
The Resolution Decision Point at Build Time
When build() executes, the GraphBuilder determines which resolver to use. According to the source code at line 542 of graph_builder.py, the builder accepts either:
- An
entity_resolverpassed directly tobuild(), or - The default resolver created during initialization
This design allows runtime override without reconstructing the builder.
The Core Resolution Workflow
After extracting entities from all sources, the builder invokes the resolution step. At line 748 of graph_builder.py, the critical call occurs:
# Line 748: The resolution execution
resolved_entities, merge_map = resolver_to_use.resolve_entities(all_entities)
The resolve_entities() method orchestrates two internal components:
DuplicateDetector– Groups entities believed to represent the same real-world object based on the chosen strategyEntityMerger– Consolidates each duplicate group into a single canonical entity
The implementation tracks performance metrics—logging entity counts before and after resolution across lines 745–751—giving observability into deduplication effectiveness.
Remapping Relationship Endpoints After Entity Merging
Entity relationships are collected before resolution occurs, meaning their source_id and target_id values reference original (now potentially merged) entity identifiers. The GraphBuilder solves this reference integrity problem through _remap_relationship_endpoints(), called at line 761.
This method rewrites edge endpoints by consulting the merged_from field on each canonical entity—an array that preserves all original IDs that were consolidated. Any relationship pointing to a merged-away entity gets redirected to its canonical successor.
Verification Through Graph Metadata
The final graph includes provenance information about whether resolution occurred. At line 787 of graph_builder.py, the builder sets:
graph_metadata["entity_resolution_applied"] = self.merge_entities
This boolean flag allows downstream consumers to understand whether entity counts reflect raw extraction or deduplicated results.
Practical Examples: Configuring Entity Resolution
Example 1: Enable Default Fuzzy Resolution
from semantica.kg import GraphBuilder
builder = GraphBuilder(merge_entities=True) # Activates EntityResolver with "fuzzy" strategy
graph = builder.build(
sources=[
{
"entities": [
{"id": "e1", "name": "Apple Inc.", "type": "Company"},
{"id": "e2", "name": "Apple", "type": "Company"},
{"id": "e3", "name": "Microsoft", "type": "Company"},
]
}
]
)
print(graph["metadata"]["entity_resolution_applied"]) # True
print(len(graph["entities"])) # 2 (Apple entities merged)
Example 2: Supply a Custom Resolver
from semantica.kg import GraphBuilder, EntityResolver
# Create resolver with exact matching (no similarity tolerance)
custom_resolver = EntityResolver(strategy="exact", similarity_threshold=1.0)
builder = GraphBuilder(merge_entities=True, entity_resolution_strategy="exact")
graph = builder.build(
sources=[{"entities": [...]}],
entity_resolver=custom_resolver # Overrides default resolver
)
Key Source Files in the Resolution Pipeline
| File | Purpose |
|---|---|
semantica/kg/graph_builder.py |
Core orchestration: creates resolver, executes resolve_entities(), remaps relationship endpoints, sets metadata flags |
semantica/kg/entity_resolver.py |
Implements resolution logic using DuplicateDetector and EntityMerger |
semantica/deduplication/duplicate_detector.py |
Strategy-driven duplicate grouping (fuzzy matching, exact matching, etc.) |
semantica/deduplication/entity_merger.py |
Canonical entity creation with merged_from provenance tracking |
Summary
- Activation: Set
merge_entities=TrueinGraphBuilderto enable automatic entity resolution - Strategy choice: Default
"fuzzy"matching can be overridden viaentity_resolution_strategyor customEntityResolverinstances - Execution flow:
build()→resolve_entities()→_remap_relationship_endpoints()with full logging - Reference integrity: Relationship endpoints are automatically rewritten to point to canonical merged entities
- Observability: Check
graph["metadata"]["entity_resolution_applied"]to verify resolution occurred
Frequently Asked Questions
What happens to relationships when entities are merged?
The GraphBuilder automatically remaps all relationship endpoints. The _remap_relationship_endpoints() method rewrites any source_id or target_id referencing a merged-away entity to point to the canonical surviving entity, using the merged_from field for lookup.
Can I use a custom entity resolution algorithm?
Yes. Pass a pre-configured EntityResolver instance to build() via the entity_resolver parameter. This overrides the default resolver created during initialization, allowing complete control over duplicate detection and merging behavior.
What resolution strategies does Semantica support?
The source code shows "fuzzy" as the default strategy with "exact" available. The EntityResolver passes the strategy to DuplicateDetector, which implements the matching logic—check semantica/deduplication/duplicate_detector.py for strategy-specific implementations.
How can I verify that entity resolution actually ran?
Inspect graph["metadata"]["entity_resolution_applied"] in the output. This boolean field is set at line 787 of graph_builder.py and directly reflects whether merge_entities was enabled during graph construction.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →