mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-09-09 04:00:52 +00:00
llms.md: - Only Groq/OpenAI/LiteLLM/HuggingFaceLLM are exported — remove non-exported Anthropic/Ollama/Gemini/DeepSeek/Novita as direct imports - Rename HuggingFace -> HuggingFaceLLM (correct class name) - Remove non-existent create_provider() — replace with LiteLLM provider/model pattern - Add LiteLLM 100+ providers section with provider/model string examples - Add Exported Classes table (class -> provider -> API key) - Update Provider Comparison table to show correct import per provider ontology.md: - Remove non-existent OntologyManager — replace with OntologyEngine facade - Remove non-existent start_explorer() — replace with CLI: semantica-explorer - SHACLValidator -> OntologyValidator (correct exported name) - OWLExporter -> OWLGenerator (correct exported name) - Add Exported Classes block with all 15+ exported symbols - Add LLMOntologyGenerator section, NamespaceManager section - Add OntologyEvaluator section with coverage/completeness metrics - Add ingest_ontology() section - Add versioning moved-to note (change_management module) kg.md: - TemporalKnowledgeGraph does not exist — replace with TemporalGraphQuery - DistanceCalculator does not exist — replace with SimilarityCalculator - Add Exported Classes block with all 20+ exported symbols - Fix temporal example to use TemporalGraphQuery + TemporalVersionManager correctly - Add SimilarityCalculator section with NodeEmbedder integration example provenance.md: - ActivityTracker not exported — remove; ProvenanceManager handles tracking - Fix track_entity() signature: add source_location, source_quote params - Fix GraphBuilderWithProvenance import: from semantica.kg, not semantica.provenance - Add Exported Classes block with storage backends and checksum utilities - Add SourceReference section with DOI/page/quote fields - Add tamper-evident checksum section (compute_checksum/verify_checksum) - Add Enable Provenance in Extractors section - Fix duplicate heading (W3C PROV-O Export appeared twice) reasoning.md: - Add Exported Classes block with all engines + data types + explanation types - Add Quick Start section - Add Choosing an Engine comparison table - Add InferenceResult/Explanation/ReasoningStep type annotations in examples - Add Tip: use DatalogReasoner for recursive rules semantic_extract.md: - Add Exported Classes block with NamedEntityRecognizer, EventDetector, Entity, Relation, Event, CoreferenceChain, EntityClassifier, TemporalEventProcessor - Add Quick Start section (one-liner extraction pipeline) - Rename EventExtractor -> EventDetector (correct exported name) - Clarify NERExtractor vs NamedEntityRecognizer distinction - Add return type annotations to EventDetector example core.md: - Add Exported Classes block - Add When to Use Core vs. Individual Modules decision table - Add Tip: LifecycleManager only for long-running apps - Fix MethodRegistry example to import build_knowledge_base correctly parse.md: - Add Exported Classes block with all format-specific parsers + data types - Add DoclingParser optional import note utils.md: - Add Exported Classes block with logging/validation/progress/helpers/exceptions deduplication.md: - Add Exported Classes block with PropertyMergeRule, MergeStrategyManager, method_registry, and all convenience functions export.md: - Add Exported Classes block with all exporters, NamespaceManager, SemanticNetworkYAMLExporter, and all convenience functions
214 lines
7.1 KiB
Markdown
214 lines
7.1 KiB
Markdown
---
|
||
title: "Deduplication Module"
|
||
description: "Entity deduplication v1/v2 — similarity scoring, blocking, merging, and cluster-based batch processing."
|
||
icon: "copy"
|
||
---
|
||
|
||
`semantica.deduplication` detects and merges duplicate entities across sources to produce a clean, single-source-of-truth knowledge graph. **v2 strategies** (`blocking_v2`, `hybrid_v2`, `semantic_v2`) are up to **7x faster** than v1 with fine-grained result control.
|
||
|
||
## Exported Classes
|
||
|
||
```python
|
||
from semantica.deduplication import (
|
||
DuplicateDetector, # pairwise + batch duplicate detection
|
||
EntityMerger, # merge duplicate groups with per-property policies
|
||
SimilarityCalculator, # Levenshtein, Jaro-Winkler, cosine, Jaccard, embedding
|
||
ClusterBuilder, # Union-Find + hierarchical clustering
|
||
PropertyMergeRule, # enum: KEEP_FIRST, KEEP_LONGEST, UNION, VOTING, ...
|
||
MergeStrategyManager, # manage and apply merge strategies
|
||
# Convenience functions
|
||
detect_duplicates, # quick: detect_duplicates(entities, method="semantic_v2")
|
||
merge_entities, # quick: merge_entities(entities, duplicates, method="union")
|
||
calculate_similarity, # quick: calculate_similarity(a, b, method="hybrid_v2")
|
||
# Registry
|
||
method_registry, # register custom similarity functions
|
||
)
|
||
```
|
||
|
||
## What You Get
|
||
|
||
- **`DuplicateDetector`** — pairwise and batch duplicate detection with configurable strategies
|
||
- **`EntityMerger`** — merge duplicate groups with configurable property-level merge policies
|
||
- **`SimilarityCalculator`** — multi-factor similarity: Levenshtein, Jaro-Winkler, cosine, Jaccard, embedding
|
||
- **`ClusterBuilder`** — Union-Find and hierarchical clustering for large-scale batch deduplication
|
||
- **Convenience functions** — `detect_duplicates`, `merge_entities`, `calculate_similarity`
|
||
|
||
## DuplicateDetector
|
||
|
||
Find duplicate entity pairs with configurable strategies and result filtering:
|
||
|
||
```python
|
||
from semantica.deduplication import DuplicateDetector
|
||
|
||
detector = DuplicateDetector(similarity_threshold=0.85)
|
||
duplicates = detector.detect_duplicates(entities)
|
||
|
||
for dup in duplicates:
|
||
print(f"{dup.entity_a} ≈ {dup.entity_b} ({dup.similarity:.2f})")
|
||
```
|
||
|
||
Fine-grained control over strategy, thresholds, and result size:
|
||
|
||
```python
|
||
duplicates = detector.detect_duplicates(
|
||
entities,
|
||
strategy="semantic_v2", # see strategies table below
|
||
min_similarity=0.85, # minimum score to consider a match
|
||
top_k_per_entity=3, # max candidates per entity
|
||
max_results=100, # total result cap
|
||
sort_by="similarity", # "similarity" | "entity_id" | "cluster_size"
|
||
)
|
||
```
|
||
|
||
### Detection Strategies
|
||
|
||
| Strategy | Algorithm | Speed | Accuracy |
|
||
| -------- | --------- | ----- | -------- |
|
||
| `jaro_winkler` | String similarity (v1) | Fast | Medium |
|
||
| `blocking_v2` | Blocking + Jaro-Winkler (v2) | Very fast | Medium |
|
||
| `hybrid_v2` | Blocking + semantic + string (v2) | Fast | High |
|
||
| `semantic_v2` | Embedding similarity (v2) | Medium | Highest |
|
||
|
||
<Note>
|
||
**v0.5.0 fix:** `DuplicateDetector` no longer produces duplicate definition errors when the same entity appears in multiple sources with identical definitions.
|
||
</Note>
|
||
|
||
## EntityMerger
|
||
|
||
Merges detected duplicate groups into canonical entities, preserving provenance:
|
||
|
||
```python
|
||
from semantica.deduplication import EntityMerger
|
||
|
||
merger = EntityMerger()
|
||
merged_entities = merger.merge_duplicates(
|
||
entities,
|
||
strategy="keep_most_complete", # see strategies table below
|
||
preserve_provenance=True, # keep source references after merge
|
||
)
|
||
```
|
||
|
||
### Merge Strategies
|
||
|
||
| Strategy | Behavior |
|
||
| -------- | -------- |
|
||
| `keep_first` | Keep the first entity in each duplicate group |
|
||
| `keep_last` | Keep the most recently seen entity |
|
||
| `keep_most_complete` | Keep the entity with the most non-null properties |
|
||
| `union` | Merge all properties — non-conflicting fields combined |
|
||
| `voting` | Most common property value wins |
|
||
|
||
Fine-grained per-property merge rules:
|
||
|
||
```python
|
||
from semantica.deduplication import EntityMerger, PropertyMergeRule
|
||
|
||
merger = EntityMerger(
|
||
property_rules={
|
||
"name": PropertyMergeRule.KEEP_FIRST,
|
||
"aliases": PropertyMergeRule.UNION,
|
||
"description": PropertyMergeRule.KEEP_LONGEST,
|
||
}
|
||
)
|
||
```
|
||
|
||
## SimilarityCalculator
|
||
|
||
Compute multi-factor similarity scores between entity pairs:
|
||
|
||
```python
|
||
from semantica.deduplication import SimilarityCalculator
|
||
|
||
calc = SimilarityCalculator()
|
||
|
||
score = calc.calculate_similarity(entity_a, entity_b)
|
||
# → SimilarityResult(score=0.91, components={...})
|
||
|
||
print(score.score) # overall score 0.0–1.0
|
||
print(score.components["label"]) # label similarity
|
||
print(score.components["embedding"]) # semantic similarity
|
||
print(score.components["property"]) # property overlap
|
||
```
|
||
|
||
Individual string and vector metrics:
|
||
|
||
```python
|
||
lev = calc.levenshtein("Apple Inc.", "Apple Inc")
|
||
jaro = calc.jaro_winkler("Steve Jobs", "Steven Jobs")
|
||
cos = calc.cosine_similarity(embedding_a, embedding_b)
|
||
jacc = calc.jaccard({"founded", "tech"}, {"founded", "technology"})
|
||
```
|
||
|
||
## ClusterBuilder
|
||
|
||
Build entity clusters for large-scale batch deduplication:
|
||
|
||
```python
|
||
from semantica.deduplication import ClusterBuilder
|
||
|
||
builder = ClusterBuilder(algorithm="union_find") # or "hierarchical"
|
||
result = builder.build_clusters(entities, similarity_threshold=0.85)
|
||
|
||
print(f"Clusters: {len(result.clusters)}")
|
||
for cluster in result.clusters:
|
||
print(f" [{cluster.id}] {cluster.members} — cohesion: {cluster.cohesion:.2f}")
|
||
```
|
||
|
||
## Blocking Strategies
|
||
|
||
Blocking reduces the O(n²) pairwise comparison problem to a manageable candidate set:
|
||
|
||
```python
|
||
detector = DuplicateDetector(
|
||
blocking_strategy="token", # "token" | "phonetic" | "ngram"
|
||
blocking_threshold=0.6,
|
||
similarity_threshold=0.85
|
||
)
|
||
```
|
||
|
||
## Custom Similarity Functions
|
||
|
||
Register domain-specific similarity logic:
|
||
|
||
```python
|
||
from semantica.deduplication import method_registry
|
||
|
||
def drug_name_similarity(entity_a, entity_b):
|
||
# Match drug names by active compound
|
||
return score # 0.0 to 1.0
|
||
|
||
method_registry.register("similarity", "drug_name", drug_name_similarity)
|
||
|
||
detector = DuplicateDetector(similarity_method="drug_name")
|
||
```
|
||
|
||
## Convenience Functions
|
||
|
||
```python
|
||
from semantica.deduplication import detect_duplicates, merge_entities, calculate_similarity
|
||
|
||
# Quick detection
|
||
duplicates = detect_duplicates(entities, method="semantic_v2", similarity_threshold=0.85)
|
||
|
||
# Quick merge
|
||
merged = merge_entities(entities, duplicates, method="keep_most_complete")
|
||
|
||
# Quick similarity
|
||
score = calculate_similarity(entity_a, entity_b, method="hybrid_v2")
|
||
```
|
||
|
||
<CardGroup cols={2}>
|
||
<Card title="Conflicts" icon="triangle-exclamation" href="conflicts">
|
||
Detect value conflicts between non-duplicate entities.
|
||
</Card>
|
||
<Card title="Knowledge Graph" icon="diagram-project" href="kg">
|
||
GraphBuilder uses deduplication during construction.
|
||
</Card>
|
||
<Card title="Normalize" icon="broom" href="normalize">
|
||
Normalize entity names before deduplication.
|
||
</Card>
|
||
<Card title="Provenance" icon="link" href="provenance">
|
||
Track merged entity lineage.
|
||
</Card>
|
||
</CardGroup>
|