diff --git a/cookbook/advanced/02_Advanced_Graph_Analytics.ipynb b/cookbook/advanced/02_Advanced_Graph_Analytics.ipynb index 058192da..e74978a0 100644 --- a/cookbook/advanced/02_Advanced_Graph_Analytics.ipynb +++ b/cookbook/advanced/02_Advanced_Graph_Analytics.ipynb @@ -45,7 +45,8 @@ "metadata": {}, "outputs": [], "source": [ - "from semantica.kg import GraphBuilder, GraphAnalyzer, CentralityCalculator, CommunityDetector, ConnectivityAnalyzer, GraphValidator, Deduplicator\n", + "from semantica.kg import GraphBuilder, GraphAnalyzer, CentralityCalculator, CommunityDetector, ConnectivityAnalyzer, GraphValidator\n", + "from semantica.deduplication import DuplicateDetector, EntityMerger, MergeStrategy\n", "\n", "builder = GraphBuilder()\n", "analyzer = GraphAnalyzer()\n", @@ -159,13 +160,18 @@ "outputs": [], "source": [ "graph_validator = GraphValidator()\n", - "deduplicator = Deduplicator()\n", "\n", "validation_result = graph_validator.validate(kg)\n", - "deduplicated_kg = deduplicator.deduplicate(kg)\n", "\n", "print(f\"Graph validation: {validation_result.get('valid', False)}\")\n", - "print(f\"Deduplicated entities: {len(deduplicated_kg.get('entities', []))}\")\n" + "print(f\"Issues found: {len(validation_result.get('issues', []))}\")\n", + "\n", + "# For deduplication, use semantica.deduplication module:\n", + "# from semantica.deduplication import DuplicateDetector, EntityMerger, MergeStrategy\n", + "# detector = DuplicateDetector(similarity_threshold=0.8)\n", + "# duplicate_groups = detector.detect_duplicate_groups(kg.get('entities', []))\n", + "# merger = EntityMerger()\n", + "# merge_operations = merger.merge_duplicates(kg.get('entities', []), strategy=MergeStrategy.KEEP_MOST_COMPLETE)\n" ] }, { diff --git a/cookbook/use_cases/blockchain/02_Transaction_Network_Analysis.ipynb b/cookbook/use_cases/blockchain/02_Transaction_Network_Analysis.ipynb index cf0b6a8f..89066790 100644 --- a/cookbook/use_cases/blockchain/02_Transaction_Network_Analysis.ipynb +++ b/cookbook/use_cases/blockchain/02_Transaction_Network_Analysis.ipynb @@ -62,7 +62,7 @@ "from semantica.kg import CentralityCalculator, CommunityDetector, ConnectivityAnalyzer\n", "from semantica.reasoning import InferenceEngine, RuleManager, ExplanationGenerator\n", "from semantica.kg_qa import KGQualityAssessor\n", - "from semantica.kg import ConflictDetector\n", + "from semantica.conflicts import ConflictDetector\n", "from semantica.export import JSONExporter, RDFExporter, ReportGenerator\n", "from semantica.visualization import KGVisualizer, TemporalVisualizer, AnalyticsVisualizer\n", "import tempfile\n", diff --git a/cookbook/use_cases/cybersecurity/01_Anomaly_Detection_Real_Time.ipynb b/cookbook/use_cases/cybersecurity/01_Anomaly_Detection_Real_Time.ipynb index ed8609a6..7439b7b9 100644 --- a/cookbook/use_cases/cybersecurity/01_Anomaly_Detection_Real_Time.ipynb +++ b/cookbook/use_cases/cybersecurity/01_Anomaly_Detection_Real_Time.ipynb @@ -292,7 +292,8 @@ "community_detector = CommunityDetector()\n", "connectivity_analyzer = ConnectivityAnalyzer()\n", "\n", - "centrality_scores = centrality_calculator.calculate_centrality(temporal_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(temporal_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "communities = community_detector.detect_communities(temporal_kg)\n", "connectivity = connectivity_analyzer.analyze_connectivity(temporal_kg)\n", "\n", @@ -482,4 +483,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cookbook/use_cases/cybersecurity/02_Incident_Analysis.ipynb b/cookbook/use_cases/cybersecurity/02_Incident_Analysis.ipynb index d5c24e7c..9db3e088 100644 --- a/cookbook/use_cases/cybersecurity/02_Incident_Analysis.ipynb +++ b/cookbook/use_cases/cybersecurity/02_Incident_Analysis.ipynb @@ -302,7 +302,8 @@ "# Analyze graph structure\n", "metrics = graph_analyzer.compute_metrics(incident_kg)\n", "connectivity = connectivity_analyzer.analyze_connectivity(incident_kg)\n", - "centrality_scores = centrality_calculator.calculate_centrality(incident_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(incident_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "\n", "print(f\"Built incident knowledge graph\")\n", "print(f\" Entities: {len(incident_kg.get('entities', []))}\")\n", @@ -462,4 +463,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cookbook/use_cases/finance/01_Financial_Data_Integration.ipynb b/cookbook/use_cases/finance/01_Financial_Data_Integration.ipynb index 1f8ffed1..f9b130f1 100644 --- a/cookbook/use_cases/finance/01_Financial_Data_Integration.ipynb +++ b/cookbook/use_cases/finance/01_Financial_Data_Integration.ipynb @@ -379,7 +379,8 @@ "connectivity_analyzer = ConnectivityAnalyzer()\n", "\n", "# Calculate graph metrics\n", - "centrality_scores = centrality_calculator.calculate_centrality(financial_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(financial_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "communities = community_detector.detect_communities(financial_kg)\n", "connectivity = connectivity_analyzer.analyze_connectivity(financial_kg)\n", "\n", @@ -517,4 +518,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cookbook/use_cases/finance/02_Financial_Reports_Analysis.ipynb b/cookbook/use_cases/finance/02_Financial_Reports_Analysis.ipynb index 6b9d1865..8bda57cd 100644 --- a/cookbook/use_cases/finance/02_Financial_Reports_Analysis.ipynb +++ b/cookbook/use_cases/finance/02_Financial_Reports_Analysis.ipynb @@ -275,7 +275,8 @@ "\n", "# Analyze graph structure\n", "metrics = graph_analyzer.compute_metrics(financial_kg)\n", - "centrality_scores = centrality_calculator.calculate_centrality(financial_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(financial_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "communities = community_detector.detect_communities(financial_kg)\n", "connectivity = connectivity_analyzer.analyze_connectivity(financial_kg)\n", "\n", @@ -424,4 +425,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cookbook/use_cases/healthcare/02_Disease_Network_Analysis.ipynb b/cookbook/use_cases/healthcare/02_Disease_Network_Analysis.ipynb index 5092418d..5bb26e91 100644 --- a/cookbook/use_cases/healthcare/02_Disease_Network_Analysis.ipynb +++ b/cookbook/use_cases/healthcare/02_Disease_Network_Analysis.ipynb @@ -294,7 +294,8 @@ "temporal_pattern_detector = TemporalPatternDetector()\n", "\n", "metrics = graph_analyzer.compute_metrics(disease_kg)\n", - "centrality_scores = centrality_calculator.calculate_centrality(disease_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(disease_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "communities = community_detector.detect_communities(disease_kg)\n", "connectivity = connectivity_analyzer.analyze_connectivity(disease_kg)\n", "\n", @@ -413,4 +414,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cookbook/use_cases/healthcare/03_Drug_Interactions_Analysis.ipynb b/cookbook/use_cases/healthcare/03_Drug_Interactions_Analysis.ipynb index d5793ee9..ccb278f4 100644 --- a/cookbook/use_cases/healthcare/03_Drug_Interactions_Analysis.ipynb +++ b/cookbook/use_cases/healthcare/03_Drug_Interactions_Analysis.ipynb @@ -260,7 +260,8 @@ "drug_kg = builder.build(drug_entities, drug_relationships)\n", "\n", "metrics = graph_analyzer.compute_metrics(drug_kg)\n", - "centrality_scores = centrality_calculator.calculate_centrality(drug_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(drug_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "communities = community_detector.detect_communities(drug_kg)\n", "connectivity = connectivity_analyzer.analyze_connectivity(drug_kg)\n", "\n", @@ -423,4 +424,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cookbook/use_cases/renewable_energy/01_Energy_Market_Analysis.ipynb b/cookbook/use_cases/renewable_energy/01_Energy_Market_Analysis.ipynb index b800b974..11bbbcb7 100644 --- a/cookbook/use_cases/renewable_energy/01_Energy_Market_Analysis.ipynb +++ b/cookbook/use_cases/renewable_energy/01_Energy_Market_Analysis.ipynb @@ -311,7 +311,8 @@ " pricing_analysis[energy_type][\"avg_price\"] = sum(data[\"prices\"]) / len(data[\"prices\"])\n", " pricing_analysis[energy_type][\"total_volume\"] = sum(data[\"volumes\"])\n", "\n", - "centrality_scores = centrality_calculator.calculate_centrality(energy_market_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(market_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "communities = community_detector.detect_communities(energy_market_kg)\n", "connectivity = connectivity_analyzer.analyze_connectivity(energy_market_kg)\n", "\n", @@ -438,4 +439,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cookbook/use_cases/renewable_energy/03_Grid_Management.ipynb b/cookbook/use_cases/renewable_energy/03_Grid_Management.ipynb index b2036c09..cc08e879 100644 --- a/cookbook/use_cases/renewable_energy/03_Grid_Management.ipynb +++ b/cookbook/use_cases/renewable_energy/03_Grid_Management.ipynb @@ -326,7 +326,8 @@ " min_frequency=1\n", ")\n", "\n", - "centrality_scores = centrality_calculator.calculate_centrality(grid_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(grid_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "communities = community_detector.detect_communities(grid_kg)\n", "connectivity = connectivity_analyzer.analyze_connectivity(grid_kg)\n", "\n", @@ -466,4 +467,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cookbook/use_cases/supply_chain/01_Supply_Chain_Data_Integration.ipynb b/cookbook/use_cases/supply_chain/01_Supply_Chain_Data_Integration.ipynb index 43c6b142..0061bee1 100644 --- a/cookbook/use_cases/supply_chain/01_Supply_Chain_Data_Integration.ipynb +++ b/cookbook/use_cases/supply_chain/01_Supply_Chain_Data_Integration.ipynb @@ -418,7 +418,8 @@ "connectivity = connectivity_analyzer.analyze_connectivity(supply_chain_kg)\n", "\n", "# Calculate graph metrics\n", - "centrality_scores = centrality_calculator.calculate_centrality(supply_chain_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(supply_chain_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "communities = community_detector.detect_communities(supply_chain_kg)\n", "\n", "print(f\" Entities: {len(supply_chain_kg.get('entities', []))}\")\n", @@ -565,4 +566,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cookbook/use_cases/trading/01_Market_Data_Analysis.ipynb b/cookbook/use_cases/trading/01_Market_Data_Analysis.ipynb index 8420eea6..34ef15a7 100644 --- a/cookbook/use_cases/trading/01_Market_Data_Analysis.ipynb +++ b/cookbook/use_cases/trading/01_Market_Data_Analysis.ipynb @@ -257,7 +257,8 @@ " min_frequency=1\n", ")\n", "\n", - "centrality_scores = centrality_calculator.calculate_centrality(market_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(market_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "communities = community_detector.detect_communities(market_kg)\n", "connectivity = connectivity_analyzer.analyze_connectivity(market_kg)\n", "\n", @@ -363,4 +364,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cookbook/use_cases/trading/03_Real_Time_Monitoring.ipynb b/cookbook/use_cases/trading/03_Real_Time_Monitoring.ipynb index 41025204..48e0fd3b 100644 --- a/cookbook/use_cases/trading/03_Real_Time_Monitoring.ipynb +++ b/cookbook/use_cases/trading/03_Real_Time_Monitoring.ipynb @@ -265,7 +265,8 @@ " \"timestamp\": position.get(\"timestamp\", \"\")\n", " })\n", "\n", - "centrality_scores = centrality_calculator.calculate_centrality(trading_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(trading_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "communities = community_detector.detect_communities(trading_kg)\n", "connectivity = connectivity_analyzer.analyze_connectivity(trading_kg)\n", "\n", @@ -405,4 +406,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/cookbook/use_cases/trading/05_Strategy_Backtesting.ipynb b/cookbook/use_cases/trading/05_Strategy_Backtesting.ipynb index 43649065..356d41ef 100644 --- a/cookbook/use_cases/trading/05_Strategy_Backtesting.ipynb +++ b/cookbook/use_cases/trading/05_Strategy_Backtesting.ipynb @@ -316,7 +316,8 @@ "explanation_generator = ExplanationGenerator()\n", "\n", "# Analyze graph structure\n", - "centrality_scores = centrality_calculator.calculate_centrality(historical_kg, measure=\"degree\")\n", + "centrality_result = centrality_calculator.calculate_degree_centrality(historical_kg)\n", + "centrality_scores = centrality_result.get('centrality', {})\n", "communities = community_detector.detect_communities(historical_kg)\n", "connectivity = connectivity_analyzer.analyze_connectivity(historical_kg)\n", "\n", @@ -417,4 +418,4 @@ }, "nbformat": 4, "nbformat_minor": 2 -} +} \ No newline at end of file diff --git a/docs/reference/kg.md b/docs/reference/kg.md index be9a7fb2..83ab3ba6 100644 --- a/docs/reference/kg.md +++ b/docs/reference/kg.md @@ -24,13 +24,7 @@ --- - Deduplicate entities using fuzzy matching and semantic similarity - -- :material-alert-decagram:{ .lg .middle } **Conflict Detection** - - --- - - Detect and resolve contradicting facts from multiple sources + Resolve entities using fuzzy matching and semantic similarity - :material-chart-network:{ .lg .middle } **Graph Analytics** @@ -48,10 +42,14 @@ !!! tip "When to Use" - **KG Building**: The primary module for assembling a KG from extracted data - - **Data Cleaning**: Merging duplicates and resolving conflicts + - **Entity Resolution**: Resolving and merging similar entities - **Analysis**: Understanding the structure and importance of nodes - **Time-Series**: Modeling how the graph evolves over time +!!! note "Related Modules" + - **Conflict Detection**: Use `semantica.conflicts` module for conflict detection and resolution + - **Deduplication**: Use `semantica.deduplication` module for advanced deduplication + --- ## ⚙️ Algorithms Used @@ -83,7 +81,7 @@ Constructs the KG from raw data. | Method | Description | |--------|-------------| | `build(sources)` | Build graph from inputs | -| `merge_entities()` | Run deduplication | +| `merge_entities()` | Merge duplicate entities during building | **Example:** @@ -118,25 +116,19 @@ Queries time-aware graphs. --- -## Convenience Functions +## Using Classes ```python -<<<<<<< HEAD -from semantica.kg import GraphBuilder, analyze_graph +from semantica.kg import GraphBuilder, GraphAnalyzer # Build using GraphBuilder -builder = GraphBuilder(resolve_conflicts=True) +builder = GraphBuilder(merge_entities=True) kg = builder.build(sources) -======= -from semantica.kg import build, analyze_graph - -# Build -kg = build(sources, resolve_conflicts=True) ->>>>>>> origin/main # Analyze -stats = analyze_graph(kg) -print(f"Communities: {stats['communities']}") +analyzer = GraphAnalyzer() +stats = analyzer.analyze_graph(kg) +print(f"Communities: {stats.get('communities', [])}") ``` --- @@ -148,7 +140,7 @@ print(f"Communities: {stats['communities']}") ```bash export KG_MERGE_STRATEGY=fuzzy export KG_TEMPORAL_GRANULARITY=day -export KG_CONFLICT_RESOLUTION=confidence +export KG_RESOLUTION_STRATEGY=fuzzy ``` ### YAML Configuration @@ -191,10 +183,12 @@ print(f"New nodes since 2020: {len(diff.nodes)}") ## Best Practices -1. **Clean Data First**: Use `EntityResolver` aggressively to prevent "entity explosion" (too many duplicate nodes). +1. **Clean Data First**: Use `EntityResolver` to resolve similar entities and prevent "entity explosion" (too many duplicate nodes). 2. **Use Provenance**: Always track sources (`track_history=True`) to debug where bad data came from. 3. **Temporal Granularity**: Choose the right granularity (Day vs Second) to balance performance and precision. 4. **Validate**: Run `GraphValidator` after building to ensure structural integrity. +5. **Deduplication**: Use `semantica.deduplication` module for advanced deduplication needs. +6. **Conflict Resolution**: Use `semantica.conflicts` module for conflict detection and resolution. --- @@ -203,3 +197,5 @@ print(f"New nodes since 2020: {len(diff.nodes)}") - [Graph Store Module](graph_store.md) - Persistence layer - [Semantic Extract Module](semantic_extract.md) - Data source - [Visualization Module](visualization.md) - Visualizing the KG +- [Conflicts Module](conflicts.md) - Conflict detection and resolution +- [Deduplication Module](deduplication.md) - Advanced deduplication diff --git a/fix_remaining_notebooks.py b/fix_remaining_notebooks.py new file mode 100644 index 00000000..25eb4bb5 --- /dev/null +++ b/fix_remaining_notebooks.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +"""Fix remaining notebooks with calculate_centrality calls""" + +import json +import os + +# List of notebooks to fix +notebooks = [ + "cookbook/use_cases/trading/01_Market_Data_Analysis.ipynb", + "cookbook/use_cases/trading/03_Real_Time_Monitoring.ipynb", + "cookbook/use_cases/trading/05_Strategy_Backtesting.ipynb", + "cookbook/use_cases/healthcare/02_Disease_Network_Analysis.ipynb", + "cookbook/use_cases/healthcare/03_Drug_Interactions_Analysis.ipynb", + "cookbook/use_cases/renewable_energy/01_Energy_Market_Analysis.ipynb", + "cookbook/use_cases/renewable_energy/03_Grid_Management.ipynb", + "cookbook/use_cases/finance/01_Financial_Data_Integration.ipynb", + "cookbook/use_cases/finance/02_Financial_Reports_Analysis.ipynb", + "cookbook/use_cases/cybersecurity/01_Anomaly_Detection_Real_Time.ipynb", + "cookbook/use_cases/cybersecurity/02_Incident_Analysis.ipynb", + "cookbook/use_cases/supply_chain/01_Supply_Chain_Data_Integration.ipynb", +] + +old_pattern = 'calculate_centrality(' +new_code = [ + 'centrality_result = centrality_calculator.calculate_degree_centrality(', + "centrality_scores = centrality_result.get('centrality', {})" +] + +for notebook_path in notebooks: + if not os.path.exists(notebook_path): + print(f"Skipping {notebook_path} - file not found") + continue + + print(f"Processing {notebook_path}...") + + with open(notebook_path, 'r', encoding='utf-8') as f: + nb = json.load(f) + + modified = False + for cell in nb['cells']: + if cell.get('cell_type') == 'code': + source = cell.get('source', []) + if isinstance(source, list): + # Check if any line contains the pattern + for i, line in enumerate(source): + if old_pattern in line and 'measure="degree"' in line: + # Extract the graph variable name + if 'market_kg' in line: + graph_var = 'market_kg' + elif 'trading_kg' in line: + graph_var = 'trading_kg' + elif 'historical_kg' in line: + graph_var = 'historical_kg' + elif 'disease_kg' in line: + graph_var = 'disease_kg' + elif 'drug_kg' in line: + graph_var = 'drug_kg' + elif 'energy_market_kg' in line: + graph_var = 'energy_market_kg' + elif 'grid_kg' in line: + graph_var = 'grid_kg' + elif 'financial_kg' in line: + graph_var = 'financial_kg' + elif 'temporal_kg' in line: + graph_var = 'temporal_kg' + elif 'incident_kg' in line: + graph_var = 'incident_kg' + elif 'supply_chain_kg' in line: + graph_var = 'supply_chain_kg' + else: + print(f" Warning: Could not identify graph variable in line: {line}") + continue + + # Replace the line + new_lines = [ + f"centrality_result = centrality_calculator.calculate_degree_centrality({graph_var})\n", + f"centrality_scores = centrality_result.get('centrality', {{}})\n" + ] + cell['source'][i:i+1] = new_lines + modified = True + print(f" Fixed calculate_centrality call with {graph_var}") + break + + if modified: + with open(notebook_path, 'w', encoding='utf-8') as f: + json.dump(nb, f, indent=1, ensure_ascii=False) + print(f" ✓ Updated {notebook_path}") + else: + print(f" - No changes needed in {notebook_path}") + +print("\nDone!") + diff --git a/semantica/kg/__init__.py b/semantica/kg/__init__.py index 3a6d593c..d757f088 100644 --- a/semantica/kg/__init__.py +++ b/semantica/kg/__init__.py @@ -3,16 +3,16 @@ Knowledge Graph Management Module This module provides comprehensive knowledge graph construction and management capabilities for the Semantica framework, including temporal knowledge graph support for time-aware -knowledge representation, graph analytics, entity resolution, conflict detection, and -provenance tracking. +knowledge representation, graph analytics, entity resolution, and provenance tracking. + +Note: For conflict detection and resolution, use the semantica.conflicts module. +For deduplication, use the semantica.deduplication module. Algorithms Used: Knowledge Graph Construction: - Graph Building: Entity-relationship graph construction from multiple sources - Entity Resolution: Fuzzy string matching, exact matching, semantic similarity matching for duplicate detection - - Conflict Detection: Value conflict detection (same entity with different property values), relationship conflict detection - - Conflict Resolution: Highest confidence strategy, source-based resolution - Temporal Graph Support: Time-aware edge creation with valid_from/valid_until timestamps - Temporal Granularity: Time normalization (second, minute, hour, day, week, month, year) - Entity Merging: Property aggregation, metadata merging, provenance tracking @@ -39,12 +39,6 @@ Entity Resolution: - Entity Merging: Property conflict resolution, metadata aggregation - ID Normalization: Canonical ID assignment for merged entities -Conflict Detection: - - Value Conflict Detection: Property value comparison, unique value set extraction - - Relationship Conflict Detection: Relationship property comparison, conflict identification - - Source Tracking: Multi-source conflict tracking, provenance-based conflict resolution - - Conflict Categorization: Value conflicts vs relationship conflicts - Graph Validation: - Entity Validation: Required field checking (ID, type), unique ID verification - Relationship Validation: Source/target reference validation, required field checking @@ -60,11 +54,6 @@ Temporal Operations: - Temporal Path Finding: BFS with temporal validity constraints - Version Management: Snapshot creation, version comparison, timestamp-based versioning -Deduplication: - - Duplicate Group Detection: Similarity-based clustering, threshold-based grouping - - Entity Merging: Property aggregation strategies, metadata merging - - Provenance Tracking: Source tracking for merged entities, lineage maintenance - Provenance Tracking: - Source Tracking: Multi-source entity tracking, timestamp recording - Lineage Retrieval: Complete provenance history reconstruction @@ -79,8 +68,7 @@ Seed Management: Key Features: - Knowledge graph construction from multiple sources - Temporal knowledge graph support with time-aware edges - - Entity resolution and deduplication - - Conflict detection and resolution + - Entity resolution - Comprehensive graph analytics (centrality, communities, connectivity) - Graph validation and consistency checking - Temporal queries and pattern detection @@ -95,75 +83,44 @@ Main Classes: - TemporalGraphQuery: Time-aware graph querying - TemporalPatternDetector: Temporal pattern detection - TemporalVersionManager: Temporal versioning and snapshots - - ConflictDetector: Conflict detection and resolution - ProvenanceTracker: Provenance tracking and management - CentralityCalculator: Centrality measures calculation - CommunityDetector: Community detection - ConnectivityAnalyzer: Connectivity analysis - - Deduplicator: Graph deduplication - GraphValidator: Graph validation - SeedManager: Seed data management - MethodRegistry: Registry for custom KG methods - KGConfig: Configuration manager for KG module -Convenience Functions: - - build: Build knowledge graph from sources - - build_kg: Knowledge graph building wrapper - - analyze_graph: Graph analysis wrapper - - resolve_entities: Entity resolution wrapper - - validate_graph: Graph validation wrapper - - detect_conflicts: Conflict detection wrapper - - calculate_centrality: Centrality calculation wrapper - - detect_communities: Community detection wrapper - - analyze_connectivity: Connectivity analysis wrapper - - deduplicate_graph: Deduplication wrapper - - query_temporal: Temporal query wrapper - - get_kg_method: Get KG method by name - - list_available_methods: List registered methods +Global Instances: + - method_registry: Global MethodRegistry instance for registering custom methods + - kg_config: Global KGConfig instance for configuration management Example Usage: - >>> from semantica.kg import build, build_kg, analyze_graph, calculate_centrality - >>> # Using convenience function - >>> kg = build(sources=[{"entities": [...], "relationships": [...]}]) - >>> # Using method functions - >>> kg = build_kg(sources, method="default") - >>> analysis = analyze_graph(kg, method="default") - >>> centrality = calculate_centrality(kg, method="degree") - >>> # Using classes directly - >>> from semantica.kg import GraphBuilder - >>> builder = GraphBuilder(merge_entities=True, resolve_conflicts=True) - >>> graph = builder.build(sources) + >>> from semantica.kg import GraphBuilder, GraphAnalyzer, CentralityCalculator + >>> # Build knowledge graph + >>> builder = GraphBuilder(merge_entities=True) + >>> kg = builder.build(sources=[{"entities": [...], "relationships": [...]}]) + >>> # Analyze graph + >>> analyzer = GraphAnalyzer() + >>> analysis = analyzer.analyze_graph(kg) + >>> # Calculate centrality + >>> centrality_calc = CentralityCalculator() + >>> degree_centrality = centrality_calc.calculate_degree_centrality(kg) Author: Semantica Contributors License: MIT """ -from typing import Any, Dict, List, Optional, Union from .centrality_calculator import CentralityCalculator from .community_detector import CommunityDetector from .config import KGConfig, kg_config -from .conflict_detector import ConflictDetector from .connectivity_analyzer import ConnectivityAnalyzer -from .deduplicator import Deduplicator from .entity_resolver import EntityResolver from .graph_analyzer import GraphAnalyzer from .graph_builder import GraphBuilder from .graph_validator import GraphValidator -from .methods import ( - analyze_connectivity, - analyze_graph, - build_kg, - calculate_centrality, - deduplicate_graph, - detect_communities, - detect_conflicts, - get_kg_method, - list_available_methods, - query_temporal, - resolve_entities, - validate_graph, -) from .provenance_tracker import ProvenanceTracker from .registry import MethodRegistry, method_registry from .seed_manager import SeedManager @@ -181,96 +138,15 @@ __all__ = [ "TemporalGraphQuery", "TemporalPatternDetector", "TemporalVersionManager", - "ConflictDetector", "ProvenanceTracker", "CentralityCalculator", "CommunityDetector", "ConnectivityAnalyzer", - "Deduplicator", "GraphValidator", "SeedManager", - # Registry and Methods + # Registry and Configuration "MethodRegistry", "method_registry", - "build_kg", - "analyze_graph", - "resolve_entities", - "validate_graph", - "detect_conflicts", - "calculate_centrality", - "detect_communities", - "analyze_connectivity", - "deduplicate_graph", - "query_temporal", - "get_kg_method", - "list_available_methods", - # Configuration "KGConfig", "kg_config", ] - -def build( - sources: Union[List[Any], Any], - merge_entities: bool = True, - entity_resolution_strategy: str = "fuzzy", - resolve_conflicts: bool = True, - enable_temporal: bool = False, - temporal_granularity: str = "day", - track_history: bool = False, - version_snapshots: bool = False, - entity_resolver: Optional[EntityResolver] = None, - **options, -) -> Dict[str, Any]: - """ - Build knowledge graph from sources (module-level convenience function). - - This is a user-friendly wrapper around GraphBuilder.build() that creates - a GraphBuilder instance and builds the knowledge graph. - - Args: - sources: List of sources (documents, entities, relationships, or dicts with entities/relationships) - merge_entities: Whether to merge duplicate entities (default: True) - entity_resolution_strategy: Strategy for entity resolution - "fuzzy", "exact", "semantic" (default: "fuzzy") - resolve_conflicts: Whether to resolve conflicts (default: True) - enable_temporal: Enable temporal knowledge graph features (default: False) - temporal_granularity: Time granularity - "second", "minute", "hour", "day", etc. (default: "day") - track_history: Track historical changes (default: False) - version_snapshots: Create version snapshots (default: False) - entity_resolver: Optional EntityResolver instance (default: None, creates one if needed) - **options: Additional build options - - Returns: - Dictionary containing: - - entities: List of entities - - relationships: List of relationships - - metadata: Graph metadata including counts and timestamps - - Examples: - >>> import semantica - >>> result = semantica.kg.build( - ... sources=[{"entities": [...], "relationships": [...]}], - ... merge_entities=True, - ... resolve_conflicts=True - ... ) - >>> print(f"Built graph with {result['metadata']['num_entities']} entities") - """ - # Normalize sources to list - if not isinstance(sources, list): - sources = [sources] - - # Create GraphBuilder instance - graph_builder = GraphBuilder( - merge_entities=merge_entities, - entity_resolution_strategy=entity_resolution_strategy, - resolve_conflicts=resolve_conflicts, - enable_temporal=enable_temporal, - temporal_granularity=temporal_granularity, - track_history=track_history, - version_snapshots=version_snapshots, - **options, - ) - - # Build knowledge graph - graph = graph_builder.build(sources, entity_resolver=entity_resolver, **options) - - return graph diff --git a/semantica/kg/conflict_detector.py b/semantica/kg/conflict_detector.py deleted file mode 100644 index 85d038f6..00000000 --- a/semantica/kg/conflict_detector.py +++ /dev/null @@ -1,304 +0,0 @@ -""" -Conflict Detection Module - -This module provides comprehensive conflict identification and resolution -capabilities for the Semantica framework, enabling detection of inconsistencies -in knowledge graphs. - -Key Features: - - Value conflict detection (conflicting property values for same entity) - - Relationship conflict detection (conflicting relationship properties) - - Conflict resolution with multiple strategies - - Source tracking for conflicts - - Conflict categorization and prioritization - -Main Classes: - - ConflictDetector: Main conflict detection and resolution engine - -Example Usage: - >>> from semantica.kg import ConflictDetector - >>> detector = ConflictDetector() - >>> conflicts = detector.detect_conflicts(knowledge_graph) - >>> resolution = detector.resolve_conflicts(conflicts) - -Author: Semantica Contributors -License: MIT -""" - -from typing import Any, Dict, List, Optional - -from ..conflicts.conflict_detector import Conflict -from ..conflicts.conflict_detector import ConflictDetector as BaseConflictDetector -from ..conflicts.conflict_resolver import ConflictResolver -from ..utils.logging import get_logger -from ..utils.progress_tracker import get_progress_tracker - - -class ConflictDetector: - """ - Conflict detection and resolution engine. - - This class identifies conflicts and inconsistencies in knowledge graphs, - including value conflicts (same entity with different property values) - and relationship conflicts. Provides conflict resolution capabilities. - - Features: - - Entity property value conflict detection - - Relationship property conflict detection - - Conflict resolution with configurable strategies - - Source tracking for conflict origins - - Example Usage: - >>> detector = ConflictDetector() - >>> conflicts = detector.detect_conflicts(knowledge_graph) - >>> resolution = detector.resolve_conflicts(conflicts) - """ - - def __init__(self, **config): - """ - Initialize conflict detector. - - Sets up the detector with base conflict detection and resolution - components from the conflicts module. - - Args: - **config: Configuration options: - - detection: Configuration for conflict detection (optional) - - resolution: Configuration for conflict resolution (optional) - """ - self.logger = get_logger("conflict_detector") - self.config = config - - # Initialize progress tracker - self.progress_tracker = get_progress_tracker() - - # Initialize conflict detection components - self.base_detector = BaseConflictDetector(**config.get("detection", {})) - self.resolver = ConflictResolver(**config.get("resolution", {})) - - self.logger.debug("Conflict detector initialized") - - def detect_conflicts(self, knowledge_graph: Any) -> List[Dict[str, Any]]: - """ - Detect conflicts in knowledge graph. - - This method identifies conflicts in the knowledge graph, including: - - Value conflicts: Same entity with different values for the same property - - Relationship conflicts: Same relationship with conflicting properties - - Args: - knowledge_graph: Knowledge graph instance (object with entities/relationships - attributes, or dict with "entities" and "relationships" keys) - - Returns: - list: List of conflict dictionaries, each containing: - - entity_id or relationship: Identifier of conflicted element - - property: Property name with conflict - - conflicting_values: List of conflicting values - - type: Conflict type ("value_conflict" or "relationship_conflict") - - sources: List of source identifiers for conflicting values - """ - self.logger.info("Detecting conflicts in knowledge graph") - - # Extract entities and relationships from graph - entities = [] - relationships = [] - - if hasattr(knowledge_graph, "entities"): - entities = knowledge_graph.entities - elif hasattr(knowledge_graph, "get_entities"): - entities = knowledge_graph.get_entities() - elif isinstance(knowledge_graph, dict): - entities = knowledge_graph.get("entities", []) - relationships = knowledge_graph.get("relationships", []) - - if hasattr(knowledge_graph, "relationships"): - relationships = knowledge_graph.relationships - elif hasattr(knowledge_graph, "get_relationships"): - relationships = knowledge_graph.get_relationships() - - # Track conflict detection - tracking_id = self.progress_tracker.start_tracking( - file=None, - module="kg", - submodule="ConflictDetector", - message="Detecting conflicts", - ) - - try: - conflicts = [] - - self.progress_tracker.update_tracking( - tracking_id, message="Detecting value conflicts..." - ) - # Detect value conflicts - entity_properties = {} - for entity in entities: - entity_id = entity.get("id") or entity.get("entity_id") - if not entity_id: - continue - - for prop_name, prop_value in entity.items(): - if prop_name in ["id", "entity_id", "type", "source"]: - continue - - if entity_id not in entity_properties: - entity_properties[entity_id] = {} - - if prop_name not in entity_properties[entity_id]: - entity_properties[entity_id][prop_name] = [] - - entity_properties[entity_id][prop_name].append( - {"value": prop_value, "entity": entity} - ) - - # Check for conflicts - for entity_id, properties in entity_properties.items(): - for prop_name, values in properties.items(): - unique_values = { - str(v["value"]) for v in values if v["value"] is not None - } - if len(unique_values) > 1: - conflicts.append( - { - "entity_id": entity_id, - "property": prop_name, - "conflicting_values": list(unique_values), - "type": "value_conflict", - "sources": [ - v["entity"].get("source", "unknown") for v in values - ], - } - ) - - self.progress_tracker.update_tracking( - tracking_id, message="Detecting relationship conflicts..." - ) - # Detect relationship conflicts - relationship_map = {} - for rel in relationships: - source = rel.get("source") or rel.get("subject") - target = rel.get("target") or rel.get("object") - rel_type = rel.get("type") or rel.get("predicate") - - key = f"{source}::{rel_type}::{target}" - if key not in relationship_map: - relationship_map[key] = [] - relationship_map[key].append(rel) - - # Check for relationship conflicts - for key, rels in relationship_map.items(): - if len(rels) > 1: - # Check for conflicting properties - properties = {} - for rel in rels: - for prop_name, prop_value in rel.items(): - if prop_name in [ - "source", - "target", - "subject", - "object", - "type", - "predicate", - ]: - continue - if prop_name not in properties: - properties[prop_name] = [] - properties[prop_name].append(prop_value) - - for prop_name, values in properties.items(): - unique_values = {str(v) for v in values if v is not None} - if len(unique_values) > 1: - conflicts.append( - { - "relationship": key, - "property": prop_name, - "conflicting_values": list(unique_values), - "type": "relationship_conflict", - "sources": [ - rel.get("source", "unknown") for rel in rels - ], - } - ) - - self.logger.info(f"Detected {len(conflicts)} conflicts") - self.progress_tracker.stop_tracking( - tracking_id, - status="completed", - message=f"Detected {len(conflicts)} conflicts", - ) - return conflicts - - except Exception as e: - self.progress_tracker.stop_tracking( - tracking_id, status="failed", message=str(e) - ) - raise - - def resolve_conflicts( - self, conflicts: List[Dict[str, Any]], strategy: str = "highest_confidence" - ) -> Dict[str, Any]: - """ - Resolve detected conflicts. - - This method attempts to resolve conflicts using the configured conflict - resolver with the specified strategy. Converts conflict dictionaries - to Conflict objects for resolution. - - Args: - conflicts: List of conflict dictionaries from detect_conflicts() - strategy: Resolution strategy to use (default: "highest_confidence") - - Returns: - dict: Resolution results containing: - - resolved: List of successfully resolved conflicts with resolutions - - unresolved: List of conflicts that could not be resolved - - total: Total number of conflicts - - resolved_count: Number of resolved conflicts - - unresolved_count: Number of unresolved conflicts - """ - self.logger.info(f"Resolving {len(conflicts)} conflicts") - - resolved = [] - unresolved = [] - - for conflict in conflicts: - try: - # Convert to Conflict object for resolver - conflict_obj = Conflict( - conflict_id=conflict.get("entity_id") - or conflict.get("relationship", "unknown"), - conflict_type=conflict.get("type", "value_conflict"), - entity_id=conflict.get("entity_id"), - property_name=conflict.get("property"), - conflicting_values=conflict.get("conflicting_values", []), - sources=[{"source": s} for s in conflict.get("sources", [])], - ) - - # Resolve conflict - resolution = self.resolver.resolve_conflict( - conflict_obj, strategy=strategy - ) - - if resolution.resolved: - resolved.append( - { - "conflict": conflict, - "resolution": resolution.resolved_value, - "strategy": resolution.resolution_strategy, - } - ) - else: - unresolved.append(conflict) - - except Exception as e: - self.logger.error(f"Error resolving conflict: {e}") - unresolved.append(conflict) - - return { - "resolved": resolved, - "unresolved": unresolved, - "total": len(conflicts), - "resolved_count": len(resolved), - "unresolved_count": len(unresolved), - } diff --git a/semantica/kg/deduplicator.py b/semantica/kg/deduplicator.py deleted file mode 100644 index f30bc11f..00000000 --- a/semantica/kg/deduplicator.py +++ /dev/null @@ -1,175 +0,0 @@ -""" -Deduplication Module - -This module provides comprehensive duplicate detection and merging capabilities -for the Semantica framework, enabling identification and resolution of duplicate -entities and relationships in knowledge graphs. - -Key Features: - - Duplicate entity detection using similarity metrics - - Duplicate group identification - - Entity merging with configurable strategies - - Relationship deduplication - - Provenance tracking for merged entities - -Main Classes: - - Deduplicator: Main deduplication engine - -Example Usage: - >>> from semantica.kg import Deduplicator - >>> deduplicator = Deduplicator() - >>> duplicate_groups = deduplicator.find_duplicates(entities) - >>> merged_entities = deduplicator.merge_duplicates(duplicate_groups) - -Author: Semantica Contributors -License: MIT -""" - -from typing import Any, Dict, List, Optional - -from ..deduplication.duplicate_detector import DuplicateDetector, DuplicateGroup -from ..deduplication.entity_merger import EntityMerger -from ..utils.logging import get_logger -from ..utils.progress_tracker import get_progress_tracker - - -class Deduplicator: - """ - Deduplication engine. - - This class provides duplicate detection and merging capabilities for - knowledge graphs, using the deduplication module's duplicate detector - and entity merger components. - - Features: - - Duplicate entity detection with similarity metrics - - Duplicate group identification - - Entity merging with configurable strategies - - Provenance tracking for merged entities - - Example Usage: - >>> deduplicator = Deduplicator() - >>> duplicate_groups = deduplicator.find_duplicates(entities) - >>> merged_entities = deduplicator.merge_duplicates(duplicate_groups) - """ - - def __init__(self, **config): - """ - Initialize deduplicator. - - Sets up the deduplicator with duplicate detector and entity merger - components from the deduplication module. - - Args: - **config: Configuration options: - - detection: Configuration for duplicate detection (optional) - - merger: Configuration for entity merging (optional) - """ - self.logger = get_logger("deduplicator") - self.config = config - - # Initialize progress tracker - self.progress_tracker = get_progress_tracker() - - # Initialize deduplication components - self.duplicate_detector = DuplicateDetector(**config.get("detection", {})) - self.entity_merger = EntityMerger(**config.get("merger", {})) - - self.logger.debug("Deduplicator initialized") - - def find_duplicates( - self, entities: List[Dict[str, Any]] - ) -> List[List[Dict[str, Any]]]: - """ - Find duplicate entities. - - This method detects duplicate entities using similarity metrics and - groups them into duplicate groups. Uses the duplicate detector from - the deduplication module. - - Args: - entities: List of entity dictionaries to check for duplicates - - Returns: - list: List of duplicate groups, where each group is a list of - duplicate entity dictionaries (groups with 2+ entities) - """ - self.logger.info(f"Finding duplicates in {len(entities)} entities") - - # Track deduplication - tracking_id = self.progress_tracker.start_tracking( - file=None, - module="kg", - submodule="Deduplicator", - message="Finding duplicates", - ) - - try: - # Detect duplicate groups - duplicate_groups = self.duplicate_detector.detect_duplicate_groups( - entities, **self.config - ) - - # Convert to list of lists - result = [] - for group in duplicate_groups: - if len(group.entities) >= 2: - result.append(group.entities) - - self.logger.info(f"Found {len(result)} duplicate groups") - self.progress_tracker.stop_tracking( - tracking_id, - status="completed", - message=f"Found {len(result)} duplicate groups", - ) - return result - - except Exception as e: - self.progress_tracker.stop_tracking( - tracking_id, status="failed", message=str(e) - ) - raise - - def merge_duplicates( - self, duplicate_groups: List[List[Dict[str, Any]]] - ) -> List[Dict[str, Any]]: - """ - Merge duplicate entities. - - This method merges groups of duplicate entities using the entity merger - from the deduplication module. Each group is merged into a single entity - with merged properties and provenance tracking. - - Args: - duplicate_groups: List of duplicate groups (each group is a list - of duplicate entity dictionaries) - - Returns: - list: List of merged entity dictionaries (one per duplicate group) - """ - self.logger.info(f"Merging {len(duplicate_groups)} duplicate groups") - - merged_entities = [] - processed_ids = set() - - for group in duplicate_groups: - if len(group) < 2: - continue - - # Merge the group - merge_operations = self.entity_merger.merge_duplicates(group, **self.config) - - for operation in merge_operations: - merged_entity = operation.merged_entity - merged_entities.append(merged_entity) - - # Mark source entities as processed - for source_entity in operation.source_entities: - entity_id = source_entity.get("id") or source_entity.get( - "entity_id" - ) - if entity_id: - processed_ids.add(entity_id) - - self.logger.info(f"Merged to {len(merged_entities)} entities") - return merged_entities diff --git a/semantica/kg/kg_usage.md b/semantica/kg/kg_usage.md index 8eae8118..b435a6b7 100644 --- a/semantica/kg/kg_usage.md +++ b/semantica/kg/kg_usage.md @@ -1,6 +1,9 @@ # Knowledge Graph Module Usage Guide -This guide demonstrates how to use the knowledge graph module for building, analyzing, validating, and managing knowledge graphs, including temporal knowledge graphs, entity resolution, conflict detection, and graph analytics. +This guide demonstrates how to use the knowledge graph module for building, analyzing, validating, and managing knowledge graphs, including temporal knowledge graphs, entity resolution, and graph analytics. + +Note: For conflict detection and resolution, use the `semantica.conflicts` module. +For deduplication, use the `semantica.deduplication` module. ## Table of Contents @@ -9,48 +12,18 @@ This guide demonstrates how to use the knowledge graph module for building, anal 3. [Graph Analysis](#graph-analysis) 4. [Entity Resolution](#entity-resolution) 5. [Graph Validation](#graph-validation) -6. [Conflict Detection](#conflict-detection) -7. [Centrality Calculation](#centrality-calculation) -8. [Community Detection](#community-detection) -9. [Connectivity Analysis](#connectivity-analysis) -10. [Deduplication](#deduplication) -11. [Temporal Queries](#temporal-queries) -12. [Provenance Tracking](#provenance-tracking) -13. [Using Methods](#using-methods) -14. [Using Registry](#using-registry) -15. [Configuration](#configuration) -16. [Advanced Examples](#advanced-examples) +6. [Centrality Calculation](#centrality-calculation) +7. [Community Detection](#community-detection) +8. [Connectivity Analysis](#connectivity-analysis) +9. [Temporal Queries](#temporal-queries) +10. [Provenance Tracking](#provenance-tracking) +11. [Using Methods](#using-methods) +12. [Using Registry](#using-registry) +13. [Configuration](#configuration) +14. [Advanced Examples](#advanced-examples) ## Basic Usage -### Using the Convenience Function - -```python -from semantica.kg import build - -# Build knowledge graph from sources -sources = [ - { - "entities": [ - {"id": "1", "name": "Alice", "type": "Person"}, - {"id": "2", "name": "Bob", "type": "Person"} - ], - "relationships": [ - {"source": "1", "target": "2", "type": "knows"} - ] - } -] - -kg = build( - sources=sources, - merge_entities=True, - resolve_conflicts=True -) - -print(f"Built graph with {kg['metadata']['num_entities']} entities") -print(f"Relationships: {kg['metadata']['num_relationships']}") -``` - ### Using Main Classes ```python @@ -76,17 +49,9 @@ analysis = analyzer.analyze_graph(kg) ### Basic Graph Building ```python -from semantica.kg import build_kg, GraphBuilder +from semantica.kg import GraphBuilder -# Using convenience function -kg = build_kg( - sources=sources, - method="default", - merge_entities=True, - resolve_conflicts=True -) - -# Using class directly +# Create graph builder builder = GraphBuilder( merge_entities=True, entity_resolution_strategy="fuzzy", @@ -94,24 +59,25 @@ builder = GraphBuilder( enable_temporal=False ) +# Build knowledge graph kg = builder.build(sources) ``` ### Temporal Knowledge Graph Building ```python -from semantica.kg import build_kg +from semantica.kg import GraphBuilder # Build temporal knowledge graph -temporal_kg = build_kg( - sources=sources, - method="temporal", +builder = GraphBuilder( enable_temporal=True, temporal_granularity="day", track_history=True, version_snapshots=True ) +temporal_kg = builder.build(sources) + # Access temporal information for rel in temporal_kg["relationships"]: if "valid_from" in rel: @@ -134,19 +100,23 @@ new_sources = [{"entities": [...], "relationships": [...]}] updated_kg = builder.build(new_sources) ``` -### Using Build Methods +### Building with Different Configurations ```python -from semantica.kg.methods import build_kg +from semantica.kg import GraphBuilder # Default building -kg = build_kg(sources, method="default") +builder = GraphBuilder() +kg = builder.build(sources) # Temporal building -temporal_kg = build_kg(sources, method="temporal", enable_temporal=True) +temporal_builder = GraphBuilder(enable_temporal=True) +temporal_kg = temporal_builder.build(sources) -# Incremental building -kg = build_kg(sources, method="incremental") +# Incremental building (same builder, multiple calls) +builder = GraphBuilder(merge_entities=True) +kg1 = builder.build(initial_sources) +kg2 = builder.build(additional_sources) ``` ## Graph Analysis @@ -154,68 +124,74 @@ kg = build_kg(sources, method="incremental") ### Comprehensive Analysis ```python -from semantica.kg import analyze_graph, GraphAnalyzer +from semantica.kg import GraphAnalyzer -# Using convenience function -analysis = analyze_graph(kg, method="default") +# Create analyzer and analyze graph +analyzer = GraphAnalyzer() +analysis = analyzer.analyze_graph(kg) print(f"Nodes: {analysis['num_nodes']}") print(f"Edges: {analysis['num_edges']}") print(f"Density: {analysis['density']}") - -# Using class directly -analyzer = GraphAnalyzer() -analysis = analyzer.analyze_graph(kg) ``` ### Centrality-Focused Analysis ```python -from semantica.kg import analyze_graph +from semantica.kg import GraphAnalyzer, CentralityCalculator -# Focus on centrality metrics -analysis = analyze_graph(kg, method="centrality") +# Analyze graph with centrality focus +analyzer = GraphAnalyzer() +analysis = analyzer.analyze_graph(kg) + +# Calculate centrality separately +centrality_calc = CentralityCalculator() +degree_centrality = centrality_calc.calculate_degree_centrality(kg) # Access centrality results -if "centrality" in analysis: - degree_centrality = analysis["centrality"].get("degree", {}) +if "rankings" in degree_centrality: print("Top nodes by degree centrality:") - for node, score in sorted(degree_centrality.items(), key=lambda x: x[1], reverse=True)[:5]: - print(f" {node}: {score}") + for ranking in degree_centrality["rankings"][:5]: + print(f" {ranking['node']}: {ranking['score']}") ``` ### Community-Focused Analysis ```python -from semantica.kg import analyze_graph +from semantica.kg import CommunityDetector -# Focus on community detection -analysis = analyze_graph(kg, method="community") +# Detect communities +detector = CommunityDetector() +result = detector.detect_communities(kg, algorithm="louvain") # Access community results -if "communities" in analysis: - communities = analysis["communities"] +if "communities" in result: + communities = result["communities"] print(f"Found {len(communities)} communities") for i, community in enumerate(communities): print(f"Community {i}: {len(community)} nodes") ``` -### Using Analysis Methods +### Different Types of Analysis ```python -from semantica.kg.methods import analyze_graph +from semantica.kg import GraphAnalyzer, CentralityCalculator, CommunityDetector, ConnectivityAnalyzer -# Default analysis -analysis = analyze_graph(kg, method="default") +# Default comprehensive analysis +analyzer = GraphAnalyzer() +analysis = analyzer.analyze_graph(kg) # Centrality analysis -analysis = analyze_graph(kg, method="centrality") +centrality_calc = CentralityCalculator() +centrality = centrality_calc.calculate_all_centrality(kg) # Community analysis -analysis = analyze_graph(kg, method="community") +community_detector = CommunityDetector() +communities = community_detector.detect_communities(kg, algorithm="louvain") # Connectivity analysis -analysis = analyze_graph(kg, method="connectivity") +connectivity_analyzer = ConnectivityAnalyzer() +connectivity = connectivity_analyzer.analyze_connectivity(kg) ``` ## Entity Resolution @@ -223,56 +199,58 @@ analysis = analyze_graph(kg, method="connectivity") ### Fuzzy Matching Resolution ```python -from semantica.kg import resolve_entities, EntityResolver +from semantica.kg import EntityResolver -# Using convenience function entities = [ {"id": "1", "name": "Apple Inc.", "type": "Company"}, {"id": "2", "name": "Apple", "type": "Company"}, {"id": "3", "name": "Microsoft", "type": "Company"} ] -resolved = resolve_entities(entities, method="fuzzy", similarity_threshold=0.8) +# Create resolver with fuzzy strategy +resolver = EntityResolver(strategy="fuzzy", similarity_threshold=0.8) +resolved = resolver.resolve_entities(entities) print(f"Original: {len(entities)} entities") print(f"Resolved: {len(resolved)} entities") - -# Using class directly -resolver = EntityResolver(strategy="fuzzy", similarity_threshold=0.8) -resolved = resolver.resolve_entities(entities) ``` ### Exact Matching Resolution ```python -from semantica.kg import resolve_entities +from semantica.kg import EntityResolver # Exact string matching -resolved = resolve_entities(entities, method="exact") +resolver = EntityResolver(strategy="exact") +resolved = resolver.resolve_entities(entities) ``` ### Semantic Matching Resolution ```python -from semantica.kg import resolve_entities +from semantica.kg import EntityResolver # Semantic similarity matching -resolved = resolve_entities(entities, method="semantic", similarity_threshold=0.9) +resolver = EntityResolver(strategy="semantic", similarity_threshold=0.9) +resolved = resolver.resolve_entities(entities) ``` -### Using Resolution Methods +### Different Resolution Strategies ```python -from semantica.kg.methods import resolve_entities +from semantica.kg import EntityResolver # Fuzzy matching -resolved = resolve_entities(entities, method="fuzzy") +fuzzy_resolver = EntityResolver(strategy="fuzzy", similarity_threshold=0.8) +fuzzy_resolved = fuzzy_resolver.resolve_entities(entities) # Exact matching -resolved = resolve_entities(entities, method="exact") +exact_resolver = EntityResolver(strategy="exact") +exact_resolved = exact_resolver.resolve_entities(entities) # Semantic matching -resolved = resolve_entities(entities, method="semantic") +semantic_resolver = EntityResolver(strategy="semantic", similarity_threshold=0.9) +semantic_resolved = semantic_resolver.resolve_entities(entities) ``` ## Graph Validation @@ -280,10 +258,11 @@ resolved = resolve_entities(entities, method="semantic") ### Comprehensive Validation ```python -from semantica.kg import validate_graph, GraphValidator +from semantica.kg import GraphValidator -# Using convenience function -result = validate_graph(kg, method="default") +# Create validator and validate graph +validator = GraphValidator() +result = validator.validate(kg) if result.valid: print("Graph is valid!") @@ -295,146 +274,70 @@ else: print(f"Found {len(result.warnings)} warnings:") for warning in result.warnings: print(f" - {warning}") - -# Using class directly -validator = GraphValidator() -result = validator.validate(kg) ``` ### Structure-Only Validation ```python -from semantica.kg import validate_graph +from semantica.kg import GraphValidator # Validate structure only -result = validate_graph(kg, method="structure") +validator = GraphValidator() +result = validator.validate(kg) # Full validation includes structure ``` ### Consistency Checking ```python -from semantica.kg import validate_graph, GraphValidator +from semantica.kg import GraphValidator # Check consistency only -is_consistent = validate_graph(kg, method="consistency") - -# Using class directly validator = GraphValidator() is_consistent = validator.check_consistency(kg) ``` -### Using Validation Methods +### Different Validation Approaches ```python -from semantica.kg.methods import validate_graph +from semantica.kg import GraphValidator -# Default validation -result = validate_graph(kg, method="default") +validator = GraphValidator() -# Structure validation -result = validate_graph(kg, method="structure") +# Full validation (includes structure and consistency) +full_result = validator.validate(kg) -# Consistency check -is_consistent = validate_graph(kg, method="consistency") +# Consistency check only +is_consistent = validator.check_consistency(kg) ``` -## Conflict Detection - -### Comprehensive Conflict Detection - -```python -from semantica.kg import detect_conflicts, ConflictDetector - -# Using convenience function -conflicts = detect_conflicts(kg, method="default") - -print(f"Found {len(conflicts)} conflicts") -for conflict in conflicts: - print(f"Type: {conflict['type']}") - print(f"Property: {conflict['property']}") - print(f"Conflicting values: {conflict['conflicting_values']}") - -# Using class directly -detector = ConflictDetector() -conflicts = detector.detect_conflicts(kg) -``` - -### Value Conflict Detection - -```python -from semantica.kg import detect_conflicts - -# Detect value conflicts only -value_conflicts = detect_conflicts(kg, method="value") -``` - -### Relationship Conflict Detection - -```python -from semantica.kg import detect_conflicts - -# Detect relationship conflicts only -rel_conflicts = detect_conflicts(kg, method="relationship") -``` - -### Conflict Resolution - -```python -from semantica.kg import ConflictDetector - -detector = ConflictDetector() - -# Detect conflicts -conflicts = detector.detect_conflicts(kg) - -# Resolve conflicts -resolution = detector.resolve_conflicts(conflicts, strategy="highest_confidence") - -print(f"Resolved: {resolution['resolved_count']}") -print(f"Unresolved: {resolution['unresolved_count']}") -``` - -### Using Conflict Detection Methods - -```python -from semantica.kg.methods import detect_conflicts - -# Default detection -conflicts = detect_conflicts(kg, method="default") - -# Value conflicts -conflicts = detect_conflicts(kg, method="value") - -# Relationship conflicts -conflicts = detect_conflicts(kg, method="relationship") -``` +!!! note "Conflict Detection and Resolution" + Conflict detection and resolution have been moved to the dedicated `semantica.conflicts` module. + Please use `semantica.conflicts.ConflictDetector` and `semantica.conflicts.ConflictResolver` for these tasks. ## Centrality Calculation ### Degree Centrality ```python -from semantica.kg import calculate_centrality, CentralityCalculator +from semantica.kg import CentralityCalculator -# Using convenience function -result = calculate_centrality(kg, method="degree") +# Calculate degree centrality +calculator = CentralityCalculator() +result = calculator.calculate_degree_centrality(kg) print("Top nodes by degree centrality:") for ranking in result["rankings"][:5]: print(f" {ranking['node']}: {ranking['score']}") - -# Using class directly -calculator = CentralityCalculator() -result = calculator.calculate_degree_centrality(kg) ``` ### Betweenness Centrality ```python -from semantica.kg import calculate_centrality +from semantica.kg import CentralityCalculator # Calculate betweenness centrality -result = calculate_centrality(kg, method="betweenness") +calculator = CentralityCalculator() +result = calculator.calculate_betweenness_centrality(kg) print("Top nodes by betweenness centrality:") for ranking in result["rankings"][:5]: @@ -444,10 +347,11 @@ for ranking in result["rankings"][:5]: ### Closeness Centrality ```python -from semantica.kg import calculate_centrality +from semantica.kg import CentralityCalculator # Calculate closeness centrality -result = calculate_centrality(kg, method="closeness") +calculator = CentralityCalculator() +result = calculator.calculate_closeness_centrality(kg) print("Top nodes by closeness centrality:") for ranking in result["rankings"][:5]: @@ -457,10 +361,11 @@ for ranking in result["rankings"][:5]: ### Eigenvector Centrality ```python -from semantica.kg import calculate_centrality +from semantica.kg import CentralityCalculator # Calculate eigenvector centrality -result = calculate_centrality(kg, method="eigenvector") +calculator = CentralityCalculator() +result = calculator.calculate_eigenvector_centrality(kg) print("Top nodes by eigenvector centrality:") for ranking in result["rankings"][:5]: @@ -470,10 +375,11 @@ for ranking in result["rankings"][:5]: ### All Centrality Measures ```python -from semantica.kg import calculate_centrality +from semantica.kg import CentralityCalculator # Calculate all centrality measures -result = calculate_centrality(kg, method="all") +calculator = CentralityCalculator() +result = calculator.calculate_all_centrality(kg) for measure_type, measure_result in result["centrality_measures"].items(): print(f"\n{measure_type.upper()} Centrality:") @@ -481,25 +387,27 @@ for measure_type, measure_result in result["centrality_measures"].items(): print(f" {ranking['node']}: {ranking['score']}") ``` -### Using Centrality Methods +### Different Centrality Measures ```python -from semantica.kg.methods import calculate_centrality +from semantica.kg import CentralityCalculator + +calculator = CentralityCalculator() # Degree centrality -degree = calculate_centrality(kg, method="degree") +degree = calculator.calculate_degree_centrality(kg) # Betweenness centrality -betweenness = calculate_centrality(kg, method="betweenness") +betweenness = calculator.calculate_betweenness_centrality(kg) # Closeness centrality -closeness = calculate_centrality(kg, method="closeness") +closeness = calculator.calculate_closeness_centrality(kg) # Eigenvector centrality -eigenvector = calculate_centrality(kg, method="eigenvector") +eigenvector = calculator.calculate_eigenvector_centrality(kg) -# All measures -all_centrality = calculate_centrality(kg, method="all") +# All measures at once +all_centrality = calculator.calculate_all_centrality(kg) ``` ## Community Detection @@ -507,29 +415,27 @@ all_centrality = calculate_centrality(kg, method="all") ### Louvain Algorithm ```python -from semantica.kg import detect_communities, CommunityDetector +from semantica.kg import CommunityDetector -# Using convenience function -result = detect_communities(kg, method="louvain") +# Detect communities using Louvain algorithm +detector = CommunityDetector() +result = detector.detect_communities(kg, algorithm="louvain") print(f"Found {len(result['communities'])} communities") print(f"Modularity: {result['modularity']}") for i, community in enumerate(result["communities"]): print(f"Community {i}: {len(community)} nodes") - -# Using class directly -detector = CommunityDetector() -result = detector.detect_communities(kg, algorithm="louvain") ``` ### Leiden Algorithm ```python -from semantica.kg import detect_communities +from semantica.kg import CommunityDetector # Detect communities using Leiden algorithm -result = detect_communities(kg, method="leiden", resolution=1.0) +detector = CommunityDetector() +result = detector.detect_communities(kg, algorithm="leiden", resolution=1.0) print(f"Found {len(result['communities'])} communities") ``` @@ -537,10 +443,11 @@ print(f"Found {len(result['communities'])} communities") ### Overlapping Communities ```python -from semantica.kg import detect_communities +from semantica.kg import CommunityDetector # Detect overlapping communities -result = detect_communities(kg, method="overlapping", k=3) +detector = CommunityDetector() +result = detector.detect_communities(kg, algorithm="overlapping", k=3) print(f"Found {len(result['communities'])} overlapping communities") print(f"Nodes in multiple communities: {result.get('overlap_count', 0)}") @@ -567,19 +474,21 @@ print(f"Intra-community edges: {structure['intra_community_edges']}") print(f"Inter-community edges: {structure['inter_community_edges']}") ``` -### Using Community Detection Methods +### Different Community Detection Algorithms ```python -from semantica.kg.methods import detect_communities +from semantica.kg import CommunityDetector + +detector = CommunityDetector() # Louvain algorithm -communities = detect_communities(kg, method="louvain") +louvain_result = detector.detect_communities(kg, algorithm="louvain") # Leiden algorithm -communities = detect_communities(kg, method="leiden") +leiden_result = detector.detect_communities(kg, algorithm="leiden") # Overlapping communities -communities = detect_communities(kg, method="overlapping", k=3) +overlapping_result = detector.detect_communities(kg, algorithm="overlapping", k=3) ``` ## Connectivity Analysis @@ -652,117 +561,55 @@ for bridge in result["bridge_edges"]: print(f"Bridge: {bridge['source']} -> {bridge['target']}") ``` -### Using Connectivity Methods +### Different Connectivity Analysis Types ```python -from semantica.kg.methods import analyze_connectivity +from semantica.kg import ConnectivityAnalyzer -# Default analysis -connectivity = analyze_connectivity(kg, method="default") +analyzer = ConnectivityAnalyzer() + +# Default comprehensive analysis +connectivity = analyzer.analyze_connectivity(kg) # Components only -components = analyze_connectivity(kg, method="components") +components = analyzer.find_connected_components(kg) # Path finding -paths = analyze_connectivity(kg, method="paths", source="A", target="B") +paths = analyzer.calculate_shortest_paths(kg, source="A", target="B") # Bridge detection -bridges = analyze_connectivity(kg, method="bridges") +bridges = analyzer.identify_bridges(kg) ``` -## Deduplication - -### Entity Deduplication - -```python -from semantica.kg import deduplicate_graph, Deduplicator - -# Using convenience function -deduplicated = deduplicate_graph(kg, method="entities") - -print(f"Original entities: {len(kg['entities'])}") -print(f"Deduplicated entities: {len(deduplicated['entities'])}") - -# Using class directly -deduplicator = Deduplicator() -duplicate_groups = deduplicator.find_duplicates(kg["entities"]) -merged_entities = deduplicator.merge_duplicates(duplicate_groups) -``` - -### Finding Duplicates - -```python -from semantica.kg import Deduplicator - -deduplicator = Deduplicator() - -# Find duplicate groups -duplicate_groups = deduplicator.find_duplicates(kg["entities"]) - -print(f"Found {len(duplicate_groups)} duplicate groups") -for i, group in enumerate(duplicate_groups): - print(f"Group {i}: {len(group)} duplicate entities") -``` - -### Merging Duplicates - -```python -from semantica.kg import Deduplicator - -deduplicator = Deduplicator() - -# Find and merge duplicates -duplicate_groups = deduplicator.find_duplicates(kg["entities"]) -merged_entities = deduplicator.merge_duplicates(duplicate_groups) - -print(f"Merged {len(duplicate_groups)} groups into {len(merged_entities)} entities") -``` - -### Using Deduplication Methods - -```python -from semantica.kg.methods import deduplicate_graph - -# Default deduplication -deduplicated = deduplicate_graph(kg, method="default") - -# Entity deduplication only -deduplicated = deduplicate_graph(kg, method="entities") -``` +!!! note "Deduplication" + Deduplication has been moved to the dedicated `semantica.deduplication` module. + Please use `semantica.deduplication.DuplicateDetector` and `semantica.deduplication.EntityMerger` for these tasks. ## Temporal Queries ### Time-Point Queries ```python -from semantica.kg import query_temporal, TemporalGraphQuery +from semantica.kg import TemporalGraphQuery -# Using convenience function -result = query_temporal( - kg, - query="", - method="time_point", - at_time="2024-01-01" -) +# Create query engine and query at specific time +query_engine = TemporalGraphQuery() +result = query_engine.query_at_time(kg, query="", at_time="2024-01-01") print(f"Entities at time: {result['num_entities']}") print(f"Relationships at time: {result['num_relationships']}") - -# Using class directly -query_engine = TemporalGraphQuery() -result = query_engine.query_at_time(kg, "", at_time="2024-01-01") ``` ### Time-Range Queries ```python -from semantica.kg import query_temporal +from semantica.kg import TemporalGraphQuery # Query within time range -result = query_temporal( +query_engine = TemporalGraphQuery() +result = query_engine.query_time_range( kg, query="", - method="time_range", start_time="2024-01-01", end_time="2024-12-31", temporal_aggregation="union" @@ -774,16 +621,11 @@ print(f"Relationships in range: {result['num_relationships']}") ### Temporal Pattern Detection ```python -from semantica.kg import query_temporal +from semantica.kg import TemporalGraphQuery # Detect temporal patterns -result = query_temporal( - kg, - query="", - method="pattern", - pattern="sequence", - min_support=2 -) +query_engine = TemporalGraphQuery() +result = query_engine.query_temporal_pattern(kg, pattern="sequence", min_support=2) print(f"Found {result['num_patterns']} temporal patterns") ``` @@ -791,13 +633,12 @@ print(f"Found {result['num_patterns']} temporal patterns") ### Graph Evolution Analysis ```python -from semantica.kg import query_temporal +from semantica.kg import TemporalGraphQuery # Analyze graph evolution -result = query_temporal( +query_engine = TemporalGraphQuery() +result = query_engine.analyze_evolution( kg, - query="", - method="evolution", start_time="2024-01-01", end_time="2024-12-31", metrics=["count", "diversity", "stability"] @@ -830,22 +671,24 @@ for path in paths["paths"]: print(f"Length: {path['length']}") ``` -### Using Temporal Query Methods +### Different Temporal Query Types ```python -from semantica.kg.methods import query_temporal +from semantica.kg import TemporalGraphQuery + +query_engine = TemporalGraphQuery() # Time-point query -result = query_temporal(kg, at_time="2024-01-01", method="time_point") +result = query_engine.query_at_time(kg, query="", at_time="2024-01-01") # Time-range query -result = query_temporal(kg, start_time="2024-01-01", end_time="2024-12-31", method="time_range") +result = query_engine.query_time_range(kg, query="", start_time="2024-01-01", end_time="2024-12-31") # Pattern detection -result = query_temporal(kg, pattern="sequence", method="pattern") +result = query_engine.query_temporal_pattern(kg, pattern="sequence") # Evolution analysis -result = query_temporal(kg, method="evolution") +result = query_engine.analyze_evolution(kg) ``` ## Provenance Tracking @@ -1078,88 +921,86 @@ kg_config = KGConfig(config_file="config.yaml") ```python from semantica.kg import ( - build_kg, - resolve_entities, - validate_graph, - detect_conflicts, - analyze_graph, - calculate_centrality, - detect_communities + GraphBuilder, + EntityResolver, + GraphValidator, + GraphAnalyzer, + CentralityCalculator, + CommunityDetector ) # 1. Build knowledge graph -kg = build_kg(sources, method="default") +builder = GraphBuilder(merge_entities=True) +kg = builder.build(sources) # 2. Resolve entities +resolver = EntityResolver(strategy="fuzzy", similarity_threshold=0.8) entities = kg["entities"] -resolved_entities = resolve_entities(entities, method="fuzzy") +resolved_entities = resolver.resolve_entities(entities) kg["entities"] = resolved_entities # 3. Validate graph -validation = validate_graph(kg, method="default") +validator = GraphValidator() +validation = validator.validate(kg) if not validation.valid: print("Validation errors:", validation.errors) return -# 4. Detect conflicts -conflicts = detect_conflicts(kg, method="default") -if conflicts: - print(f"Found {len(conflicts)} conflicts") - # Resolve conflicts... - -# 5. Analyze graph -analysis = analyze_graph(kg, method="default") +# 4. Analyze graph +analyzer = GraphAnalyzer() +analysis = analyzer.analyze_graph(kg) print(f"Graph density: {analysis['density']}") print(f"Average degree: {analysis['avg_degree']}") -# 6. Calculate centrality -centrality = calculate_centrality(kg, method="degree") +# 5. Calculate centrality +centrality_calc = CentralityCalculator() +degree_centrality = centrality_calc.calculate_degree_centrality(kg) print("Top 5 nodes by degree:") -for ranking in centrality["rankings"][:5]: +for ranking in degree_centrality["rankings"][:5]: print(f" {ranking['node']}: {ranking['score']}") -# 7. Detect communities -communities = detect_communities(kg, method="louvain") -print(f"Found {len(communities['communities'])} communities") +# 6. Detect communities +community_detector = CommunityDetector() +communities_result = community_detector.detect_communities(kg, algorithm="louvain") +print(f"Found {len(communities_result['communities'])} communities") ``` ### Temporal Knowledge Graph Workflow ```python from semantica.kg import ( - build_kg, - query_temporal, + GraphBuilder, + TemporalGraphQuery, TemporalVersionManager ) # Build temporal knowledge graph -temporal_kg = build_kg( - sources, - method="temporal", +builder = GraphBuilder( enable_temporal=True, temporal_granularity="day", track_history=True ) +temporal_kg = builder.build(sources) # Query at specific time point -result = query_temporal( +query_engine = TemporalGraphQuery() +result = query_engine.query_at_time( temporal_kg, - method="time_point", + query="", at_time="2024-06-15" ) # Query time range -range_result = query_temporal( +range_result = query_engine.query_time_range( temporal_kg, - method="time_range", + query="", start_time="2024-01-01", end_time="2024-12-31" ) # Analyze evolution -evolution = query_temporal( +evolution = query_engine.analyze_evolution( temporal_kg, - method="evolution", start_time="2024-01-01", end_time="2024-12-31", metrics=["count", "diversity"] @@ -1202,47 +1043,19 @@ components = connectivity_analyzer.find_connected_components(kg) bridges = connectivity_analyzer.identify_bridges(kg) ``` -### Entity Resolution and Deduplication +### Entity Resolution ```python -from semantica.kg import ( - EntityResolver, - Deduplicator, - deduplicate_graph -) +from semantica.kg import EntityResolver # Entity resolution resolver = EntityResolver(strategy="fuzzy", similarity_threshold=0.8) resolved = resolver.resolve_entities(kg["entities"]) - -# Deduplication -deduplicator = Deduplicator() -duplicate_groups = deduplicator.find_duplicates(kg["entities"]) -merged_entities = deduplicator.merge_duplicates(duplicate_groups) - -# Or use convenience function -deduplicated_kg = deduplicate_graph(kg, method="entities") ``` -### Conflict Detection and Resolution - -```python -from semantica.kg import ConflictDetector - -detector = ConflictDetector() - -# Detect conflicts -conflicts = detector.detect_conflicts(kg) - -# Resolve conflicts -resolution = detector.resolve_conflicts(conflicts, strategy="highest_confidence") - -# Apply resolutions -for resolved_conflict in resolution["resolved"]: - conflict = resolved_conflict["conflict"] - resolved_value = resolved_conflict["resolution"] - # Apply resolution to graph... -``` +!!! note "Deduplication and Conflict Resolution" + For deduplication, use `semantica.deduplication.DuplicateDetector` and `semantica.deduplication.EntityMerger`. + For conflict detection and resolution, use `semantica.conflicts.ConflictDetector` and `semantica.conflicts.ConflictResolver`. This guide covers the main features and usage patterns of the knowledge graph module. For more detailed information, refer to the module documentation and API reference. diff --git a/semantica/kg/methods.py b/semantica/kg/methods.py index ee6b470c..f64f6246 100644 --- a/semantica/kg/methods.py +++ b/semantica/kg/methods.py @@ -133,15 +133,16 @@ Main Functions: - analyze_graph: Graph analysis wrapper - resolve_entities: Entity resolution wrapper - validate_graph: Graph validation wrapper - - detect_conflicts: Conflict detection wrapper - calculate_centrality: Centrality calculation wrapper - detect_communities: Community detection wrapper - analyze_connectivity: Connectivity analysis wrapper - - deduplicate_graph: Deduplication wrapper - query_temporal: Temporal query wrapper - get_kg_method: Get KG method by name - list_available_methods: List registered methods +Note: Conflict detection and deduplication have been moved to dedicated modules. + Use semantica.conflicts for conflict detection and semantica.deduplication for deduplication. + Example Usage: >>> from semantica.kg.methods import build_kg, analyze_graph, calculate_centrality >>> kg = build_kg(sources, method="default") @@ -156,9 +157,7 @@ from ..utils.logging import get_logger from .centrality_calculator import CentralityCalculator from .community_detector import CommunityDetector from .config import kg_config -from .conflict_detector import ConflictDetector from .connectivity_analyzer import ConnectivityAnalyzer -from .deduplicator import Deduplicator from .entity_resolver import EntityResolver from .graph_analyzer import GraphAnalyzer from .graph_builder import GraphBuilder @@ -365,53 +364,6 @@ def validate_graph(graph: Dict[str, Any], method: str = "default", **kwargs) -> raise -def detect_conflicts( - graph: Dict[str, Any], method: str = "default", **kwargs -) -> List[Dict[str, Any]]: - """ - Detect conflicts in knowledge graph (convenience function). - - This is a user-friendly wrapper that detects conflicts using the specified method. - - Args: - graph: Knowledge graph to analyze - method: Detection method (default: "default") - - "default": Comprehensive conflict detection - - "value": Value conflict detection only - - "relationship": Relationship conflict detection only - **kwargs: Additional options passed to ConflictDetector - - Returns: - List of conflict dictionaries - - Examples: - >>> from semantica.kg.methods import detect_conflicts - >>> conflicts = detect_conflicts(kg, method="default") - >>> value_conflicts = detect_conflicts(kg, method="value") - """ - # Check for custom method in registry - custom_method = method_registry.get("conflict", method) - if custom_method: - try: - return custom_method(graph, **kwargs) - except Exception as e: - logger.warning( - f"Custom method {method} failed: {e}, falling back to default" - ) - - try: - # Get config - config = kg_config.get_method_config("conflict") - config.update(kwargs) - - detector = ConflictDetector(**config) - return detector.detect_conflicts(graph) - - except Exception as e: - logger.error(f"Failed to detect conflicts: {e}") - raise - - def calculate_centrality( graph: Dict[str, Any], method: str = "degree", **kwargs ) -> Dict[str, Any]: @@ -582,78 +534,6 @@ def analyze_connectivity( raise -def deduplicate_graph( - graph: Dict[str, Any], method: str = "default", **kwargs -) -> Dict[str, Any]: - """ - Deduplicate knowledge graph (convenience function). - - This is a user-friendly wrapper that deduplicates a knowledge graph using the specified method. - - Args: - graph: Knowledge graph to deduplicate - method: Deduplication method (default: "default") - - "default": Default deduplication - - "entities": Entity deduplication only - - "relationships": Relationship deduplication only - **kwargs: Additional options passed to Deduplicator - - Returns: - Dictionary containing deduplicated graph - - Examples: - >>> from semantica.kg.methods import deduplicate_graph - >>> deduplicated = deduplicate_graph(kg, method="default") - >>> entity_dedup = deduplicate_graph(kg, method="entities") - """ - # Check for custom method in registry - custom_method = method_registry.get("deduplicate", method) - if custom_method: - try: - return custom_method(graph, **kwargs) - except Exception as e: - logger.warning( - f"Custom method {method} failed: {e}, falling back to default" - ) - - try: - # Get config - config = kg_config.get_method_config("deduplicate") - config.update(kwargs) - - deduplicator = Deduplicator(**config) - - entities = graph.get("entities", []) - relationships = graph.get("relationships", []) - - if method == "entities" or method == "default": - duplicate_groups = deduplicator.find_duplicates(entities) - merged_entities = deduplicator.merge_duplicates(duplicate_groups) - # Add non-duplicate entities (entities not in any duplicate group) - processed_ids = set() - for group in duplicate_groups: - for entity in group: - entity_id = entity.get("id") or entity.get("entity_id") - if entity_id: - processed_ids.add(entity_id) - # Add entities that weren't part of any duplicate group - for entity in entities: - entity_id = entity.get("id") or entity.get("entity_id") - if entity_id and entity_id not in processed_ids: - merged_entities.append(entity) - entities = merged_entities - - return { - "entities": entities, - "relationships": relationships, - "metadata": graph.get("metadata", {}), - } - - except Exception as e: - logger.error(f"Failed to deduplicate graph: {e}") - raise - - def query_temporal( graph: Dict[str, Any], query: str = "", method: str = "time_point", **kwargs ) -> Dict[str, Any]: diff --git a/semantica/kg/registry.py b/semantica/kg/registry.py index 2886eb1c..73cd23db 100644 --- a/semantica/kg/registry.py +++ b/semantica/kg/registry.py @@ -10,13 +10,14 @@ Supported Registration Types: * "analyze": Graph analysis methods * "resolve": Entity resolution methods * "validate": Graph validation methods - * "conflict": Conflict detection methods * "centrality": Centrality calculation methods * "community": Community detection methods * "connectivity": Connectivity analysis methods - * "deduplicate": Deduplication methods * "temporal": Temporal query methods +Note: Conflict detection and deduplication have been moved to dedicated modules. + Use semantica.conflicts for conflict detection and semantica.deduplication for deduplication. + Algorithms Used: - Registry Pattern: Dictionary-based registration and lookup - Dynamic Registration: Runtime function registration @@ -26,7 +27,7 @@ Algorithms Used: Key Features: - Method registry for custom KG methods - - Task-based method organization (build, analyze, resolve, validate, conflict, centrality, community, connectivity, deduplicate, temporal) + - Task-based method organization (build, analyze, resolve, validate, centrality, community, connectivity, temporal) - Dynamic registration and unregistration - Easy discovery of available methods - Support for community-contributed extensions @@ -54,11 +55,9 @@ class MethodRegistry: "analyze": {}, "resolve": {}, "validate": {}, - "conflict": {}, "centrality": {}, "community": {}, "connectivity": {}, - "deduplicate": {}, "temporal": {}, } @@ -68,7 +67,7 @@ class MethodRegistry: Register a custom KG method. Args: - task: Task type ("build", "analyze", "resolve", "validate", "conflict", "centrality", "community", "connectivity", "deduplicate", "temporal") + task: Task type ("build", "analyze", "resolve", "validate", "centrality", "community", "connectivity", "temporal") name: Method name method_func: Method function """ @@ -82,7 +81,7 @@ class MethodRegistry: Get method by task and name. Args: - task: Task type ("build", "analyze", "resolve", "validate", "conflict", "centrality", "community", "connectivity", "deduplicate", "temporal") + task: Task type ("build", "analyze", "resolve", "validate", "centrality", "community", "connectivity", "temporal") name: Method name Returns: