# How GraphBuilder Handles Entity Resolution in Semantica: A Deep Dive into the Source Code

> Discover how Semantica's GraphBuilder uses EntityResolver to detect and merge duplicate entities. Explore the source code for automatic entity resolution.

- Repository: [Semantica /semantica](https://github.com/semantica-agi/semantica)
- Tags: deep-dive
- Published: 2026-08-15

---

**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`](https://github.com/semantica-agi/semantica/blob/main/semantica/kg/graph_builder.py), the constructor checks the `merge_entities` flag and creates a default `EntityResolver` instance if enabled.

```python

# 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`](https://github.com/semantica-agi/semantica/blob/main/graph_builder.py), the builder accepts either:

- An `entity_resolver` passed directly to `build()`, 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`](https://github.com/semantica-agi/semantica/blob/main/graph_builder.py), the critical call occurs:

```python

# Line 748: The resolution execution

resolved_entities, merge_map = resolver_to_use.resolve_entities(all_entities)

```

The `resolve_entities()` method orchestrates two internal components:

1. **`DuplicateDetector`** – Groups entities believed to represent the same real-world object based on the chosen strategy
2. **`EntityMerger`** – 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`](https://github.com/semantica-agi/semantica/blob/main/graph_builder.py), the builder sets:

```python
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

```python
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

```python
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`](https://github.com/semantica-agi/semantica/blob/main/semantica/kg/graph_builder.py) | Core orchestration: creates resolver, executes `resolve_entities()`, remaps relationship endpoints, sets metadata flags |
| [`semantica/kg/entity_resolver.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/kg/entity_resolver.py) | Implements resolution logic using `DuplicateDetector` and `EntityMerger` |
| [`semantica/deduplication/duplicate_detector.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/deduplication/duplicate_detector.py) | Strategy-driven duplicate grouping (fuzzy matching, exact matching, etc.) |
| [`semantica/deduplication/entity_merger.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/deduplication/entity_merger.py) | Canonical entity creation with `merged_from` provenance tracking |

## Summary

- **Activation**: Set `merge_entities=True` in `GraphBuilder` to enable automatic entity resolution
- **Strategy choice**: Default `"fuzzy"` matching can be overridden via `entity_resolution_strategy` or custom `EntityResolver` instances
- **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`](https://github.com/semantica-agi/semantica/blob/main/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`](https://github.com/semantica-agi/semantica/blob/main/graph_builder.py) and directly reflects whether `merge_entities` was enabled during graph construction.