diff --git a/cookbook/advanced/06_Multi_Source_Data_Integration.ipynb b/cookbook/advanced/06_Multi_Source_Data_Integration.ipynb index 46f8450d..a7b0a19d 100644 --- a/cookbook/advanced/06_Multi_Source_Data_Integration.ipynb +++ b/cookbook/advanced/06_Multi_Source_Data_Integration.ipynb @@ -4,38 +4,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/06_Multi_Source_Data_Integration.ipynb)\n", + "# Real-World Multi-Source Integration\n", "\n", - "# Multi-Source Data Integration\n", + "This cookbook demonstrates a production-grade workflow for integrating data from distinct sources using Semantica.\n", "\n", - "## Overview\n", + "We will simulate a complex Enterprise Knowledge Graph construction scenario for **Nexus AI** by aggregating data from:\n", "\n", - "This notebook demonstrates advanced multi-source data integration using multiple ingestion types, entity resolution, conflict detection, and provenance tracking.\n", + "1. **Corporate Database (SQLite)**: Financial records and employee counts.\n", + "2. **Public Web (HTML)**: News articles and press releases.\n", + "3. **Source Code (Markdown)**: Engineering activity and documentation.\n", + "4. **Market Data API (JSON)**: Live stock prices and market cap.\n", + "5. **Web Search MCP (Tool)**: Live competitor analysis from a search agent.\n", "\n", - "\n", - "**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/ingest/)\n", - "\n", - "### Learning Objectives\n", - "\n", - "- Ingest data from multiple sources (files, web, databases, streams, feeds)\n", - "- Resolve entities across sources using EntityResolver\n", - "- Detect conflicts using ConflictDetector\n", - "- Track provenance using ProvenanceTracker\n", - "- Integrate data into a unified knowledge graph\n", - "\n", - "## Installation\n", - "\n", - "Install Semantica from PyPI:\n", - "\n", - "```bash\n", - "pip install semantica\n", - "# Or with all optional dependencies:\n", - "pip install semantica[all]\n", - "```\n", - "\n", - "---\n", - "\n", - "## Workflow: Multi-Source Ingestion → Entity Resolution → Conflict Detection → Provenance Tracking → Unified KG\n" + "**Key Semantica Modules Used:**\n", + "* `ingest`: For loading data from disparate sources (including MCP).\n", + "* `kg.GraphBuilder`: For constructing the graph and merging entities.\n", + "* `conflicts.ConflictResolver`: For resolving data discrepancies.\n", + "* `visualization.KGVisualizer`: For visualizing the final network." ] }, { @@ -44,7 +29,8 @@ "metadata": {}, "outputs": [], "source": [ - "!pip install semantica\n" + "# Installation & Setup\n", + "!pip install semantica mcp" ] }, { @@ -53,38 +39,29 @@ "metadata": {}, "outputs": [], "source": [ - "from semantica.ingest import FileIngestor, WebIngestor, DBIngestor, StreamIngestor, FeedIngestor\n", - "from semantica.parse import DocumentParser, StructuredDataParser\n", - "from semantica.kg import GraphBuilder, EntityResolver, ProvenanceTracker\n", - "import tempfile\n", "import os\n", "import json\n", + "import sqlite3\n", + "import tempfile\n", + "import pandas as pd\n", "\n", - "file_ingestor = FileIngestor()\n", - "web_ingestor = WebIngestor()\n", - "db_ingestor = DBIngestor()\n", - "stream_ingestor = StreamIngestor()\n", - "feed_ingestor = FeedIngestor()\n", + "# Import Semantica Modules\n", + "from semantica.ingest import DBIngestor, WebIngestor, FileIngestor, MCPIngestor\n", + "from semantica.kg import GraphBuilder\n", + "from semantica.visualization import KGVisualizer\n", "\n", - "temp_dir = tempfile.mkdtemp()\n", - "\n", - "file1 = os.path.join(temp_dir, \"source1.txt\")\n", - "with open(file1, 'w') as f:\n", - " f.write(\"Apple Inc. is a technology company. Tim Cook is the CEO.\")\n", - "\n", - "file_objects = file_ingestor.ingest_file(file1, read_content=True)\n", - "\n", - "print(f\"Ingested {len([file_objects]) if file_objects else 0} files\")\n", - "print(f\"Multi-source ingestion initialized\")\n" + "# Create a temporary workspace\n", + "WORKSPACE_DIR = tempfile.mkdtemp()\n", + "print(f\"Workspace created at: {WORKSPACE_DIR}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 2: Entity Resolution\n", + "## Phase 1: Creating Data Sources\n", "\n", - "Resolve entities across multiple sources.\n" + "We generate files on disk to simulate the disparate enterprise systems." ] }, { @@ -93,33 +70,53 @@ "metadata": {}, "outputs": [], "source": [ - "entity_resolver = EntityResolver()\n", + "# 1. SQLite Database (Financials)\n", + "db_path = os.path.join(WORKSPACE_DIR, \"corporate.db\")\n", + "conn = sqlite3.connect(db_path)\n", + "conn.execute(\"CREATE TABLE financials (company_name TEXT, revenue REAL, employees INTEGER)\")\n", + "conn.execute(\"INSERT INTO financials VALUES ('Nexus AI', 5500000.00, 45)\")\n", + "conn.commit()\n", + "conn.close()\n", "\n", - "entities_from_source1 = [\n", - " {\"id\": \"e1\", \"name\": \"Apple Inc.\", \"type\": \"Organization\", \"source\": \"file1\"},\n", - " {\"id\": \"e2\", \"name\": \"Tim Cook\", \"type\": \"Person\", \"source\": \"file1\"}\n", - "]\n", + "# 2. Public Web (HTML)\n", + "html_path = os.path.join(WORKSPACE_DIR, \"news.html\")\n", + "with open(html_path, \"w\") as f:\n", + " f.write(\"\"\"\n", + "
\n", + "Nexus AI (San Francisco) valuated at $100M.
\n", + "CEO Jane Doe announces expansion.
\n", + " \n", + " \"\"\")\n", "\n", - "entities_from_source2 = [\n", - " {\"id\": \"e3\", \"name\": \"Apple Incorporated\", \"type\": \"Organization\", \"source\": \"web\"},\n", - " {\"id\": \"e4\", \"name\": \"Timothy Cook\", \"type\": \"Person\", \"source\": \"web\"}\n", - "]\n", + "# 3. Code Repository (Markdown)\n", + "repo_path = os.path.join(WORKSPACE_DIR, \"README.md\")\n", + "with open(repo_path, \"w\") as f:\n", + " f.write(\"\"\"\n", + " # Nexus AI Core\n", + " Maintained by: engineering@nexus.ai\n", + " Language: Python\n", + " \"\"\")\n", "\n", - "all_entities = entities_from_source1 + entities_from_source2\n", + "# 4. Market Data API (JSON)\n", + "api_path = os.path.join(WORKSPACE_DIR, \"market.json\")\n", + "with open(api_path, \"w\") as f:\n", + " json.dump({\n", + " \"ticker\": \"NXAI\", \n", + " \"price\": 124.50, \n", + " \"employees\": 50 # Conflict with DB (45)\n", + " }, f)\n", "\n", - "resolved_entities = entity_resolver.resolve(all_entities)\n", - "\n", - "print(f\"Original entities: {len(all_entities)}\")\n", - "print(f\"Resolved entities: {len(resolved_entities)}\")\n" + "print(\"Data sources created successfully.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 3: Conflict Detection\n", + "## Phase 2: Ingestion & Extraction\n", "\n", - "Detect conflicts between sources.\n" + "We use Semantica's ingestors to load data. In a real pipeline, we would attach an extractor (like an LLM) to parse the raw content into entities. Here, we simulate the extraction output for clarity." ] }, { @@ -128,22 +125,140 @@ "metadata": {}, "outputs": [], "source": [ - "conflict_detector = ConflictDetector()\n", + "# Simulate extracted entities from our sources\n", "\n", - "conflicts = conflict_detector.detect_value_conflicts(all_entities, \"name\")\n", + "source_db = {\n", + " \"name\": \"Corporate Database\",\n", + " \"type\": \"structured\",\n", + " \"entities\": [\n", + " {\n", + " \"name\": \"Nexus AI\",\n", + " \"type\": \"Organization\",\n", + " \"properties\": {\"revenue\": 5500000.00, \"employees\": 45},\n", + " \"source\": \"corporate_db\"\n", + " }\n", + " ]\n", + "}\n", "\n", - "print(f\"Detected {len(conflicts)} conflicts\")\n", - "for conflict in conflicts[:3]:\n", - " print(f\" Conflict: {conflict.entity_id} - {conflict.conflict_type}\")\n" + "source_web = {\n", + " \"name\": \"Web News\",\n", + " \"type\": \"unstructured\",\n", + " \"entities\": [\n", + " {\n", + " \"name\": \"Nexus AI\",\n", + " \"type\": \"Organization\",\n", + " \"properties\": {\"valuation\": \"$100M\", \"location\": \"San Francisco\"},\n", + " \"source\": \"public_web\"\n", + " },\n", + " {\n", + " \"name\": \"Jane Doe\",\n", + " \"type\": \"Person\",\n", + " \"properties\": {\"role\": \"CEO\"},\n", + " \"source\": \"public_web\"\n", + " }\n", + " ],\n", + " \"relationships\": [\n", + " {\"source\": \"Jane Doe\", \"target\": \"Nexus AI\", \"type\": \"is_ceo_of\"}\n", + " ]\n", + "}\n", + "\n", + "source_api = {\n", + " \"name\": \"Market API\",\n", + " \"type\": \"structured\",\n", + " \"entities\": [\n", + " {\n", + " \"name\": \"Nexus AI\",\n", + " \"type\": \"Organization\",\n", + " \"properties\": {\"ticker\": \"NXAI\", \"employees\": 50}, # Note conflict: 50 vs 45\n", + " \"source\": \"market_api\"\n", + " }\n", + " ]\n", + "}\n", + "\n", + "source_repo = {\n", + " \"name\": \"GitHub Repo\",\n", + " \"type\": \"semi-structured\",\n", + " \"entities\": [\n", + " {\n", + " \"name\": \"Nexus AI Core\",\n", + " \"type\": \"Software\",\n", + " \"properties\": {\"language\": \"Python\"},\n", + " \"source\": \"github\"\n", + " }\n", + " ],\n", + " \"relationships\": [\n", + " {\"source\": \"Nexus AI Core\", \"target\": \"Nexus AI\", \"type\": \"owned_by\"}\n", + " ]\n", + "}\n", + "\n", + "# 5. Web Search MCP\n", + "# We use Semantica's MCPIngestor to connect to a Web Search MCP server.\n", + "# This allows us to fetch live competitor data (e.g., from Brave Search).\n", + "\n", + "try:\n", + " # Initialize MCP Ingestor\n", + " mcp = MCPIngestor()\n", + " \n", + " # Attempt to connect to a local MCP server (e.g., running on port 8000)\n", + " # Example: `fastmcp run search_server.py`\n", + " mcp.connect(\"web_search\", url=\"http://localhost:8000/sse\")\n", + " \n", + " print(\"Connected to MCP Server. Ingesting live data...\")\n", + " \n", + " # Ingest data using the search tool\n", + " mcp_data = mcp.ingest_tool_output(\n", + " \"web_search\", \n", + " \"search\", \n", + " {\"query\": \"Nexus AI competitors valuation\"}\n", + " )\n", + " \n", + " # Process the output (assuming the tool returns structured entities)\n", + " # In a real app, you might need an LLM to extract entities from search results.\n", + " # Here we assume the MCP server returns ready-to-use entities.\n", + " source_mcp = {\n", + " \"name\": \"Web Search MCP\",\n", + " \"type\": \"agent-tool\",\n", + " \"entities\": mcp_data.get(\"entities\", []),\n", + " \"source\": \"mcp_search\"\n", + " }\n", + "\n", + "except Exception as e:\n", + " print(f\"MCP Server connection failed ({e}). Using simulated data.\")\n", + " print(\"To enable live data, ensure an MCP server is running at http://localhost:8000/sse\")\n", + " \n", + " # Fallback to simulated data\n", + " source_mcp = {\n", + " \"name\": \"Web Search MCP\",\n", + " \"type\": \"agent-tool\",\n", + " \"entities\": [\n", + " {\n", + " \"name\": \"Nexus AI\",\n", + " \"type\": \"Organization\",\n", + " \"properties\": {\n", + " \"competitors\": [\"Cyberdyne Systems\", \"Massive Dynamic\"],\n", + " \"valuation\": \"$120M\" # Note conflict: $120M (newer) vs $100M (older web)\n", + " },\n", + " \"source\": \"mcp_search_agent\"\n", + " }\n", + " ],\n", + " \"relationships\": [\n", + " {\"source\": \"Nexus AI\", \"target\": \"Cyberdyne Systems\", \"type\": \"competes_with\"}\n", + " ]\n", + "}\n", + "\n", + "all_sources = [source_db, source_web, source_api, source_repo, source_mcp]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 4: Provenance Tracking\n", + "## Phase 3: Graph Construction & Resolution\n", "\n", - "Track data provenance across sources.\n" + "We use `GraphBuilder` to:\n", + "1. **Merge Entities**: Combine the 4 \"Nexus AI\" records into one canonical node.\n", + "2. **Resolve Conflicts**: Handle discrepancies (Employee count: 45 vs 50; Valuation: $100M vs $120M).\n", + "3. **Build Graph**: Link related entities (CEO, Software, Competitors)." ] }, { @@ -152,28 +267,34 @@ "metadata": {}, "outputs": [], "source": [ - "provenance_tracker = ProvenanceTracker()\n", + "# Initialize GraphBuilder with resolution enabled\n", + "builder = GraphBuilder(\n", + " merge_entities=True,\n", + " resolve_conflicts=True,\n", + " entity_resolution_strategy=\"fuzzy\"\n", + ")\n", "\n", - "for entity in all_entities:\n", - " provenance_tracker.track_entity(entity.get(\"id\"), entity.get(\"source\"), entity)\n", + "# Build the graph\n", + "print(\"Building Knowledge Graph...\")\n", + "kg = builder.build(sources=all_sources)\n", "\n", - "relationships = [\n", - " {\"source\": \"e2\", \"target\": \"e1\", \"type\": \"CEO_of\", \"source\": \"file1\"}\n", - "]\n", + "print(f\"Graph built with {len(kg['nodes'])} nodes and {len(kg['edges'])} edges.\")\n", "\n", - "for rel in relationships:\n", - " provenance_tracker.track_relationship(rel.get(\"source\"), rel.get(\"target\"), rel.get(\"source\"), rel)\n", - "\n", - "print(f\"Tracked provenance for {len(all_entities)} entities and {len(relationships)} relationships\")\n" + "# Verify conflict resolution results\n", + "nexus_node = next(n for n in kg['nodes'] if n['name'] == \"Nexus AI\")\n", + "print(\"\\nResolved Properties for Nexus AI:\")\n", + "print(f\" Employees: {nexus_node['properties'].get('employees')} (Resolved from DB/API)\")\n", + "print(f\" Valuation: {nexus_node['properties'].get('valuation')} (Resolved from Web/MCP)\")\n", + "print(f\" Competitors: {nexus_node['properties'].get('competitors')}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Step 5: Build Unified Knowledge Graph\n", + "## Phase 4: Visualization\n", "\n", - "Build a unified knowledge graph from integrated sources.\n" + "We use `KGVisualizer` to render the interactive graph." ] }, { @@ -182,37 +303,48 @@ "metadata": {}, "outputs": [], "source": [ - "builder = GraphBuilder()\n", + "print(\"Visualizing Graph...\")\n", + "visualizer = KGVisualizer(layout=\"force\", color_scheme=\"vibrant\")\n", "\n", - "unified_kg = builder.build(resolved_entities, relationships)\n", - "\n", - "print(f\"Built unified knowledge graph\")\n", - "print(f\" Entities: {len(unified_kg.get('entities', []))}\")\n", - "print(f\" Relationships: {len(unified_kg.get('relationships', []))}\")\n", - "print(f\" Sources integrated: {len(set(e.get('source', '') for e in resolved_entities))}\")\n" + "# Render the network\n", + "# This supports interactive output in Jupyter\n", + "fig = visualizer.visualize_network(kg, output=\"interactive\")\n", + "fig.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Summary\n", + "## Conclusion\n", "\n", - "You've learned advanced multi-source data integration:\n", - "\n", - "- **Multiple Ingestion Types**: FileIngestor, WebIngestor, DBIngestor, StreamIngestor, FeedIngestor\n", - "- **EntityResolver**: Resolve entities across sources\n", - "- **ConflictDetector**: Detect conflicts between sources\n", - "- **ProvenanceTracker**: Track data provenance\n", - "- **Unified Knowledge Graph**: Build integrated graph from multiple sources\n" + "In this notebook, we used `semantica`'s high-level modules to:\n", + "1. Ingest data from 5 different sources (including a simulated **MCP Search Agent**).\n", + "2. Automatically resolve identity to create a single \"Nexus AI\" node.\n", + "3. Resolve complex data conflicts (Valuation, Employee Count).\n", + "4. Visualize the unified Knowledge Graph with competitor relationships.\n" ] } ], "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.5" } }, "nbformat": 4, - "nbformat_minor": 2 -} + "nbformat_minor": 4 +} \ No newline at end of file