mirror of
https://github.com/semantica-agi/semantica.git
synced 2026-08-30 04:40:16 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
957c122116 | ||
|
|
31ca2e4446 | ||
|
|
b08c13364b | ||
|
|
01dd0c97ab | ||
|
|
2bd1d06eb2 | ||
|
|
9a2f2cd2d2 | ||
|
|
04a210232e | ||
|
|
b3baeaa74e | ||
|
|
58707ff721 | ||
|
|
9b18bc3da3 | ||
|
|
5764a88d7e | ||
|
|
cc69899b13 | ||
|
|
e3b53998c3 | ||
|
|
de3441e76e | ||
|
|
bd3c258458 | ||
|
|
51cc445327 | ||
|
|
04c4c9fb4c | ||
|
|
010251ac35 | ||
|
|
dcd6f25f87 | ||
|
|
55abd52b77 | ||
|
|
960d7c5f8f | ||
|
|
2489ce72b5 | ||
|
|
f488dfb82a | ||
|
|
74fdd3330e | ||
|
|
e712949872 | ||
|
|
c208f6b54e | ||
|
|
d516ea69dc | ||
|
|
2790132e8e | ||
|
|
1e22ff3a75 | ||
|
|
9c59f97542 | ||
|
|
4eb69e5048 | ||
|
|
2b43fa4699 | ||
|
|
9fb18e3ec6 | ||
|
|
7f7c36f94d | ||
|
|
2e2f19f43d | ||
|
|
d7b686f32a | ||
|
|
e89e707e49 | ||
|
|
a441e935f9 | ||
|
|
3fb98aa0ed | ||
|
|
4e0c3bc361 | ||
|
|
ef2c3dc841 | ||
|
|
96604ae398 | ||
|
|
88a4b9f1d2 | ||
|
|
ea02896617 | ||
|
|
01808728f4 | ||
|
|
b03ab2458d | ||
|
|
f8551c5dfb | ||
|
|
e7f713d43b | ||
|
|
6595f1918c | ||
|
|
47809f2ef9 | ||
|
|
40beea447e | ||
|
|
96a98fa037 | ||
|
|
222f25b275 | ||
|
|
43c14e41fa | ||
|
|
ac942f7895 | ||
|
|
fd916b15b5 | ||
|
|
bc28c22ee0 | ||
|
|
966692bafb | ||
|
|
04eea7e7eb | ||
|
|
35391382d3 | ||
|
|
e916ab3f7a | ||
|
|
aee046ec8b | ||
|
|
5aa0bdb630 | ||
|
|
b44803dcae | ||
|
|
7796cb5283 | ||
|
|
8cde40d753 | ||
|
|
9ef8a7aa18 | ||
|
|
af17585087 | ||
|
|
7b9bd42790 | ||
|
|
d8f78cd49e | ||
|
|
f4016237bd | ||
|
|
0c5e12f5c9 | ||
|
|
9c97d3236c | ||
|
|
599372a50f | ||
|
|
9f31f825ff | ||
|
|
a674e8c039 | ||
|
|
1124a56a06 | ||
|
|
9ad1f574af | ||
|
|
b053602c7d | ||
|
|
d2d6adafdb | ||
|
|
0c27f0fcd9 | ||
|
|
00575b135e | ||
|
|
9e0aa28eb1 | ||
|
|
53db5bbdc0 | ||
|
|
8313cd73a0 | ||
|
|
c7559afdc5 | ||
|
|
40e5c5110c | ||
|
|
1719ff5832 | ||
|
|
2ecebf1003 | ||
|
|
7be2d38bb1 | ||
|
|
c3555e0cfd | ||
|
|
94ddcc4d33 | ||
|
|
7a652cf227 | ||
|
|
f53935e0a1 | ||
|
|
b9ffba67ea | ||
|
|
d4f008a183 | ||
|
|
f7fcfa3691 | ||
|
|
8289d56d89 | ||
|
|
bde4ef18a3 | ||
|
|
1542b2dafb | ||
|
|
76def647d8 | ||
|
|
c15ee40cdf | ||
|
|
068d0d489a | ||
|
|
7a82b7b597 | ||
|
|
96e784509e | ||
|
|
bd594f9c41 | ||
|
|
b5f895e289 | ||
|
|
7d07691d99 | ||
|
|
8740379df6 | ||
|
|
5e220dc341 | ||
|
|
3f74040509 | ||
|
|
a54959d277 | ||
|
|
7c5ee9fb10 | ||
|
|
6155a28d9f | ||
|
|
2bbe36400a | ||
|
|
106e817ad8 | ||
|
|
d5ec639d3c | ||
|
|
cd437a9cfb | ||
|
|
bd466b6016 | ||
|
|
ef0797e03e | ||
|
|
eaa1fbefa6 | ||
|
|
9cc096dcd5 | ||
|
|
07bd371e7d | ||
|
|
e24ee50a0d | ||
|
|
7046c92b3a | ||
|
|
1ca83dd3c9 | ||
|
|
b2925ed773 | ||
|
|
4524f071e1 | ||
|
|
644314e976 | ||
|
|
65cb229ed5 | ||
|
|
ab4fa0e4c5 | ||
|
|
ab9624fb39 | ||
|
|
323a788288 | ||
|
|
e92bf0e872 | ||
|
|
995c1f27eb | ||
|
|
fcd61772b2 | ||
|
|
2cf2733d5b | ||
|
|
b07b1d58f7 | ||
|
|
e91cc315ec | ||
|
|
5b14f1cc4a | ||
|
|
75fbeeb7e2 | ||
|
|
1f45fe1197 | ||
|
|
ef829ce0d5 | ||
|
|
a8828741e1 | ||
|
|
8e3f06e3a3 | ||
|
|
27e1d94290 | ||
|
|
6e0bb43d6c | ||
|
|
529f099ddd | ||
|
|
0c9d6dad64 | ||
|
|
7525f14e7f | ||
|
|
e96bd62ebf | ||
|
|
0e2f1369dd | ||
|
|
eb94b3a5ce | ||
|
|
4166de2777 | ||
|
|
640315e287 | ||
|
|
a6fde080a9 | ||
|
|
6b4a5f1a89 | ||
|
|
ae3febfa05 | ||
|
|
a1674f6aa3 | ||
|
|
a408bc1958 | ||
|
|
b817816d5d | ||
|
|
6582481a28 | ||
|
|
9a999c02cb | ||
|
|
409e8c3d5c | ||
|
|
88e16b8360 | ||
|
|
a9bd3be689 | ||
|
|
02a6f3fac2 | ||
|
|
34284077cf | ||
|
|
724d75afbc | ||
|
|
fe1d8c425c | ||
|
|
35760f97aa | ||
|
|
d987abd7a9 | ||
|
|
7e09892bc4 | ||
|
|
1fceb634ae | ||
|
|
8705724b23 | ||
|
|
bd3bc7de7d | ||
|
|
712abf0e7d | ||
|
|
d73bcd52c4 | ||
|
|
859f4765fd | ||
|
|
13a5c383c7 | ||
|
|
b8f0f40d16 | ||
|
|
cbab6e4633 | ||
|
|
432e883ca9 | ||
|
|
c880984e40 | ||
|
|
ee56ca3829 | ||
|
|
e18b1cc123 | ||
|
|
dc94526e9a | ||
|
|
3f78d00c6b | ||
|
|
52d94bb1d7 | ||
|
|
a9538a0ddd | ||
|
|
5fc188b9eb | ||
|
|
30e0dc81de | ||
|
|
9e1aa64043 | ||
|
|
6eca6af7bc | ||
|
|
eb5980a1fb | ||
|
|
ec6cfdf304 | ||
|
|
bb63faa1ec | ||
|
|
38962d3d7a | ||
|
|
fbe0ed1a41 | ||
|
|
affb16de9e | ||
|
|
8d6b38d7da | ||
|
|
a1ae001618 | ||
|
|
5cc0c7eac4 | ||
|
|
734585ed92 | ||
|
|
e45875f924 | ||
|
|
1620de371f | ||
|
|
ae4e93923e | ||
|
|
7297d46ac8 | ||
|
|
1a124c7294 | ||
|
|
0a052b676d | ||
|
|
0476950fdf | ||
|
|
a467cb5af6 | ||
|
|
89235d1f19 | ||
|
|
3934c74300 | ||
|
|
8f8e532114 | ||
|
|
b091c870bc | ||
|
|
53f6aba967 | ||
|
|
0b67bfa998 | ||
|
|
381de30cbd | ||
|
|
999c490ba9 | ||
|
|
00322d81c6 | ||
|
|
ad6dd1af4f | ||
|
|
78a3b4a6cd | ||
|
|
07208318ec | ||
|
|
ea6cfdf6a8 | ||
|
|
7439f31399 | ||
|
|
8a25494f55 | ||
|
|
72d948972b | ||
|
|
a62326a61f | ||
|
|
e171e86daa | ||
|
|
6dc4f69c84 | ||
|
|
45205ad54d | ||
|
|
dd6b341fb9 | ||
|
|
77186a518d | ||
|
|
adabdd283f | ||
|
|
abe730891f | ||
|
|
96702923de | ||
|
|
bfd4bd60e5 | ||
|
|
e211a7bf57 | ||
|
|
30e2645a98 | ||
|
|
e5e8823423 | ||
|
|
b5c91a90a3 | ||
|
|
569fdc31f1 | ||
|
|
bdcaab92b0 | ||
|
|
3f4e6f831f | ||
|
|
52aa1a6896 | ||
|
|
d34731d687 | ||
|
|
8dace2f078 | ||
|
|
4fdc483935 | ||
|
|
d042054f9a | ||
|
|
c2d7d92a53 | ||
|
|
b6e27b7d71 | ||
|
|
444746de02 | ||
|
|
e8655a97ed | ||
|
|
f15ab2a327 | ||
|
|
2f9ad467f0 | ||
|
|
253d35ee31 | ||
|
|
09e7e61111 | ||
|
|
05f553271d | ||
|
|
ccb3f43104 | ||
|
|
6be868e067 | ||
|
|
7b7d3fa8ad | ||
|
|
c178b8dead | ||
|
|
8b9f6dbd09 | ||
|
|
096ad31f77 | ||
|
|
4b7cc5a359 | ||
|
|
c41f2951b2 | ||
|
|
a047ebf74f | ||
|
|
88c12b1867 | ||
|
|
094bb8d82b | ||
|
|
7ff2fd9981 | ||
|
|
0a555145e4 | ||
|
|
994e58a170 | ||
|
|
244144dee3 | ||
|
|
5dfca85500 | ||
|
|
f3dd7a05bd | ||
|
|
d03a237278 | ||
|
|
f3ac9fbffa | ||
|
|
6856580a7a | ||
|
|
4a282628ea | ||
|
|
c73e35a2fe | ||
|
|
a99f18b71b | ||
|
|
84b90b45a2 | ||
|
|
d7d589f64e | ||
|
|
d3366bbcf0 | ||
|
|
95c5486d22 |
@@ -0,0 +1,20 @@
|
||||
# Linguist documentation and generated files
|
||||
# This ensures GitHub language statistics reflect the core Python code
|
||||
|
||||
# Mark the entire docs directory as documentation
|
||||
docs/* linguist-documentation
|
||||
|
||||
# Mark the cookbook directory as documentation/examples
|
||||
cookbook/* linguist-documentation
|
||||
|
||||
# Specifically ignore large generated HTML/JSON files in cookbook
|
||||
cookbook/**/*.html linguist-documentation
|
||||
cookbook/**/*.json linguist-documentation
|
||||
cookbook/**/*.graphml linguist-documentation
|
||||
cookbook/**/*.ttl linguist-documentation
|
||||
|
||||
# Ensure .ipynb files are treated as documentation/examples
|
||||
cookbook/**/*.ipynb linguist-documentation
|
||||
|
||||
# Mark data directories as documentation or vendored
|
||||
**/data/* linguist-vendored
|
||||
@@ -8,7 +8,11 @@ on:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'semantica/**'
|
||||
- 'mkdocs.yml'
|
||||
- 'requirements-docs.txt'
|
||||
- 'CHANGELOG.md'
|
||||
- 'RELEASE.md'
|
||||
workflow_dispatch:
|
||||
|
||||
# Permissions needed to deploy to GitHub Pages
|
||||
|
||||
+57
-2
@@ -7,6 +7,61 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
- Fixed model switching bug in `TextEmbedder` where internal state was not cleared, preventing dynamic updates between `fastembed` and `sentence_transformers` (#160).
|
||||
- Implemented model-intrinsic embedding dimension detection in `TextEmbedder` to ensure consistency between models and vector databases.
|
||||
- Updated `set_model` to properly refresh configuration and dimensions during model switches.
|
||||
|
||||
### Added
|
||||
- Added comprehensive unit test suite `tests/embeddings/test_model_switching.py` for verifying dynamic model transitions and dimension updates.
|
||||
- Fixed `TypeError: unhashable type: 'Entity'` in `GraphAnalyzer` when processing graphs with raw `Entity` objects or dictionaries in relationships (#159).
|
||||
- Robustified ID extraction across `CentralityCalculator`, `CommunityDetector`, and `ConnectivityAnalyzer` to handle various entity formats.
|
||||
- Improved `Entity` class hashability and equality logic in `utils/types.py`.
|
||||
- Added end-to-end integration test suite for Knowledge Graph pipeline validation (GraphBuilder -> EntityResolver -> GraphAnalyzer).
|
||||
- Fixed orchestrator lazy property initialization and configuration normalization logic in `Orchestrator`.
|
||||
- Resolved `AssertionError` in orchestrator tests by aligning test mocks with production component usage.
|
||||
- Fixed dependency compatibility issues by pinning `protobuf==4.25.3` and `grpcio==1.67.1`.
|
||||
- Added missing dependencies `GitPython` and `chardet` to `pyproject.toml`.
|
||||
- Verified and aligned `FileObject.text` property usage in GraphRAG notebooks for consistent content decoding.
|
||||
|
||||
### Added
|
||||
- **Semantic Extract Improvements**:
|
||||
- Introduced `auto-chunking` for long text processing in LLM extraction methods (`extract_entities_llm`, `extract_relations_llm`, `extract_triplets_llm`).
|
||||
- Added `silent_fail` parameter to LLM extraction methods for configurable error handling.
|
||||
- Implemented robust JSON parsing and automatic retry logic (3 attempts with exponential backoff) in `BaseProvider` for all LLM providers.
|
||||
- Enhanced `GroqProvider` with better diagnostics and connectivity testing.
|
||||
- Added comprehensive entity, relation, and triplet deduplication for chunked extraction.
|
||||
|
||||
### Fixed
|
||||
- Fixed a bug in `TripletExtractor` where the `validate_triplets` method was shadowed by an internal attribute.
|
||||
- Fixed incorrect `TextSplitter` import path in the `semantic_extract.methods` module.
|
||||
|
||||
## [0.1.1] - 2026-01-05
|
||||
|
||||
### Added
|
||||
- Exported `DoclingParser` and `DoclingMetadata` from `semantica.parse` for easier access.
|
||||
- Added comprehensive `DoclingParser` usage examples to README and documentation.
|
||||
- Added Windows-specific troubleshooting note for PyTorch DLL issues.
|
||||
|
||||
### Fixed
|
||||
- Fixed `DoclingParser` import/export issues across platforms (Windows, Linux, Google Colab).
|
||||
- Improved error messaging when optional `docling` dependency is missing.
|
||||
- Fixed versioning inconsistencies across the framework.
|
||||
|
||||
## [0.1.0] - 2025-12-31
|
||||
|
||||
### Added
|
||||
- New command-line interface (`semantica` CLI) with support for knowledge base building and info commands.
|
||||
- Integrated FastAPI-based REST API server for remote access to framework functionality.
|
||||
- Dedicated background worker component for scalable task processing and pipeline execution.
|
||||
- Framework-level versioning configuration for PyPI distribution.
|
||||
- Automated release workflow with Trusted Publishing support.
|
||||
|
||||
### Changed
|
||||
- Updated versioning across the framework to 0.1.0.
|
||||
- Refined entry point configurations in `pyproject.toml`.
|
||||
- Improved lazy module loading for core framework components.
|
||||
|
||||
## [0.0.5] - 2025-11-26
|
||||
|
||||
### Changed
|
||||
@@ -49,7 +104,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Added
|
||||
- Core framework architecture
|
||||
- Universal data ingestion (50+ file formats)
|
||||
- Universal data ingestion (multiple file formats)
|
||||
- Semantic intelligence engine (NER, relation extraction, event detection)
|
||||
- Knowledge graph construction with entity resolution
|
||||
- 6-stage ontology generation pipeline
|
||||
@@ -58,7 +113,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Production-ready quality assurance modules
|
||||
- Comprehensive documentation with MkDocs
|
||||
- Cookbook with interactive tutorials
|
||||
- Support for multiple vector stores (Pinecone, Weaviate, Qdrant, FAISS)
|
||||
- Support for multiple vector stores (Weaviate, Qdrant, FAISS)
|
||||
- Support for multiple graph databases (Neo4j, NetworkX, RDFLib)
|
||||
- Temporal knowledge graph support
|
||||
- Conflict detection and resolution
|
||||
|
||||
+15
-6
@@ -326,14 +326,23 @@ def extract_entities(
|
||||
|
||||
## Types of Contributions
|
||||
|
||||
### Code Contributions
|
||||
### 💻 Code Contributions
|
||||
|
||||
- Bug fixes
|
||||
- New features
|
||||
- Performance improvements
|
||||
- Refactoring
|
||||
- **Bug Fixes**: Resolving issues reported in the issue tracker.
|
||||
- **New Features**: Implementing new capabilities (please discuss via an issue first!).
|
||||
- **Refactoring**: Improving code structure and maintainability without changing behavior.
|
||||
- **Algorithm Optimization**: Improving the efficiency of graph algorithms and vector search.
|
||||
|
||||
### Documentation Contributions
|
||||
#### ⚡ Performance and Latency
|
||||
We deeply value efficiency. Contributions that make Semantica faster and lighter are highly appreciated!
|
||||
|
||||
- **Latency Reduction**: Optimize critical paths and RAG pipeline response times.
|
||||
- **Memory Optimization**: Reduce graph/vector processing memory footprint.
|
||||
- **Throughput**: Improve operations per second (bulk ingestion, parallel queries).
|
||||
- **Benchmarks**: Add performance benchmarks to track regressions.
|
||||
- **Async/Concurrency**: Enhance asynchronous execution and concurrency.
|
||||
|
||||
### 📚 Documentation Contributions
|
||||
|
||||
- Fix typos and grammar
|
||||
- Improve clarity
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Hawksight AI
|
||||
Copyright (c) 2026 Hawksight AI
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
|
||||
[](https://www.python.org/downloads/)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://pypi.org/project/semantica/0.0.1/)
|
||||
[](https://pepy.tech/project/semantica)
|
||||
[](https://discord.gg/semantica)
|
||||
[](https://pypi.org/project/semantica/)
|
||||
[](https://pypi.org/project/semantica/)
|
||||
[](https://pepy.tech/project/semantica)
|
||||
[](https://discord.gg/pMHguUzG)
|
||||
[](https://github.com/Hawksight-AI/semantica/actions)
|
||||
|
||||
<p align="center">
|
||||
@@ -27,9 +28,9 @@
|
||||
|
||||
*The missing fabric between raw data and AI engineering. A comprehensive open-source framework for building semantic layers and knowledge engineering systems that transform unstructured data into AI-ready knowledge — powering Knowledge Graph-Powered RAG (GraphRAG), AI Agents, Multi-Agent Systems, and AI applications with structured semantic knowledge.*
|
||||
|
||||
**100% Open Source** • **MIT Licensed** • **Production Ready** • **Community Driven**
|
||||
**100% Open Source** • **MIT Licensed** • **Latest Version: 0.1.1** • **Production Ready** • **Community Driven**
|
||||
|
||||
[**Discord**](https://discord.gg/semantica) • [**GitHub**](https://github.com/Hawksight-AI/semantica)
|
||||
[**Discord**](https://discord.gg/pMHguUzG)
|
||||
|
||||
</div>
|
||||
|
||||
@@ -81,58 +82,16 @@ Organizations have **unstructured data** (PDFs, emails, logs), **messy data** (i
|
||||
|
||||
Semantica operates through three integrated layers that transform raw data into AI-ready knowledge:
|
||||
|
||||
**Input Layer** — Universal ingestion from 50+ data formats (PDFs, DOCX, HTML, JSON, CSV, databases, live feeds, APIs, streams, archives, multi-modal content) into a unified pipeline.
|
||||
**Input Layer** — Universal ingestion from multiple data formats (PDFs, DOCX, HTML, JSON, CSV, databases, live feeds, APIs, streams, archives, multi-modal content) into a unified pipeline.
|
||||
|
||||
**Semantic Layer** — Core intelligence engine performing entity extraction, relationship mapping, ontology generation, context engineering, and quality assurance. This is where unstructured data transforms into structured knowledge.
|
||||
**Semantic Layer** — Core intelligence engine performing entity extraction, relationship mapping, ontology generation, context engineering, and quality assurance. Includes **advanced entity deduplication** (Jaro-Winkler, disjoint property handling) to ensure a clean single source of truth.
|
||||
|
||||
**Output Layer** — Production-ready knowledge graphs, vector embeddings, and validated ontologies that power GraphRAG systems, AI agents, and multi-agent systems.
|
||||
|
||||
**Powers: GraphRAG, AI Agents, Multi-Agent Systems**
|
||||
|
||||
#### Semantica Processing Flow
|
||||
|
||||
<details>
|
||||
<summary>View Interactive Flowchart</summary>
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Raw Data Sources<br/>PDFs, Emails, Logs, Databases<br/>50+ Formats] --> B[Input Layer<br/>Universal Data Ingestion]
|
||||
B --> C[Format Detection<br/>& Parsing]
|
||||
C --> D[Normalization<br/>& Preprocessing]
|
||||
D --> E[Semantic Layer<br/>Core Intelligence]
|
||||
|
||||
E --> F[Entity Extraction<br/>NER + LLM Enhancement]
|
||||
E --> G[Relationship Mapping<br/>Triple Generation]
|
||||
E --> H[Ontology Generation<br/>6-Stage Pipeline]
|
||||
E --> I[Context Engineering<br/>Semantic Enrichment]
|
||||
E --> J[Quality Assurance<br/>Conflict Detection]
|
||||
|
||||
F --> K[Output Layer]
|
||||
G --> K
|
||||
H --> K
|
||||
I --> K
|
||||
J --> K
|
||||
|
||||
K --> L[Knowledge Graphs<br/>Production-Ready]
|
||||
K --> M[Vector Embeddings<br/>Semantic Search]
|
||||
K --> N[Ontologies<br/>OWL Validated]
|
||||
|
||||
L --> O[Application Layer]
|
||||
M --> O
|
||||
N --> O
|
||||
|
||||
O --> P[GraphRAG Engine<br/>91% Accuracy]
|
||||
O --> Q[AI Agents<br/>Persistent Memory]
|
||||
O --> R[Multi-Agent Systems<br/>Shared Models]
|
||||
O --> S[Analytics & BI<br/>Graph Insights]
|
||||
|
||||
style A fill:#e1f5ff
|
||||
style E fill:#fff4e1
|
||||
style K fill:#e8f5e9
|
||||
style O fill:#f3e5f5
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
### What Happens Without Semantics?
|
||||
@@ -153,13 +112,15 @@ flowchart TD
|
||||
|
||||
### How Semantica Solves These Problems
|
||||
|
||||
**Universal Data Ingestion** — Handles 50+ formats (PDF, DOCX, HTML, JSON, CSV, databases, APIs, streams) with unified pipeline, no custom parsers needed.
|
||||
**Efficient Embeddings** — Uses **FastEmbed** by default for high-performance, lightweight local embedding generation (faster than sentence-transformers).
|
||||
|
||||
**Automated Semantic Extraction** — NER, relationship extraction, and triple generation with LLM enhancement discovers entities and relationships automatically.
|
||||
**Universal Data Ingestion** — Handles multiple formats (PDF, DOCX, HTML, JSON, CSV, databases, APIs, streams) with unified pipeline, no custom parsers needed.
|
||||
|
||||
**Automated Semantic Extraction** — NER, relationship extraction, and triplet generation with LLM enhancement. Includes **auto-chunking** for long documents and **robust error handling** with automatic retry logic.
|
||||
|
||||
**Knowledge Graph Construction** — Production-ready graphs with entity resolution, temporal support, and graph analytics. Queryable knowledge ready for AI applications.
|
||||
|
||||
**GraphRAG Engine** — Hybrid vector + graph retrieval achieves 91% accuracy (30% improvement) via semantic search + graph traversal for multi-hop reasoning.
|
||||
**GraphRAG Engine** — Hybrid vector + graph retrieval achieves 91% accuracy (30% improvement) via semantic search + graph traversal for multi-hop reasoning. Features LLM-generated responses grounded in knowledge graph context with reasoning traces. [See Comparison Benchmark](cookbook/use_cases/advanced_rag/02_RAG_vs_GraphRAG_Comparison.ipynb)
|
||||
|
||||
**AI Agent Context Engineering** — Persistent memory with RAG + knowledge graphs enables context maintenance, action validation, and structured knowledge access.
|
||||
|
||||
@@ -173,12 +134,13 @@ flowchart TD
|
||||
|
||||
| **Feature Category** | **Capabilities** | **Key Benefits** |
|
||||
|:---------------------|:-----------------|:------------------|
|
||||
| **Data Ingestion** | 50+ formats (PDF, DOCX, HTML, JSON, CSV, databases, APIs, streams, archives) | Universal ingestion, no custom parsers needed |
|
||||
| **Semantic Extraction** | NER, relationship extraction, triple generation, LLM enhancement | Automated discovery of entities and relationships |
|
||||
| **Data Ingestion** | Multiple formats (PDF, DOCX, HTML, JSON, CSV, databases, APIs, streams, archives) | Universal ingestion, no custom parsers needed |
|
||||
| **Semantic Extraction** | NER, relations, triplets, LLM enhancement, **auto-chunking** | Automated discovery with robust error handling |
|
||||
| **Knowledge Graphs** | Entity resolution, temporal support, graph analytics, query interface | Production-ready, queryable knowledge structures |
|
||||
| **Ontology Generation** | 6-stage LLM pipeline, OWL generation, HermiT/Pellet validation | Automated ontology creation from documents |
|
||||
| **GraphRAG** | Hybrid vector + graph retrieval, multi-hop reasoning | 91% accuracy, 30% improvement over vector-only |
|
||||
| **Agent Memory** | Persistent memory, RAG integration, MCP-compatible tools | Context-aware agents with semantic understanding |
|
||||
| **GraphRAG** | Hybrid vector + graph retrieval, multi-hop reasoning, LLM-generated responses | 91% accuracy, 30% improvement over vector-only, reasoning traces |
|
||||
| **LLM Providers** | Unified interface to 100+ LLMs (Groq, OpenAI, HuggingFace, LiteLLM) | Clean imports, multiple providers, structured output |
|
||||
| **Agent Memory** | Persistent memory (Save/Load), Hybrid Retrieval (Vector+Graph), FastEmbed support | Context-aware agents with semantic understanding |
|
||||
| **Pipeline Orchestration** | Parallel execution, custom steps, orchestrator-worker pattern | Scalable, flexible data processing |
|
||||
| **Quality Assurance** | Conflict detection, deduplication, quality scoring, provenance | Trusted knowledge graphs ready for production |
|
||||
|
||||
@@ -210,6 +172,8 @@ Semantica is designed for **developers, data engineers, and organizations** buil
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
> **✅ Available on PyPI!** Semantica is now published on PyPI. Install it with a single command: `pip install semantica`
|
||||
|
||||
**Prerequisites:** Python 3.8+ (3.9+ recommended) • pip (latest version)
|
||||
|
||||
### Install from PyPI (Recommended)
|
||||
@@ -221,11 +185,19 @@ pip install semantica
|
||||
# Or install with optional dependencies
|
||||
pip install semantica[all]
|
||||
|
||||
# GitHub Workaround (if PyPI version has issues)
|
||||
pip install git+https://github.com/Hawksight-AI/semantica.git@main
|
||||
|
||||
# Verify installation
|
||||
python -c "import semantica; print(semantica.__version__)"
|
||||
python -c "from semantica.parse import DoclingParser; DoclingParser(); print('✓ Semantica ready')"
|
||||
```
|
||||
|
||||
**Current Version:** [](https://pypi.org/project/semantica/0.0.1/) • [View on PyPI](https://pypi.org/project/semantica/0.0.1/)
|
||||
**Current Version:** [](https://pypi.org/project/semantica/) • [View on PyPI](https://pypi.org/project/semantica/)
|
||||
|
||||
!!! info "Windows PyTorch Note"
|
||||
If you encounter PyTorch DLL errors on Windows, ensure you have the [Microsoft Visual C++ Redistributable](https://aka.ms/vs/17/release/vc_redist.x64.exe) installed. This is a common environment-specific issue with PyTorch on Windows and not a bug in Semantica.
|
||||
|
||||
|
||||
|
||||
### Install from Source (Development)
|
||||
|
||||
@@ -246,7 +218,7 @@ pip install -e ".[dev]"
|
||||
|
||||
> **New to Semantica?** Check out the [**Cookbook**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook) for hands-on examples!
|
||||
|
||||
- [**Cookbook**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook) - 50+ interactive notebooks
|
||||
- [**Cookbook**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook) - Interactive notebooks
|
||||
- [Introduction](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction) - Getting started tutorials
|
||||
- [Advanced](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced) - Advanced techniques
|
||||
- [Use Cases](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/use_cases) - Real-world applications
|
||||
@@ -255,15 +227,17 @@ pip install -e ".[dev]"
|
||||
|
||||
| **Data Ingestion** | **Semantic Extract** | **Knowledge Graphs** | **Ontology** |
|
||||
|:--------------------:|:----------------------:|:----------------------:|:--------------:|
|
||||
| [50+ Formats](#universal-data-ingestion) | [Entity & Relations](#semantic-intelligence-engine) | [Graph Analytics](#knowledge-graph-construction) | [Auto Generation](#ontology-generation--management) |
|
||||
| **Context** | **GraphRAG** | **Pipeline** | **QA** |
|
||||
| [Agent Memory](#context-engineering-for-ai-agents) | [Hybrid RAG](#knowledge-graph-powered-rag-graphrag) | [Parallel Workers](#pipeline-orchestration--parallel-processing) | [Conflict Resolution](#production-ready-quality-assurance) |
|
||||
| [Multiple Formats](#universal-data-ingestion) | [Entity & Relations](#semantic-intelligence-engine) | [Graph Analytics](#knowledge-graph-construction) | [Auto Generation](#ontology-generation--management) |
|
||||
| **Context** | **GraphRAG** | **LLM Providers** | **Pipeline** |
|
||||
| [Agent Memory, Context Graph, Context Retriever](#context-engineering--memory-systems) | [Hybrid RAG](#knowledge-graph-powered-rag-graphrag) | [100+ LLMs](#llm-providers-module) | [Parallel Workers](#pipeline-orchestration--parallel-processing) |
|
||||
| **QA** | **Reasoning** | | |
|
||||
| [Conflict Resolution](#production-ready-quality-assurance) | [Rule-based Inference](#reasoning--inference-engine) | | |
|
||||
|
||||
---
|
||||
|
||||
### Universal Data Ingestion
|
||||
|
||||
> **50+ file formats** • PDF, DOCX, HTML, JSON, CSV, databases, feeds, archives
|
||||
> **Multiple file formats** • PDF, DOCX, HTML, JSON, CSV, databases, feeds, archives
|
||||
|
||||
```python
|
||||
from semantica.ingest import FileIngestor, WebIngestor, DBIngestor
|
||||
@@ -280,21 +254,60 @@ sources.extend(db_ingestor.ingest(query="SELECT * FROM articles"))
|
||||
print(f" Ingested {len(sources)} sources")
|
||||
```
|
||||
|
||||
[**Cookbook: Data Ingestion**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/02_Data_Ingestion.ipynb) • [**Document Parsing**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/03_Document_Parsing.ipynb) • [**Data Normalization**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/04_Data_Normalization.ipynb) • [**Chunking & Splitting**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/11_Chunking_and_Splitting.ipynb)
|
||||
[**Cookbook: Data Ingestion**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/02_Data_Ingestion.ipynb)
|
||||
|
||||
### Document Parsing & Processing
|
||||
|
||||
> **Multi-format parsing** • **Text normalization** • **Intelligent chunking**
|
||||
|
||||
```python
|
||||
from semantica.parse import DocumentParser, DoclingParser
|
||||
from semantica.normalize import TextNormalizer
|
||||
from semantica.split import TextSplitter
|
||||
|
||||
# Standard parsing
|
||||
parser = DocumentParser()
|
||||
parsed = parser.parse("document.pdf", format="auto")
|
||||
|
||||
# Enhanced parsing with Docling (recommended for complex layouts/tables)
|
||||
# Requires: pip install docling
|
||||
docling_parser = DoclingParser(enable_ocr=True)
|
||||
result = docling_parser.parse("complex_table.pdf")
|
||||
|
||||
print(f"Text (Markdown): {result['full_text'][:100]}...")
|
||||
print(f"Extracted {len(result['tables'])} tables")
|
||||
for i, table in enumerate(result['tables']):
|
||||
print(f"Table {i+1} headers: {table.get('headers', [])}")
|
||||
|
||||
# Normalize text
|
||||
normalizer = TextNormalizer()
|
||||
normalized = normalizer.normalize(parsed, clean_html=True, normalize_entities=True)
|
||||
|
||||
# Split into chunks
|
||||
splitter = TextSplitter(method="token", chunk_size=1000, chunk_overlap=200)
|
||||
chunks = splitter.split(normalized)
|
||||
```
|
||||
|
||||
[**Cookbook: Document Parsing**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/03_Document_Parsing.ipynb) • [**Data Normalization**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/04_Data_Normalization.ipynb) • [**Chunking & Splitting**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/11_Chunking_and_Splitting.ipynb)
|
||||
|
||||
### Semantic Intelligence Engine
|
||||
|
||||
> **Entity & Relation Extraction** • NER, Relationships, Events, Triples with LLM Enhancement
|
||||
> **Entity & Relation Extraction** • NER, Relationships, Events, Triplets with LLM Enhancement
|
||||
|
||||
```python
|
||||
from semantica import Semantica
|
||||
from semantica.semantic_extract import NERExtractor, RelationExtractor
|
||||
|
||||
text = "Apple Inc., founded by Steve Jobs in 1976, acquired Beats Electronics for $3 billion."
|
||||
|
||||
core = Semantica(ner_model="transformer", relation_strategy="hybrid")
|
||||
results = core.extract_semantics(text)
|
||||
# Extract entities
|
||||
ner_extractor = NERExtractor(method="ml", model="en_core_web_sm")
|
||||
entities = ner_extractor.extract(text)
|
||||
|
||||
print(f"Entities: {len(results.entities)}, Relationships: {len(results.relationships)}")
|
||||
# Extract relationships
|
||||
relation_extractor = RelationExtractor(method="dependency", model="en_core_web_sm")
|
||||
relationships = relation_extractor.extract(text, entities=entities)
|
||||
|
||||
print(f"Entities: {len(entities)}, Relationships: {len(relationships)}")
|
||||
```
|
||||
|
||||
[**Cookbook: Entity Extraction**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/05_Entity_Extraction.ipynb) • [**Relation Extraction**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/06_Relation_Extraction.ipynb) • [**Advanced Extraction**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/01_Advanced_Extraction.ipynb)
|
||||
@@ -304,77 +317,256 @@ print(f"Entities: {len(results.entities)}, Relationships: {len(results.relations
|
||||
> **Production-Ready KGs** • Entity Resolution • Temporal Support • Graph Analytics
|
||||
|
||||
```python
|
||||
from semantica import Semantica
|
||||
from semantica.kg import GraphAnalyzer
|
||||
from semantica.semantic_extract import NERExtractor, RelationExtractor
|
||||
from semantica.kg import GraphBuilder
|
||||
|
||||
documents = ["doc1.txt", "doc2.txt", "doc3.txt"]
|
||||
core = Semantica(graph_db="neo4j", merge_entities=True)
|
||||
kg = core.build_knowledge_graph(documents, generate_embeddings=True)
|
||||
# Extract entities and relationships
|
||||
ner_extractor = NERExtractor(method="ml", model="en_core_web_sm")
|
||||
relation_extractor = RelationExtractor(method="dependency", model="en_core_web_sm")
|
||||
|
||||
analyzer = GraphAnalyzer()
|
||||
pagerank = analyzer.compute_centrality(kg, method="pagerank")
|
||||
communities = analyzer.detect_communities(kg, method="louvain")
|
||||
entities = ner_extractor.extract(text)
|
||||
relationships = relation_extractor.extract(text, entities=entities)
|
||||
|
||||
result = kg.query("Who founded the company?", return_format="structured")
|
||||
print(f"Nodes: {kg.node_count}, Answer: {result.answer}")
|
||||
# Build knowledge graph
|
||||
builder = GraphBuilder()
|
||||
kg = builder.build({"entities": entities, "relationships": relationships})
|
||||
|
||||
print(f"Nodes: {len(kg.get('entities', []))}, Edges: {len(kg.get('relationships', []))}")
|
||||
```
|
||||
|
||||
[**Cookbook: Building Knowledge Graphs**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/07_Building_Knowledge_Graphs.ipynb) • [**Graph Store**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/09_Graph_Store.ipynb) • [**Triple Store**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/20_Triple_Store.ipynb) • [**Visualization**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/16_Visualization.ipynb)
|
||||
[**Cookbook: Building Knowledge Graphs**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/07_Building_Knowledge_Graphs.ipynb) • [**Graph Analytics**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/10_Graph_Analytics.ipynb)
|
||||
|
||||
[**Graph Analytics**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/10_Graph_Analytics.ipynb) • [**Advanced Graph Analytics**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/02_Advanced_Graph_Analytics.ipynb)
|
||||
### Embeddings & Vector Store
|
||||
|
||||
> **FastEmbed by default** • **Multiple backends** • **Semantic search**
|
||||
|
||||
```python
|
||||
from semantica.embeddings import EmbeddingGenerator
|
||||
from semantica.vector_store import VectorStore
|
||||
|
||||
# Generate embeddings
|
||||
embedding_gen = EmbeddingGenerator(model_name="sentence-transformers/all-MiniLM-L6-v2", dimension=384)
|
||||
embeddings = embedding_gen.generate_embeddings(chunks, data_type="text")
|
||||
|
||||
# Store in vector database
|
||||
vector_store = VectorStore(backend="faiss", dimension=384)
|
||||
vector_store.store_vectors(vectors=embeddings, metadata=[{"text": chunk} for chunk in chunks])
|
||||
|
||||
# Search
|
||||
results = vector_store.search(query="supply chain", top_k=5)
|
||||
```
|
||||
|
||||
[**Cookbook: Embedding Generation**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/12_Embedding_Generation.ipynb) • [**Vector Store**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/13_Vector_Store.ipynb)
|
||||
|
||||
### Graph Store & Triplet Store
|
||||
|
||||
> **Neo4j, FalkorDB support** • **SPARQL queries** • **RDF triplets**
|
||||
|
||||
```python
|
||||
from semantica.graph_store import GraphStore
|
||||
from semantica.triplet_store import TripletStore
|
||||
|
||||
# Graph Store (Neo4j, FalkorDB)
|
||||
graph_store = GraphStore(backend="neo4j", uri="bolt://localhost:7687", user="neo4j", password="password")
|
||||
graph_store.add_nodes([{"id": "n1", "labels": ["Person"], "properties": {"name": "Alice"}}])
|
||||
|
||||
# Triplet Store (Blazegraph, Jena, RDF4J)
|
||||
triplet_store = TripletStore(backend="blazegraph", endpoint="http://localhost:9999/blazegraph")
|
||||
triplet_store.add_triplet({"subject": "Alice", "predicate": "knows", "object": "Bob"})
|
||||
results = triplet_store.execute_query("SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10")
|
||||
```
|
||||
|
||||
[**Cookbook: Graph Store**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/09_Graph_Store.ipynb) • [**Triplet Store**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/20_Triplet_Store.ipynb)
|
||||
|
||||
### Ontology Generation & Management
|
||||
|
||||
> **6-Stage LLM Pipeline** • Automatic OWL Generation • HermiT/Pellet Validation
|
||||
|
||||
```python
|
||||
from semantica.ontology import OntologyGenerator, OntologyValidator
|
||||
from semantica.ontology import OntologyGenerator
|
||||
|
||||
generator = OntologyGenerator(llm_provider="openai", model="gpt-4")
|
||||
ontology = generator.generate_from_documents(sources=["domain_docs/"])
|
||||
|
||||
validator = OntologyValidator(reasoner="hermit")
|
||||
validation = validator.validate(ontology)
|
||||
|
||||
print(f"Classes: {len(ontology.classes)}, Valid: {validation.is_consistent}")
|
||||
print(f"Classes: {len(ontology.classes)}")
|
||||
```
|
||||
|
||||
[**Cookbook: Ontology**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/14_Ontology.ipynb)
|
||||
|
||||
### Context Engineering for AI Agents
|
||||
### Context Engineering & Memory Systems
|
||||
|
||||
> **Persistent Memory** • RAG + Knowledge Graphs • MCP-Compatible Tools
|
||||
> **Persistent Memory** • **Context Graph** • **Context Retriever** • **Hybrid Retrieval (Vector + Graph)** • **Production Graph Store (Neo4j)** • **Entity Linking** • **Multi-Hop Reasoning**
|
||||
|
||||
```python
|
||||
from semantica.context import AgentMemory, ContextRetriever
|
||||
from semantica.context import AgentContext, ContextGraph, ContextRetriever
|
||||
from semantica.vector_store import VectorStore
|
||||
from semantica.graph_store import GraphStore
|
||||
from semantica.llms import Groq
|
||||
|
||||
memory = AgentMemory(vector_store=VectorStore(backend="faiss"), retention_policy="unlimited")
|
||||
memory.store("User prefers technical docs", metadata={"user_id": "user_123"})
|
||||
# Initialize Context with Hybrid Retrieval (Graph + Vector)
|
||||
context = AgentContext(
|
||||
vector_store=VectorStore(backend="faiss"),
|
||||
knowledge_graph=GraphStore(backend="neo4j"), # Optional: Use persistent graph
|
||||
hybrid_alpha=0.75 # 75% weight to Knowledge Graph, 25% to Vector
|
||||
)
|
||||
|
||||
retriever = ContextRetriever(memory_store=memory)
|
||||
context = retriever.retrieve("What are user preferences?", max_results=5)
|
||||
# Build Context Graph from entities and relationships
|
||||
graph_stats = context.build_graph(
|
||||
entities=kg.get('entities', []),
|
||||
relationships=kg.get('relationships', []),
|
||||
link_entities=True
|
||||
)
|
||||
|
||||
# Store memory with automatic entity linking
|
||||
context.store(
|
||||
"User is building a RAG system with Semantica",
|
||||
metadata={"priority": "high", "topic": "rag"}
|
||||
)
|
||||
|
||||
# Use Context Retriever for hybrid retrieval
|
||||
retriever = context.retriever # Access underlying ContextRetriever
|
||||
results = retriever.retrieve(
|
||||
query="What is the user building?",
|
||||
max_results=10,
|
||||
use_graph_expansion=True
|
||||
)
|
||||
|
||||
# Retrieve with context expansion
|
||||
results = context.retrieve("What is the user building?", use_graph_expansion=True)
|
||||
|
||||
# Query with reasoning and LLM-generated responses
|
||||
llm_provider = Groq(model="llama-3.1-8b-instant", api_key=os.getenv("GROQ_API_KEY"))
|
||||
reasoned_result = context.query_with_reasoning(
|
||||
query="What is the user building?",
|
||||
llm_provider=llm_provider,
|
||||
max_hops=2
|
||||
)
|
||||
```
|
||||
|
||||
[**Cookbook: Vector Store**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/13_Vector_Store.ipynb) • [**Embedding Generation**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/12_Embedding_Generation.ipynb) • [**Context Module**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/19_Context_Module.ipynb) • [**Advanced Vector Store**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/Advanced_Vector_Store_and_Search.ipynb)
|
||||
**Core Components:**
|
||||
- **ContextGraph**: Builds and manages context graphs from entities and relationships for enhanced retrieval
|
||||
- **ContextRetriever**: Performs hybrid retrieval combining vector search, graph traversal, and memory for optimal context relevance
|
||||
- **AgentContext**: High-level interface integrating Context Graph and Context Retriever for GraphRAG applications
|
||||
|
||||
**Core Notebooks:**
|
||||
- [**Context Module Introduction**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/19_Context_Module.ipynb) - Basic memory and storage.
|
||||
- [**Advanced Context Engineering**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/11_Advanced_Context_Engineering.ipynb) - Hybrid retrieval, graph builders, and custom memory policies.
|
||||
- [**Fraud Detection**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/use_cases/finance/02_Fraud_Detection.ipynb) - Demonstrates Context Graph and Context Retriever for fraud detection with GraphRAG.
|
||||
|
||||
**Related Components:**
|
||||
[**Vector Store**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/13_Vector_Store.ipynb) • [**Embedding Generation**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/12_Embedding_Generation.ipynb) • [**Advanced Vector Store**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/Advanced_Vector_Store_and_Search.ipynb)
|
||||
|
||||
### Knowledge Graph-Powered RAG (GraphRAG)
|
||||
|
||||
> **30% Accuracy Improvement** • Vector + Graph Hybrid Search • 91% Accuracy
|
||||
> **30% Accuracy Improvement** • Vector + Graph Hybrid Search • 91% Accuracy • **Multi-Hop Reasoning** • **LLM-Generated Responses**
|
||||
|
||||
```python
|
||||
from semantica.qa_rag import GraphRAGEngine
|
||||
from semantica.context import AgentContext
|
||||
from semantica.llms import Groq, OpenAI, LiteLLM
|
||||
from semantica.vector_store import VectorStore
|
||||
import os
|
||||
|
||||
graphrag = GraphRAGEngine(
|
||||
# Initialize GraphRAG with hybrid retrieval
|
||||
context = AgentContext(
|
||||
vector_store=VectorStore(backend="faiss"),
|
||||
knowledge_graph=kg
|
||||
)
|
||||
result = graphrag.query("Who founded the company?", top_k=5, expand_graph=True)
|
||||
print(f"Answer: {result.answer} (Confidence: {result.confidence:.2f})")
|
||||
|
||||
# Configure LLM provider (supports Groq, OpenAI, HuggingFace, LiteLLM)
|
||||
llm_provider = Groq(
|
||||
model="llama-3.1-8b-instant",
|
||||
api_key=os.getenv("GROQ_API_KEY")
|
||||
)
|
||||
|
||||
# Query with multi-hop reasoning and LLM-generated responses
|
||||
result = context.query_with_reasoning(
|
||||
query="What IPs are associated with security alerts?",
|
||||
llm_provider=llm_provider,
|
||||
max_results=10,
|
||||
max_hops=2
|
||||
)
|
||||
|
||||
print(f"Response: {result['response']}")
|
||||
print(f"Reasoning Path: {result['reasoning_path']}")
|
||||
print(f"Confidence: {result['confidence']:.3f}")
|
||||
```
|
||||
|
||||
[**Cookbook: GraphRAG**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/use_cases/advanced_rag/01_GraphRAG_Complete.ipynb)
|
||||
**Key Features:**
|
||||
- **Multi-Hop Reasoning**: Traverses knowledge graph up to N hops to find related entities
|
||||
- **LLM-Generated Responses**: Natural language answers grounded in graph context
|
||||
- **Reasoning Trace**: Shows entity relationship paths used in reasoning
|
||||
- **Multiple LLM Providers**: Supports Groq, OpenAI, HuggingFace, and LiteLLM (100+ LLMs)
|
||||
|
||||
[**Cookbook: GraphRAG**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/use_cases/advanced_rag/01_GraphRAG_Complete.ipynb) • [**Real-Time Anomaly Detection**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/use_cases/cybersecurity/01_Real_Time_Anomaly_Detection.ipynb)
|
||||
|
||||
### LLM Providers Module
|
||||
|
||||
> **Unified LLM Interface** • **100+ LLM Support via LiteLLM** • **Clean Imports** • **Multiple Providers**
|
||||
|
||||
```python
|
||||
from semantica.llms import Groq, OpenAI, HuggingFaceLLM, LiteLLM
|
||||
import os
|
||||
|
||||
# Groq - Fast inference
|
||||
groq = Groq(
|
||||
model="llama-3.1-8b-instant",
|
||||
api_key=os.getenv("GROQ_API_KEY")
|
||||
)
|
||||
response = groq.generate("What is AI?")
|
||||
|
||||
# OpenAI
|
||||
openai = OpenAI(
|
||||
model="gpt-4",
|
||||
api_key=os.getenv("OPENAI_API_KEY")
|
||||
)
|
||||
response = openai.generate("What is AI?")
|
||||
|
||||
# HuggingFace - Local models
|
||||
hf = HuggingFaceLLM(model_name="gpt2")
|
||||
response = hf.generate("What is AI?")
|
||||
|
||||
# LiteLLM - Unified interface to 100+ LLMs
|
||||
litellm = LiteLLM(
|
||||
model="openai/gpt-4o", # or "anthropic/claude-sonnet-4-20250514", "groq/llama-3.1-8b-instant", etc.
|
||||
api_key=os.getenv("OPENAI_API_KEY")
|
||||
)
|
||||
response = litellm.generate("What is AI?")
|
||||
|
||||
# Structured output
|
||||
structured = groq.generate_structured("Extract entities from: Apple Inc. was founded by Steve Jobs.")
|
||||
```
|
||||
|
||||
**Supported Providers:**
|
||||
- **Groq**: Fast inference with Llama models
|
||||
- **OpenAI**: GPT-3.5, GPT-4, and other OpenAI models
|
||||
- **HuggingFace**: Local LLM inference with Transformers
|
||||
- **LiteLLM**: Unified interface to 100+ LLM providers (OpenAI, Anthropic, Azure, Bedrock, Vertex AI, and more)
|
||||
|
||||
### Reasoning & Inference Engine
|
||||
|
||||
> **Rule-based Inference** • **Forward/Backward Chaining** • **Rete Algorithm** • **Explanation Generation**
|
||||
|
||||
```python
|
||||
from semantica.reasoning import Reasoner
|
||||
|
||||
# Initialize Reasoner
|
||||
reasoner = Reasoner()
|
||||
|
||||
# Define rules and facts
|
||||
rules = ["IF Parent(?a, ?b) AND Parent(?b, ?c) THEN Grandparent(?a, ?c)"]
|
||||
facts = ["Parent(Alice, Bob)", "Parent(Bob, Charlie)"]
|
||||
|
||||
# Infer new facts (Forward Chaining)
|
||||
inferred = reasoner.infer_facts(facts, rules)
|
||||
print(f"Inferred: {inferred}") # ['Grandparent(Alice, Charlie)']
|
||||
|
||||
# Explain reasoning
|
||||
from semantica.reasoning import ExplanationGenerator
|
||||
explainer = ExplanationGenerator()
|
||||
# ... generate explanation for inferred facts
|
||||
```
|
||||
|
||||
[**Cookbook: Reasoning**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/08_Reasoning_and_Inference.ipynb) • [**Rete Engine**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/09_Rete_Engine.ipynb)
|
||||
|
||||
### Pipeline Orchestration & Parallel Processing
|
||||
|
||||
@@ -392,7 +584,7 @@ pipeline = PipelineBuilder() \
|
||||
result = ExecutionEngine().execute_pipeline(pipeline, parallel=True)
|
||||
```
|
||||
|
||||
[**Cookbook: Pipeline Orchestration**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/07_Pipeline_Orchestration.ipynb)
|
||||
|
||||
|
||||
### Production-Ready Quality Assurance
|
||||
|
||||
@@ -402,43 +594,87 @@ result = ExecutionEngine().execute_pipeline(pipeline, parallel=True)
|
||||
from semantica.deduplication import DuplicateDetector
|
||||
from semantica.conflicts import ConflictDetector
|
||||
|
||||
conflicts = ConflictDetector().detect_conflicts(kg)
|
||||
duplicates = DuplicateDetector().find_duplicates(entities=kg.entities, similarity_threshold=0.85)
|
||||
entities = kg.get("entities", [])
|
||||
conflicts = ConflictDetector().detect_conflicts(entities)
|
||||
duplicates = DuplicateDetector(similarity_threshold=0.85).detect_duplicates(entities)
|
||||
|
||||
print(f"Conflicts: {len(conflicts)} | Duplicates: {len(duplicates)}")
|
||||
```
|
||||
|
||||
[**Cookbook: Conflict Detection**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/17_Conflict_Detection.ipynb) • [**Deduplication**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/18_Deduplication.ipynb) • [**Graph Quality**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/11_Graph_Quality.ipynb) • [**Conflict Resolution**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/04_Conflict_Resolution_Strategies.ipynb)
|
||||
[**Cookbook: Conflict Detection & Resolution**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/17_Conflict_Detection_and_Resolution.ipynb) • [**Deduplication**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/18_Deduplication.ipynb)
|
||||
|
||||
### Export & Integration
|
||||
### Visualization & Export
|
||||
|
||||
> **Multi-Format Export** • JSON, CSV, RDF, GraphML
|
||||
> **Interactive graphs** • **Multi-format export** • **Graph analytics**
|
||||
|
||||
```python
|
||||
from semantica.visualization import KGVisualizer
|
||||
from semantica.export import GraphExporter
|
||||
|
||||
exporter = GraphExporter(kg)
|
||||
exporter.export("graph.json", format="json")
|
||||
exporter.export("graph.ttl", format="turtle")
|
||||
# Visualize knowledge graph
|
||||
viz = KGVisualizer(layout="force")
|
||||
fig = viz.visualize_network(kg, output="interactive")
|
||||
fig.show()
|
||||
|
||||
# Export to multiple formats
|
||||
exporter = GraphExporter()
|
||||
exporter.export(kg, format="json", output_path="graph.json")
|
||||
exporter.export(kg, format="graphml", output_path="graph.graphml")
|
||||
```
|
||||
|
||||
[**Cookbook: Export**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/15_Export.ipynb) • [**Multi-Format Export**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/05_Multi_Format_Export.ipynb) • [**Multi-Source Integration**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/06_Multi_Source_Data_Integration.ipynb)
|
||||
[**Cookbook: Visualization**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/16_Visualization.ipynb) • [**Export**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/15_Export.ipynb)
|
||||
|
||||
### Seed Data Integration
|
||||
|
||||
> **Foundation data** • **Entity resolution** • **Domain knowledge**
|
||||
|
||||
```python
|
||||
from semantica.seed import SeedDataManager
|
||||
|
||||
seed_manager = SeedDataManager()
|
||||
seed_manager.seed_data.entities = [
|
||||
{"id": "s1", "text": "Supplier A", "type": "Supplier", "source": "foundation", "verified": True}
|
||||
]
|
||||
|
||||
# Use seed data for entity resolution
|
||||
resolved = seed_manager.resolve_entities(extracted_entities)
|
||||
```
|
||||
|
||||
[**Cookbook: Seed Data**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/advanced/07_Seed_Data_Integration.ipynb)
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
> **For comprehensive examples, see the [**Cookbook**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook) with 50+ interactive notebooks!**
|
||||
> **For comprehensive examples, see the [**Cookbook**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook) with interactive notebooks!**
|
||||
|
||||
```python
|
||||
from semantica import Semantica
|
||||
from semantica.semantic_extract import NERExtractor, RelationExtractor
|
||||
from semantica.kg import GraphBuilder
|
||||
from semantica.context import AgentContext, ContextGraph
|
||||
from semantica.vector_store import VectorStore
|
||||
|
||||
# Initialize and build knowledge graph
|
||||
core = Semantica(ner_model="transformer", relation_strategy="hybrid")
|
||||
documents = ["doc1.txt", "doc2.txt", "doc3.txt"]
|
||||
kg = core.build_knowledge_graph(documents, merge_entities=True)
|
||||
# Extract entities and relationships
|
||||
ner_extractor = NERExtractor(method="ml", model="en_core_web_sm")
|
||||
relation_extractor = RelationExtractor(method="dependency", model="en_core_web_sm")
|
||||
|
||||
# Query the graph
|
||||
result = kg.query("Who founded the company?", return_format="structured")
|
||||
print(f"Answer: {result.answer} | Nodes: {kg.node_count}, Edges: {kg.edge_count}")
|
||||
text = "Apple Inc. was founded by Steve Jobs in 1976."
|
||||
entities = ner_extractor.extract(text)
|
||||
relationships = relation_extractor.extract(text, entities=entities)
|
||||
|
||||
# Build knowledge graph
|
||||
builder = GraphBuilder()
|
||||
kg = builder.build({"entities": entities, "relationships": relationships})
|
||||
|
||||
# Query using GraphRAG
|
||||
vector_store = VectorStore(backend="faiss", dimension=384)
|
||||
context_graph = ContextGraph()
|
||||
context_graph.build_from_entities_and_relationships(
|
||||
entities=kg.get('entities', []),
|
||||
relationships=kg.get('relationships', [])
|
||||
)
|
||||
context = AgentContext(vector_store=vector_store, knowledge_graph=context_graph)
|
||||
|
||||
results = context.retrieve("Who founded Apple?", max_results=5)
|
||||
print(f"Found {len(results)} results")
|
||||
```
|
||||
|
||||
[**Cookbook: Your First Knowledge Graph**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/08_Your_First_Knowledge_Graph.ipynb)
|
||||
@@ -449,7 +685,7 @@ print(f"Answer: {result.answer} | Nodes: {kg.node_count}, Edges: {kg.edge_count}
|
||||
|
||||
**AI Agents & Autonomous Systems** — Build agents with persistent memory and semantic understanding.
|
||||
|
||||
**Multi-Format Document Processing** — Process 50+ formats through a unified pipeline.
|
||||
**Multi-Format Document Processing** — Process multiple formats through a unified pipeline.
|
||||
|
||||
**Data Pipeline Processing** — Build scalable pipelines with parallel execution.
|
||||
|
||||
@@ -457,19 +693,74 @@ print(f"Answer: {result.answer} | Nodes: {kg.node_count}, Edges: {kg.edge_count}
|
||||
|
||||
**Finance & Trading** — Fraud detection, market intelligence, risk assessment.
|
||||
|
||||
**Healthcare & Biomedical** — Clinical reports, drug discovery, medical literature analysis.
|
||||
**Biomedical** — Drug discovery, medical literature analysis.
|
||||
|
||||
[**Explore Use Case Examples**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/use_cases) — See real-world implementations in finance, healthcare, cybersecurity, trading, and more.
|
||||
|
||||
|
||||
## 🍳 Semantica Cookbook
|
||||
|
||||
> **Interactive Jupyter Notebooks** designed to take you from beginner to expert.
|
||||
|
||||
[**View Full Cookbook**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook)
|
||||
|
||||
### Featured Recipes
|
||||
|
||||
| **Recipe** | **Description** | **Link** |
|
||||
|:-----------|:----------------|:---------|
|
||||
| **GraphRAG Complete** | Build a production-ready **Graph Retrieval Augmented Generation** system. Features **Graph Validation**, **Hybrid Retrieval**, and **Logical Inference**. | [Open Notebook](cookbook/use_cases/advanced_rag/01_GraphRAG_Complete.ipynb) |
|
||||
| **RAG vs. GraphRAG** | Side-by-side comparison. Demonstrates the **Reasoning Gap** and how GraphRAG solves it with **Inference Engines**. | [Open Notebook](cookbook/use_cases/advanced_rag/02_RAG_vs_GraphRAG_Comparison.ipynb) |
|
||||
| **First Knowledge Graph** | Go from raw text to a queryable knowledge graph in 20 minutes. | [Open Notebook](cookbook/introduction/08_Your_First_Knowledge_Graph.ipynb) |
|
||||
| **Real-Time Anomalies** | Detect anomalies in streaming data using temporal knowledge graphs and pattern detection. | [Open Notebook](cookbook/use_cases/cybersecurity/01_Real_Time_Anomaly_Detection.ipynb) |
|
||||
|
||||
### Core Tutorials
|
||||
|
||||
- [**Welcome to Semantica**](cookbook/introduction/01_Welcome_to_Semantica.ipynb) - Framework Overview
|
||||
- [**Data Ingestion**](cookbook/introduction/02_Data_Ingestion.ipynb) - Universal Ingestion
|
||||
- [**Entity Extraction**](cookbook/introduction/05_Entity_Extraction.ipynb) - NER & Relationships
|
||||
- [**Building Knowledge Graphs**](cookbook/introduction/07_Building_Knowledge_Graphs.ipynb) - Graph Construction
|
||||
|
||||
### Industry Use Cases (14 Cookbooks)
|
||||
|
||||
**Domain-Specific Cookbooks** showcasing real-world applications with real data sources, advanced chunking strategies, temporal KGs, GraphRAG, and comprehensive Semantica module integration:
|
||||
|
||||
#### Biomedical
|
||||
- [**Drug Discovery Pipeline**](cookbook/use_cases/biomedical/01_Drug_Discovery_Pipeline.ipynb) - PubMed RSS, entity-aware chunking, GraphRAG, vector similarity search
|
||||
- [**Genomic Variant Analysis**](cookbook/use_cases/biomedical/02_Genomic_Variant_Analysis.ipynb) - bioRxiv RSS, temporal KGs, deduplication, pathway analysis
|
||||
|
||||
#### Finance
|
||||
- [**Financial Data Integration MCP**](cookbook/use_cases/finance/01_Financial_Data_Integration_MCP.ipynb) - Alpha Vantage API, MCP servers, seed data, real-time ingestion
|
||||
- [**Fraud Detection**](cookbook/use_cases/finance/02_Fraud_Detection.ipynb) - Transaction streams, temporal KGs, pattern detection, conflict resolution, **Context Graph**, **Context Retriever**, GraphRAG with Groq LLM
|
||||
|
||||
#### Blockchain
|
||||
- [**DeFi Protocol Intelligence**](cookbook/use_cases/blockchain/01_DeFi_Protocol_Intelligence.ipynb) - CoinDesk RSS, ontology-aware chunking, conflict detection, ontology generation
|
||||
- [**Transaction Network Analysis**](cookbook/use_cases/blockchain/02_Transaction_Network_Analysis.ipynb) - Blockchain APIs, deduplication, network analytics
|
||||
|
||||
#### Cybersecurity
|
||||
- [**Real-Time Anomaly Detection**](cookbook/use_cases/cybersecurity/01_Real_Time_Anomaly_Detection.ipynb) - CVE RSS, Kafka streams, temporal KGs, sentence chunking
|
||||
- [**Threat Intelligence Hybrid RAG**](cookbook/use_cases/cybersecurity/02_Threat_Intelligence_Hybrid_RAG.ipynb) - Security RSS, entity-aware chunking, enhanced GraphRAG, deduplication
|
||||
|
||||
#### Intelligence & Law Enforcement
|
||||
- [**Criminal Network Analysis**](cookbook/use_cases/intelligence/01_Criminal_Network_Analysis.ipynb) - OSINT RSS, deduplication, network centrality, graph analytics
|
||||
- [**Intelligence Analysis Orchestrator Worker**](cookbook/use_cases/intelligence/02_Intelligence_Analysis_Orchestrator_Worker.ipynb) - Pipeline orchestrator, multi-source integration, conflict detection
|
||||
|
||||
#### Renewable Energy
|
||||
- [**Energy Market Analysis**](cookbook/use_cases/renewable_energy/01_Energy_Market_Analysis.ipynb) - Energy RSS, EIA API, temporal KGs, TemporalPatternDetector, trend prediction
|
||||
|
||||
#### Supply Chain
|
||||
- [**Supply Chain Data Integration**](cookbook/use_cases/supply_chain/01_Supply_Chain_Data_Integration.ipynb) - Logistics RSS, deduplication, relationship mapping
|
||||
|
||||
|
||||
[**Explore Use Case Examples**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/use_cases) — See real-world implementations in finance, biomedical, cybersecurity, and more. **14 comprehensive domain-specific cookbooks** with real data sources, advanced chunking strategies, temporal KGs, GraphRAG, and full Semantica module integration.
|
||||
|
||||
## 🔬 Advanced Features
|
||||
|
||||
**Incremental Updates** — Real-time stream processing with Kafka, RabbitMQ, Kinesis for live updates.
|
||||
|
||||
**Multi-Language Support** — Process 50+ languages with automatic detection.
|
||||
**Multi-Language Support** — Process multiple languages with automatic detection.
|
||||
|
||||
**Custom Ontology Import** — Import and extend Schema.org and custom ontologies.
|
||||
|
||||
**Advanced Reasoning** — Deductive, inductive, abductive reasoning with HermiT/Pellet.
|
||||
**Advanced Reasoning** — Forward/backward chaining, Rete-based pattern matching, and automated explanation generation.
|
||||
|
||||
**Graph Analytics** — Centrality, community detection, path finding, temporal analysis.
|
||||
|
||||
@@ -485,10 +776,11 @@ print(f"Answer: {result.answer} | Nodes: {kg.node_count}, Edges: {kg.edge_count}
|
||||
- [x] Core framework (v1.0)
|
||||
- [x] GraphRAG engine
|
||||
- [x] 6-stage ontology pipeline
|
||||
- [x] Advanced reasoning v2 (Rete, Forward/Backward Chaining)
|
||||
- [ ] Quality assurance features and Quality Assurance module
|
||||
- [ ] Enhanced multi-language support
|
||||
- [ ] Evals
|
||||
- [ ] Real-time streaming improvements
|
||||
- [ ] Advanced reasoning v2
|
||||
|
||||
### Q2 2026
|
||||
- [ ] Multi-modal processing
|
||||
@@ -501,7 +793,7 @@ print(f"Answer: {result.answer} | Nodes: {kg.node_count}, Edges: {kg.edge_count}
|
||||
|
||||
| **Channel** | **Purpose** |
|
||||
|:-----------:|:-----------|
|
||||
| [**Discord**](https://discord.gg/semantica) | Real-time help, showcases |
|
||||
| [**Discord**](https://discord.gg/pMHguUzG) | Real-time help, showcases |
|
||||
| [**GitHub Discussions**](https://github.com/Hawksight-AI/semantica/discussions) | Q&A, feature requests |
|
||||
|
||||
### Learning Resources
|
||||
@@ -509,14 +801,20 @@ print(f"Answer: {result.answer} | Nodes: {kg.node_count}, Edges: {kg.edge_count}
|
||||
|
||||
### Enterprise Support
|
||||
|
||||
| **Tier** | **Features** | **SLA** | **Price** |
|
||||
|:--------:|:-----------|:-------:|:--------:|
|
||||
| **Community** | Public support | Best effort | Free |
|
||||
| **Professional** | Email support | 48h | Contact |
|
||||
| **Enterprise** | 24/7 support | 4h | Contact |
|
||||
| **Premium** | Phone, custom dev | 1h | Contact |
|
||||
Enterprise support, professional services, and commercial licensing will be available in the future. For now, we offer community support through Discord and GitHub Discussions.
|
||||
|
||||
**Contact:** [GitHub Issues](https://github.com/Hawksight-AI/semantica/issues) with "[Enterprise]" prefix
|
||||
**Current Support:**
|
||||
- **Community Support** - Free support via [Discord](https://discord.gg/pMHguUzG) and [GitHub Discussions](https://github.com/Hawksight-AI/semantica/discussions)
|
||||
- **Bug Reports** - [GitHub Issues](https://github.com/Hawksight-AI/semantica/issues)
|
||||
|
||||
**Future Enterprise Offerings:**
|
||||
- Professional support with SLA
|
||||
- Enterprise licensing
|
||||
- Custom development services
|
||||
- Priority feature requests
|
||||
- Dedicated support channels
|
||||
|
||||
Stay tuned for updates!
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
@@ -550,13 +848,12 @@ git push origin feature/your-feature
|
||||
3. **Bug Reports** - [Create issue](https://github.com/Hawksight-AI/semantica/issues/new)
|
||||
4. **Feature Requests** - [Request feature](https://github.com/Hawksight-AI/semantica/issues/new)
|
||||
|
||||
### Recognition
|
||||
|
||||
Contributors receive:
|
||||
- Recognition in [CONTRIBUTORS.md](https://github.com/Hawksight-AI/semantica/blob/main/CONTRIBUTORS.md)
|
||||
- GitHub badges
|
||||
- Semantica swag
|
||||
- Featured showcases
|
||||
### Contributors
|
||||
|
||||
<a href="https://github.com/Hawksight-AI/semantica/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=Hawksight-AI/semantica" alt="Contributors" />
|
||||
</a>
|
||||
|
||||
## 📜 License
|
||||
|
||||
@@ -566,6 +863,6 @@ Semantica is licensed under the **MIT License** - see the [LICENSE](https://gith
|
||||
|
||||
**Built by the Semantica Community**
|
||||
|
||||
[GitHub](https://github.com/Hawksight-AI/semantica) • [Discord](https://discord.gg/semantica)
|
||||
[GitHub](https://github.com/Hawksight-AI/semantica) • [Discord](https://discord.gg/pMHguUzG)
|
||||
|
||||
</div>
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# Release Process for Semantica
|
||||
|
||||
This document outlines the steps to release a new version of the Semantica framework.
|
||||
|
||||
## 1. Versioning Policy
|
||||
|
||||
Semantica follows [Semantic Versioning (SemVer)](https://semver.org/).
|
||||
- **MAJOR** version for incompatible API changes.
|
||||
- **MINOR** version for functionality added in a backwards compatible manner.
|
||||
- **PATCH** version for backwards compatible bug fixes.
|
||||
|
||||
## 2. Pre-release Checklist
|
||||
|
||||
Before releasing, ensure:
|
||||
- [ ] All tests pass: `pytest`
|
||||
- [ ] Documentation is up to date in `docs/` and `MkDocs` config.
|
||||
- [ ] `CHANGELOG.md` is updated with the latest changes.
|
||||
- [ ] Version is updated in:
|
||||
- `semantica/__init__.py`
|
||||
- `pyproject.toml`
|
||||
- `docs/citation.md` (BibTeX entry)
|
||||
|
||||
## 3. Release Steps
|
||||
|
||||
### Automated Release (Recommended)
|
||||
|
||||
The project uses GitHub Actions for automated releases to PyPI.
|
||||
|
||||
1. **Tag the commit**: Create a new git tag for the version (e.g., `v0.1.1`).
|
||||
```bash
|
||||
git tag -a v0.1.1 -m "Release v0.1.1"
|
||||
git push origin v0.1.1
|
||||
```
|
||||
2. **GitHub Action**: The `Release` workflow will automatically trigger, build the package, create a GitHub Release, and publish to PyPI using Trusted Publishing.
|
||||
|
||||
### Manual Release
|
||||
|
||||
If you need to release manually:
|
||||
|
||||
1. **Build the package**:
|
||||
```bash
|
||||
python -m build
|
||||
```
|
||||
2. **Verify the build**:
|
||||
```bash
|
||||
twine check dist/*
|
||||
```
|
||||
3. **Upload to PyPI**:
|
||||
```bash
|
||||
twine upload dist/*
|
||||
```
|
||||
|
||||
## 4. Post-release
|
||||
|
||||
- Verify the new version is available on [PyPI](https://pypi.org/project/semantica/).
|
||||
- Check the [GitHub Releases](https://github.com/your-org/semantica/releases) page for the new release notes.
|
||||
+3
-2
@@ -6,8 +6,9 @@ We actively support the following versions of Semantica with security updates:
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 0.0.1 | :white_check_mark: |
|
||||
| < 0.0.1 | :x: |
|
||||
| 0.1.1 | :white_check_mark: |
|
||||
| 0.1.0 | :white_check_mark: |
|
||||
| < 0.1.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
# Deduplication & Conflict Resolution Strategies Summary
|
||||
|
||||
## Quick Reference by Use Case
|
||||
|
||||
| Use Case | Deduplication Method | Merge Strategy | Conflict Detection | Conflict Resolution |
|
||||
|----------|---------------------|----------------|-------------------|---------------------|
|
||||
| **Finance** |
|
||||
| `01_Financial_Data_Integration_MCP` | `DuplicateDetector` (incremental) | `keep_highest_confidence` | `temporal` | `most_recent` |
|
||||
| `02_Fraud_Detection` | `ClusterBuilder` (graph_based) | `merge_all` | `logical` | `expert_review` |
|
||||
| **Biomedical** |
|
||||
| `01_Drug_Discovery_Pipeline` | `EntityResolver` (semantic) | - | `relationship` | `voting` |
|
||||
| `02_Genomic_Variant_Analysis` | `DuplicateDetector` (group) | `keep_most_complete` | `value` | `credibility_weighted` |
|
||||
| **Cybersecurity** |
|
||||
| `01_Real_Time_Anomaly_Detection` | `DuplicateDetector` (pairwise) | `keep_first` | `entity` | `first_seen` |
|
||||
| `02_Threat_Intelligence_Hybrid_RAG` | `EntityResolver` (exact) | - | `type` | `highest_confidence` |
|
||||
| **Blockchain** |
|
||||
| `01_DeFi_Protocol_Intelligence` | `DuplicateDetector` (group) | `keep_last` | `relationship` | `voting` |
|
||||
| `02_Transaction_Network_Analysis` | `ClusterBuilder` (hierarchical) | `keep_most_complete` | `temporal` | `most_recent` |
|
||||
| **Intelligence** |
|
||||
| `01_Criminal_Network_Analysis` | `EntityResolver` (fuzzy) | - | `value` | `credibility_weighted` |
|
||||
| `02_Intelligence_Analysis_Orchestrator_Worker` | `DuplicateDetector` (batch) | `merge_all` | `entity` | `voting` |
|
||||
| **Renewable Energy** |
|
||||
| `01_Energy_Market_Analysis` | `DuplicateDetector` (pairwise) | `keep_highest_confidence` | `temporal` | `most_recent` |
|
||||
| **Supply Chain** |
|
||||
| `01_Supply_Chain_Data_Integration` | `DuplicateDetector` (incremental) | `keep_most_complete` | `value` | `credibility_weighted` |
|
||||
|
||||
---
|
||||
|
||||
## Strategy Rationale by Domain
|
||||
|
||||
### Finance
|
||||
- **Financial Data Integration**: Incremental for streaming data; most_recent for time-sensitive financial data
|
||||
- **Fraud Detection**: Graph-based clustering for fraud groups; expert_review for fraud assessment
|
||||
|
||||
### Biomedical
|
||||
- **Drug Discovery**: Semantic matching for drug compounds; voting for research source aggregation
|
||||
- **Genomic Variants**: Group method for related variants; credibility weighting for research sources
|
||||
|
||||
### Cybersecurity
|
||||
- **Real-Time Anomaly**: Pairwise for real-time streams; keep_first for first detection priority
|
||||
- **Threat Intelligence**: Exact matching for IOCs; highest_confidence for threat classification
|
||||
|
||||
### Blockchain
|
||||
- **DeFi Protocols**: Group method for related protocols; keep_last for latest protocol info
|
||||
- **Transaction Networks**: Hierarchical clustering for nested groups; temporal for time-sensitive data
|
||||
|
||||
### Intelligence
|
||||
- **Criminal Networks**: Fuzzy matching for intelligence data; credibility weighting for intelligence sources
|
||||
- **Intelligence Analysis**: Batch for multi-source integration; merge_all to combine all intelligence sources
|
||||
|
||||
### Renewable Energy
|
||||
- **Energy Markets**: Pairwise for real-time market data; most_recent for time-sensitive energy data
|
||||
|
||||
### Supply Chain
|
||||
- **Supply Chain Integration**: Incremental for continuous updates; credibility weighting for supply chain sources
|
||||
|
||||
---
|
||||
|
||||
## Method Distribution
|
||||
|
||||
### Deduplication Methods (9 total)
|
||||
- `pairwise`: 2 notebooks (real-time processing)
|
||||
- `batch`: 3 notebooks (large datasets)
|
||||
- `incremental`: 2 notebooks (streaming/continuous)
|
||||
- `group`: 2 notebooks (related entities)
|
||||
- `graph_based` (ClusterBuilder): 2 notebooks (interconnected entities)
|
||||
- `hierarchical` (ClusterBuilder): 1 notebook (nested groups)
|
||||
- `exact` (EntityResolver): 1 notebook (exact matching)
|
||||
- `semantic` (EntityResolver): 2 notebooks (semantic similarity)
|
||||
- `fuzzy` (EntityResolver): 1 notebook (fuzzy matching)
|
||||
|
||||
### Merge Strategies (5 total)
|
||||
- `keep_first`: 1 notebook (first detection priority)
|
||||
- `keep_last`: 1 notebook (latest information)
|
||||
- `keep_most_complete`: 5 notebooks (preserve all details)
|
||||
- `keep_highest_confidence`: 2 notebooks (most reliable data)
|
||||
- `merge_all`: 3 notebooks (combine all information)
|
||||
|
||||
### Conflict Detection Methods (6 total)
|
||||
- `value`: 4 notebooks (property value conflicts)
|
||||
- `type`: 2 notebooks (type/classification conflicts)
|
||||
- `entity`: 2 notebooks (entity-wide conflicts)
|
||||
- `relationship`: 3 notebooks (relationship conflicts)
|
||||
- `temporal`: 3 notebooks (time-sensitive conflicts)
|
||||
- `logical`: 2 notebooks (logical inconsistencies)
|
||||
|
||||
### Conflict Resolution Strategies (6 total)
|
||||
- `voting`: 5 notebooks (majority vote)
|
||||
- `credibility_weighted`: 4 notebooks (source credibility)
|
||||
- `most_recent`: 3 notebooks (latest data)
|
||||
- `first_seen`: 1 notebook (first detection)
|
||||
- `highest_confidence`: 2 notebooks (most confident)
|
||||
- `expert_review`: 1 notebook (manual review)
|
||||
|
||||
---
|
||||
|
||||
## Key Patterns
|
||||
|
||||
1. **Real-Time Systems**: Use `pairwise` + `keep_first` + `first_seen`
|
||||
2. **Time-Sensitive Data**: Use `temporal` + `most_recent`
|
||||
3. **Multi-Source Integration**: Use `batch` + `merge_all` + `voting`
|
||||
4. **Medical/Research**: Use `credibility_weighted` for authoritative sources
|
||||
5. **Fraud/Security**: Use `graph_based` + `logical` + `expert_review`
|
||||
6. **Exact Matching Required**: Use `exact` strategy (IOCs, identifiers)
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ Start with our comprehensive documentation:
|
||||
|
||||
**Best for**: Real-time chat and quick questions
|
||||
|
||||
- [Join Discord](https://discord.gg/semantica)
|
||||
- [Join Discord](https://discord.gg/pMHguUzG)
|
||||
|
||||
#### GitHub Issues
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates advanced semantic extraction using EventDetector, CoreferenceResolver, TripleExtractor, SemanticAnalyzer, SemanticNetworkExtractor, LLMEnhancer, and ExtractionValidator.\n",
|
||||
"This notebook demonstrates advanced semantic extraction using EventDetector, CoreferenceResolver, TripletExtractor, SemanticAnalyzer, SemanticNetworkExtractor, LLMEnhancer, and ExtractionValidator.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/semantic_extract/)\n",
|
||||
@@ -19,7 +19,7 @@
|
||||
"\n",
|
||||
"- Use EventDetector to detect events\n",
|
||||
"- Use CoreferenceResolver to resolve coreferences\n",
|
||||
"- Use TripleExtractor to extract RDF triples\n",
|
||||
"- Use TripletExtractor to extract RDF triplets\n",
|
||||
"- Use SemanticAnalyzer for semantic analysis\n",
|
||||
"- Use SemanticNetworkExtractor to extract semantic networks\n",
|
||||
"- Use LLMEnhancer for LLM-based enhancement\n",
|
||||
@@ -37,7 +37,16 @@
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Workflow: Event Detection → Coreference Resolution → Triple Extraction → Semantic Analysis → Network Extraction → LLM Enhancement → Validation\n"
|
||||
"## Workflow: Event Detection → Coreference Resolution → Triplet Extraction → Semantic Analysis → Network Extraction → LLM Enhancement → Validation\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -q semantica"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -47,7 +56,7 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.semantic_extract import (\n",
|
||||
" EventDetector, CoreferenceResolver, TripleExtractor,\n",
|
||||
" EventDetector, CoreferenceResolver, TripletExtractor,\n",
|
||||
" SemanticAnalyzer, SemanticNetworkExtractor, LLMEnhancer, ExtractionValidator\n",
|
||||
")\n",
|
||||
"\n",
|
||||
@@ -58,7 +67,7 @@
|
||||
"\n",
|
||||
"print(f\"Detected {len(events)} events\")\n",
|
||||
"for event in events[:3]:\n",
|
||||
" print(f\" Event: {event.get('type', 'Unknown')} - {event.get('text', '')[:50]}\")\n"
|
||||
" print(f\" Event: {event.event_type} - {event.text[:50]}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -87,9 +96,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Triple Extraction\n",
|
||||
"## Step 3: Triplet Extraction\n",
|
||||
"\n",
|
||||
"Extract RDF triples.\n"
|
||||
"Extract RDF triplets.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -98,13 +107,13 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"triple_extractor = TripleExtractor()\n",
|
||||
"triplet_extractor = TripletExtractor()\n",
|
||||
"\n",
|
||||
"triples = triple_extractor.extract_triples(text)\n",
|
||||
"triplets = triplet_extractor.extract_triplets(text)\n",
|
||||
"\n",
|
||||
"print(f\"Extracted {len(triples)} triples\")\n",
|
||||
"for triple in triples[:3]:\n",
|
||||
" print(f\" ({triple.get('subject', '')}, {triple.get('predicate', '')}, {triple.get('object', '')})\")\n"
|
||||
"print(f\"Extracted {len(triplets)} triplets\")\n",
|
||||
"for triplet in triplets[:3]:\n",
|
||||
" print(f\" ({triplet.get('subject', '')}, {triplet.get('predicate', '')}, {triplet.get('object', '')})\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -208,7 +217,7 @@
|
||||
"\n",
|
||||
"- **EventDetector**: Event detection and classification\n",
|
||||
"- **CoreferenceResolver**: Coreference resolution\n",
|
||||
"- **TripleExtractor**: RDF triple extraction\n",
|
||||
"- **TripletExtractor**: RDF triplet extraction\n",
|
||||
"- **SemanticAnalyzer**: Semantic analysis and role labeling\n",
|
||||
"- **SemanticNetworkExtractor**: Semantic network extraction\n",
|
||||
"- **LLMEnhancer**: LLM-based extraction enhancement\n",
|
||||
@@ -217,8 +226,22 @@
|
||||
}
|
||||
],
|
||||
"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.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -4,39 +4,30 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/02_Advanced_Graph_Analytics.ipynb)\n",
|
||||
"# Graph Analytics \n",
|
||||
"\n",
|
||||
"# Advanced Graph Analytics\n",
|
||||
"Welcome to the **comprehensive walkthrough** of Semantica's Graph Analytics capabilities. This notebook goes beyond simple graph construction to demonstrate a full-lifecycle production pipeline.\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"We will simulate a messy, real-world scenario involving a **Startup Ecosystem** (Investors, Startups, Founders) and guide you through every step of the process:\n",
|
||||
"\n",
|
||||
"This notebook demonstrates advanced graph analytics using GraphAnalyzer, CentralityCalculator, CommunityDetector, ConnectivityAnalyzer, GraphValidator, Deduplicator, and **GraphStore** for persistent storage.\n",
|
||||
"1. **Validation**: Catching bad data before it enters the graph.\n",
|
||||
"2. **Cleaning**: Deduplicating entities and resolving conflicts.\n",
|
||||
"3. **Structural Analysis**: Understanding the shape and health of your network.\n",
|
||||
"4. **Deep Analytics**: Centrality, Communities, and Path Finding.\n",
|
||||
"5. **Temporal Analytics**: Time-traveling through your graph data.\n",
|
||||
"6. **Provenance**: Tracking where your data came from.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/kg/)\n",
|
||||
"\n",
|
||||
"### Learning Objectives\n",
|
||||
"\n",
|
||||
"- Use GraphAnalyzer for comprehensive graph analysis\n",
|
||||
"- Use CentralityCalculator for advanced centrality measures\n",
|
||||
"- Use CommunityDetector for community detection\n",
|
||||
"- Use ConnectivityAnalyzer for connectivity analysis\n",
|
||||
"- Use GraphValidator and Deduplicator for graph quality\n",
|
||||
"- **Use GraphStore to persist graphs to Neo4j or FalkorDB**\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: Graph Analysis → Centrality → Communities → Connectivity → Validation → Deduplication → **Persist to Graph Store**\n"
|
||||
"Let's dive in!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "695d435c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -q semantica"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -45,221 +36,360 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.kg import GraphBuilder, GraphAnalyzer, CentralityCalculator, CommunityDetector, ConnectivityAnalyzer, GraphValidator\n",
|
||||
"from semantica.deduplication import DuplicateDetector, EntityMerger, MergeStrategy\n",
|
||||
"import logging\n",
|
||||
"import json\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"builder = GraphBuilder()\n",
|
||||
"analyzer = GraphAnalyzer()\n",
|
||||
"# Set up logging to see what's happening under the hood\n",
|
||||
"logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')\n",
|
||||
"\n",
|
||||
"entities = [\n",
|
||||
" {\"id\": \"e1\", \"type\": \"Organization\", \"name\": \"Apple Inc.\", \"properties\": {}},\n",
|
||||
" {\"id\": \"e2\", \"type\": \"Person\", \"name\": \"Tim Cook\", \"properties\": {}},\n",
|
||||
" {\"id\": \"e3\", \"type\": \"Location\", \"name\": \"Cupertino\", \"properties\": {}}\n",
|
||||
"# Import all the powerful tools from Semantica\n",
|
||||
"from semantica.kg import (\n",
|
||||
" GraphBuilder,\n",
|
||||
" GraphAnalyzer,\n",
|
||||
" GraphValidator,\n",
|
||||
" ConnectivityAnalyzer,\n",
|
||||
" CentralityCalculator,\n",
|
||||
" CommunityDetector,\n",
|
||||
" TemporalGraphQuery,\n",
|
||||
" ProvenanceTracker\n",
|
||||
")\n",
|
||||
"from semantica.deduplication import DuplicateDetector\n",
|
||||
"from semantica.conflicts import ConflictDetector, ConflictResolver"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. The Scenario: A Messy Startup Ecosystem\n",
|
||||
"\n",
|
||||
"We have data from multiple sources (scrapers, news, user submissions). It's messy:\n",
|
||||
"- **Duplicates**: \"TechFlow AI\" and \"TechFlow Inc.\"\n",
|
||||
"- **Conflicts**: Different revenue numbers for the same company.\n",
|
||||
"- **Errors**: Relationships pointing to non-existent nodes (dangling edges).\n",
|
||||
"- **History**: Investment rounds happening at different times."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Our \"Raw\" Messy Data\n",
|
||||
"raw_entities = [\n",
|
||||
" {\"id\": \"startup_1\", \"type\": \"Startup\", \"name\": \"TechFlow AI\", \"revenue\": 1000000, \"founded\": \"2021-01-01\"},\n",
|
||||
" {\"id\": \"startup_2\", \"type\": \"Startup\", \"name\": \"GreenEnergy Co\", \"revenue\": 500000, \"founded\": \"2020-05-15\"},\n",
|
||||
" {\"id\": \"startup_1_dup\", \"type\": \"Startup\", \"name\": \"TechFlow Inc.\", \"revenue\": 1200000, \"founded\": \"2021-01-01\"}, # Duplicate!\n",
|
||||
" {\"id\": \"investor_1\", \"type\": \"Investor\", \"name\": \"Venture Capital X\"},\n",
|
||||
" {\"id\": \"founder_1\", \"type\": \"Person\", \"name\": \"Alice Chen\"},\n",
|
||||
" {\"id\": \"founder_2\", \"type\": \"Person\", \"name\": \"Bob Smith\"}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"relationships = [\n",
|
||||
" {\"source\": \"e2\", \"target\": \"e1\", \"type\": \"CEO_of\", \"properties\": {}},\n",
|
||||
" {\"source\": \"e1\", \"target\": \"e3\", \"type\": \"located_in\", \"properties\": {}}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"kg = builder.build(entities, relationships)\n",
|
||||
"\n",
|
||||
"metrics = analyzer.compute_metrics(kg)\n",
|
||||
"\n",
|
||||
"print(f\"Graph metrics:\")\n",
|
||||
"print(f\" Entities: {metrics.get('entity_count', 0)}\")\n",
|
||||
"print(f\" Relationships: {metrics.get('relationship_count', 0)}\")\n",
|
||||
"print(f\" Density: {metrics.get('density', 0):.3f}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Advanced Centrality Measures\n",
|
||||
"\n",
|
||||
"Calculate multiple centrality measures.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"centrality_calculator = CentralityCalculator()\n",
|
||||
"\n",
|
||||
"degree_centrality_result = centrality_calculator.calculate_degree_centrality(kg)\n",
|
||||
"degree_centrality = degree_centrality_result.get('centrality', {})\n",
|
||||
"betweenness_centrality_result = centrality_calculator.calculate_betweenness_centrality(kg)\n",
|
||||
"betweenness_centrality = betweenness_centrality_result.get('centrality', {})\n",
|
||||
"\n",
|
||||
"print(f\"Degree centrality: {len(degree_centrality)} entities\")\n",
|
||||
"print(f\"Betweenness centrality: {len(betweenness_centrality)} entities\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Community Detection\n",
|
||||
"\n",
|
||||
"Detect communities in the graph.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"community_detector = CommunityDetector()\n",
|
||||
"\n",
|
||||
"communities = community_detector.detect_communities(kg)\n",
|
||||
"\n",
|
||||
"print(f\"Detected {len(communities)} communities\")\n",
|
||||
"for i, community in enumerate(communities[:3], 1):\n",
|
||||
" print(f\" Community {i}: {len(community)} entities\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Connectivity Analysis\n",
|
||||
"\n",
|
||||
"Analyze graph connectivity.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"connectivity_analyzer = ConnectivityAnalyzer()\n",
|
||||
"\n",
|
||||
"connectivity = connectivity_analyzer.analyze_connectivity(kg)\n",
|
||||
"\n",
|
||||
"print(f\"Connectivity analysis:\")\n",
|
||||
"print(f\" Is connected: {connectivity.get('is_connected', False)}\")\n",
|
||||
"print(f\" Components: {len(connectivity.get('components', []))}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Graph Validation and Deduplication\n",
|
||||
"\n",
|
||||
"Validate and deduplicate the graph.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"graph_validator = GraphValidator()\n",
|
||||
"\n",
|
||||
"validation_result = graph_validator.validate(kg)\n",
|
||||
"\n",
|
||||
"print(f\"Graph validation: {validation_result.get('valid', False)}\")\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"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 6: Persist to Graph Store\n",
|
||||
"\n",
|
||||
"Store the analyzed graph in a persistent graph database using GraphStore.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.graph_store import GraphStore\n",
|
||||
"\n",
|
||||
"# Option 1: Neo4j (requires Neo4j server running)\n",
|
||||
"graph_store = GraphStore(backend=\"neo4j\", uri=\"bolt://localhost:7687\", user=\"neo4j\", password=\"password\")\n",
|
||||
"graph_store.connect()\n",
|
||||
"\n",
|
||||
"# Store entities as nodes and track node ID mapping\n",
|
||||
"node_id_map = {}\n",
|
||||
"for entity in entities:\n",
|
||||
" node = graph_store.create_node(\n",
|
||||
" labels=[entity[\"type\"]],\n",
|
||||
" properties={\"name\": entity[\"name\"], \"original_id\": entity[\"id\"]}\n",
|
||||
" )\n",
|
||||
" node_id_map[entity[\"id\"]] = node.get(\"id\")\n",
|
||||
" print(f\"Stored node: {entity['name']} (ID: {node.get('id')})\")\n",
|
||||
"\n",
|
||||
"# Store relationships using mapped node IDs\n",
|
||||
"for rel in relationships:\n",
|
||||
" source_id = node_id_map.get(rel[\"source\"])\n",
|
||||
" target_id = node_id_map.get(rel[\"target\"])\n",
|
||||
"raw_relationships = [\n",
|
||||
" # Valid Relationships\n",
|
||||
" {\"source\": \"founder_1\", \"target\": \"startup_1\", \"type\": \"FOUNDED\", \"valid_from\": \"2021-01-01\"},\n",
|
||||
" {\"source\": \"investor_1\", \"target\": \"startup_1\", \"type\": \"INVESTED_IN\", \"amount\": 5000000, \"valid_from\": \"2023-06-01\"},\n",
|
||||
" \n",
|
||||
" if source_id is not None and target_id is not None:\n",
|
||||
" relationship = graph_store.create_relationship(\n",
|
||||
" start_node_id=source_id,\n",
|
||||
" end_node_id=target_id,\n",
|
||||
" rel_type=rel[\"type\"],\n",
|
||||
" properties=rel.get(\"properties\", {})\n",
|
||||
" )\n",
|
||||
" print(f\"Stored relationship: {rel['source']} -{rel['type']}-> {rel['target']}\")\n",
|
||||
" else:\n",
|
||||
" print(f\"Warning: Could not find node IDs for relationship {rel['source']} -> {rel['target']}\")\n",
|
||||
" # Dangling Edge (Error!)\n",
|
||||
" {\"source\": \"founder_2\", \"target\": \"startup_999\", \"type\": \"FOUNDED\", \"valid_from\": \"2020-05-15\"}, \n",
|
||||
" \n",
|
||||
" # Temporal Data (History)\n",
|
||||
" {\"source\": \"founder_1\", \"target\": \"startup_2\", \"type\": \"ADVISED\", \"valid_from\": \"2020-01-01\", \"valid_until\": \"2021-01-01\"}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Query using Cypher\n",
|
||||
"results = graph_store.execute_query(\"MATCH (n) RETURN n.name, labels(n) LIMIT 10\")\n",
|
||||
"print(f\"\\nQuery results: {len(results.get('records', []))} nodes\")\n",
|
||||
"\n",
|
||||
"# Get statistics\n",
|
||||
"stats = graph_store.get_stats()\n",
|
||||
"print(f\"\\nGraph store statistics:\")\n",
|
||||
"print(f\" Node count: {stats.get('node_count', 'N/A')}\")\n",
|
||||
"print(f\" Relationship count: {stats.get('relationship_count', 'N/A')}\")\n",
|
||||
"print(f\" Label counts: {stats.get('label_counts', {})}\")\n",
|
||||
"\n",
|
||||
"graph_store.close()\n"
|
||||
"print(f\"Loaded {len(raw_entities)} raw entities and {len(raw_relationships)} raw relationships.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"## 2. Phase 1: Validation (The Gatekeeper)\n",
|
||||
"\n",
|
||||
"You've learned advanced graph analytics:\n",
|
||||
"Before we do anything, we must validate the graph. Bad data in = Bad insights out.\n",
|
||||
"We use `GraphValidator` to check for:\n",
|
||||
"- **Structural Integrity**: Are all relationship targets present?\n",
|
||||
"- **Schema Compliance**: Do entities have required fields?\n",
|
||||
"- **Consistency**: Are IDs unique?"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bd8fb13d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Initialize Validator\n",
|
||||
"validator = GraphValidator()\n",
|
||||
"\n",
|
||||
"- **GraphAnalyzer**: Comprehensive graph analysis and metrics\n",
|
||||
"- **CentralityCalculator**: Multiple centrality measures\n",
|
||||
"- **CommunityDetector**: Community detection\n",
|
||||
"- **ConnectivityAnalyzer**: Connectivity analysis\n",
|
||||
"- **GraphValidator**: Graph validation\n",
|
||||
"- **Deduplicator**: Graph deduplication\n",
|
||||
"- **GraphStore**: Persist graphs to Neo4j or FalkorDB\n",
|
||||
"# Create a temporary graph object for validation\n",
|
||||
"temp_graph = {\"entities\": raw_entities, \"relationships\": raw_relationships}\n",
|
||||
"\n",
|
||||
"# Run Validation\n",
|
||||
"print(\"Running Validation Check...\")\n",
|
||||
"validation_result = validator.validate(temp_graph)\n",
|
||||
"\n",
|
||||
"if not validation_result.is_valid:\n",
|
||||
" print(\"Validation Failed! Issues found:\")\n",
|
||||
" for issue in validation_result.issues:\n",
|
||||
" print(f\" - [{issue.severity.name}] {issue.message} (Code: {issue.code})\")\n",
|
||||
" \n",
|
||||
" # AUTOMATIC FIX: If it's a dangling edge, remove it\n",
|
||||
" if issue.code == \"DANGLING_EDGE\":\n",
|
||||
" print(\" Auto-Fixing: Removing invalid relationship...\")\n",
|
||||
" raw_relationships = [r for r in raw_relationships \n",
|
||||
" if r['target'] != issue.details.get('target_id')]\n",
|
||||
"else:\n",
|
||||
" print(\"Graph is valid!\")\n",
|
||||
"\n",
|
||||
"# Re-validate to confirm fix\n",
|
||||
"print(\"\\nRe-validating after fixes...\")\n",
|
||||
"temp_graph = {\"entities\": raw_entities, \"relationships\": raw_relationships}\n",
|
||||
"if validator.validate(temp_graph).is_valid:\n",
|
||||
" print(\"Graph is now clean and valid!\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Phase 2: Deduplication & Conflict Resolution\n",
|
||||
"\n",
|
||||
"We have \"TechFlow AI\" and \"TechFlow Inc.\". These are likely the same company.\n",
|
||||
"We also have conflicting revenue data."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 1. Detect Duplicates\n",
|
||||
"print(\"Scanning for duplicates...\")\n",
|
||||
"deduper = DuplicateDetector(similarity_threshold=0.7) # 70% similarity threshold\n",
|
||||
"duplicates = deduper.detect_duplicates(raw_entities)\n",
|
||||
"\n",
|
||||
"for candidate in duplicates:\n",
|
||||
" print(f\"Found potential duplicate pair (Score: {candidate.similarity_score:.2f}):\")\n",
|
||||
" print(f\" - {candidate.entity1['name']} (ID: {candidate.entity1['id']})\")\n",
|
||||
" print(f\" - {candidate.entity2['name']} (ID: {candidate.entity2['id']})\")\n",
|
||||
" \n",
|
||||
" # MERGE STRATEGY: Keep entity1, merge data from entity2\n",
|
||||
" print(\" Merging entities...\")\n",
|
||||
" # (In a real app, you'd use EntityMerger, but here's the logic:)\n",
|
||||
" # We keep startup_1 and discard startup_1_dup, but we note the conflict\n",
|
||||
" \n",
|
||||
"# 2. Detect Conflicts\n",
|
||||
"print(\"\\nChecking for data conflicts...\")\n",
|
||||
"conflict_detector = ConflictDetector()\n",
|
||||
"\n",
|
||||
"# Simulating a conflict check between the two versions of TechFlow\n",
|
||||
"# To check conflicts, we treat them as the same entity (same ID)\n",
|
||||
"entity_a = raw_entities[0].copy()\n",
|
||||
"entity_b = raw_entities[2].copy()\n",
|
||||
"entity_b['id'] = entity_a['id'] # Force same ID for conflict detection\n",
|
||||
"\n",
|
||||
"conflicts = conflict_detector.detect_conflicts([entity_a, entity_b])\n",
|
||||
"\n",
|
||||
"for conflict in conflicts:\n",
|
||||
" print(f\" Conflict detected in field '{conflict.property_name}':\")\n",
|
||||
" print(f\" Values: {conflict.conflicting_values}\")\n",
|
||||
" \n",
|
||||
" # RESOLUTION: Trust the higher number (optimistic!)\n",
|
||||
" if conflict.property_name == \"revenue\":\n",
|
||||
" # values are strings or ints, need to handle types\n",
|
||||
" vals = [float(v) for v in conflict.conflicting_values if v is not None]\n",
|
||||
" resolved_val = max(vals)\n",
|
||||
" print(f\" Resolved to: {resolved_val}\")\n",
|
||||
" raw_entities[0]['revenue'] = resolved_val\n",
|
||||
"\n",
|
||||
"# Final Cleanup: Remove the duplicate entity from our list\n",
|
||||
"clean_entities = [e for e in raw_entities if e['id'] != 'startup_1_dup']\n",
|
||||
"clean_relationships = raw_relationships # (We'd normally re-link relationships too)\n",
|
||||
"\n",
|
||||
"print(f\"\\nCleaned Data: {len(clean_entities)} entities remaining.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Phase 3: Building the Knowledge Graph\n",
|
||||
"\n",
|
||||
"Now that our data is clean, we build the official graph object."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Manual Graph Construction (since we already cleaned it)\n",
|
||||
"kg = {\n",
|
||||
" \"entities\": clean_entities,\n",
|
||||
" \"relationships\": clean_relationships,\n",
|
||||
" \"metadata\": {\n",
|
||||
" \"created_at\": datetime.now().isoformat(),\n",
|
||||
" \"source\": \"Manual Advanced Pipeline\"\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"print(\"Knowledge Graph Assembled Successfully!\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Phase 4: Advanced Analytics\n",
|
||||
"\n",
|
||||
"This is where the magic happens. We'll use multiple analyzers to extract insights."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Initialize the Master Analyzer\n",
|
||||
"analyzer = GraphAnalyzer(enable_temporal=True)\n",
|
||||
"\n",
|
||||
"# 1. Structural Analysis (Connectivity)\n",
|
||||
"print(\"\\n--- Connectivity Analysis ---\")\n",
|
||||
"connectivity = analyzer.analyze_connectivity(kg)\n",
|
||||
"print(f\" • Graph Connected? {'Yes' if connectivity['is_connected'] else 'No'}\")\n",
|
||||
"print(f\" • Connected Components: {connectivity['num_components']}\")\n",
|
||||
"\n",
|
||||
"# 2. Centrality (Who is important?)\n",
|
||||
"print(\"\\n--- Centrality Analysis ---\")\n",
|
||||
"centrality_result = analyzer.calculate_centrality(kg, centrality_type=\"degree\")\n",
|
||||
"degree_data = centrality_result[\"centrality_measures\"][\"degree\"]\n",
|
||||
"\n",
|
||||
"# Get pre-calculated rankings\n",
|
||||
"top_nodes = degree_data[\"rankings\"][:3]\n",
|
||||
"\n",
|
||||
"print(\" • Top Influencers (Degree Centrality):\")\n",
|
||||
"for item in top_nodes:\n",
|
||||
" print(f\" - {item['node']}: {item['score']:.2f}\")\n",
|
||||
"\n",
|
||||
"# 3. Community Detection (Clustering)\n",
|
||||
"print(\"\\n--- Community Detection ---\")\n",
|
||||
"community_result = analyzer.detect_communities(kg, algorithm=\"louvain\")\n",
|
||||
"communities = community_result[\"communities\"]\n",
|
||||
"\n",
|
||||
"print(f\" • Detected {len(communities)} communities.\")\n",
|
||||
"for i, comm in enumerate(communities):\n",
|
||||
" # comm is a set of node IDs\n",
|
||||
" members = list(comm)\n",
|
||||
" print(f\" Community {i+1}: {', '.join(members)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 6. Phase 5: Temporal Analytics (Time Travel)\n",
|
||||
"\n",
|
||||
"Static graphs are boring. Real worlds change. Let's analyze the **evolution** of our ecosystem."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"temporal_engine = TemporalGraphQuery(temporal_granularity=\"year\")\n",
|
||||
"\n",
|
||||
"# 1. Time Travel Query: What did the world look like in 2020?\n",
|
||||
"print(\"\\n--- Time Travel: 2020 ---\")\n",
|
||||
"snapshot_2020 = temporal_engine.query_at_time(kg, query=\"*\", at_time=\"2020-06-01\")\n",
|
||||
"print(f\" Active Relationships in 2020: {len(snapshot_2020['relationships'])}\")\n",
|
||||
"for rel in snapshot_2020['relationships']:\n",
|
||||
" print(f\" - {rel['source']} --[{rel['type']}]--> {rel['target']}\")\n",
|
||||
"\n",
|
||||
"# 2. Time Travel Query: What about 2023?\n",
|
||||
"print(\"\\n--- Time Travel: 2023 ---\")\n",
|
||||
"snapshot_2023 = temporal_engine.query_at_time(kg, query=\"*\", at_time=\"2023-07-01\")\n",
|
||||
"print(f\" Active Relationships in 2023: {len(snapshot_2023['relationships'])}\")\n",
|
||||
"for rel in snapshot_2023['relationships']:\n",
|
||||
" print(f\" - {rel['source']} --[{rel['type']}]--> {rel['target']}\")\n",
|
||||
" \n",
|
||||
"# Notice how 'ADVISED' might disappear if it ended, and 'INVESTED_IN' appears!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 7. Phase 6: Provenance (Data Lineage)\n",
|
||||
"\n",
|
||||
"Finally, in a production system, you need to know **where** a fact came from. This is crucial for trust."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"tracker = ProvenanceTracker()\n",
|
||||
"\n",
|
||||
"# Let's pretend we're tracking the source of our data\n",
|
||||
"tracker.track_entity(\"startup_1\", source=\"Crunchbase_API_v2\", metadata={\"confidence\": 0.95})\n",
|
||||
"tracker.track_entity(\"startup_1\", source=\"Manual_Entry_User_Bob\", metadata={\"confidence\": 1.0})\n",
|
||||
"\n",
|
||||
"print(\"\\n--- Provenance Report: TechFlow AI ---\")\n",
|
||||
"lineage = tracker.get_lineage(\"startup_1\")\n",
|
||||
"print(f\" Entity: startup_1\")\n",
|
||||
"print(f\" First Seen: {lineage['first_seen']}\")\n",
|
||||
"print(f\" Sources:\")\n",
|
||||
"for src in lineage['sources']:\n",
|
||||
" print(f\" - {src['source']} (at {src['timestamp']})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Conclusion\n",
|
||||
"\n",
|
||||
"You have just walked through a complete, advanced Knowledge Graph pipeline:\n",
|
||||
"\n",
|
||||
"1. **Validated** messy input data.\n",
|
||||
"2. **Cleaned** duplicates and conflicts.\n",
|
||||
"3. **Analyzed** structure and community dynamics.\n",
|
||||
"4. **Queried** across time dimensions.\n",
|
||||
"5. **Tracked** data lineage.\n",
|
||||
"\n",
|
||||
"This represents the state-of-the-art in modern KG Engineering using Semantica."
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Notice**: The `semantica.kg_qa` module is temporarily unavailable and will be reintroduced in a future release. Any quality assessment examples in this notebook are disabled."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -17,7 +10,7 @@
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"Comprehensive visualization capabilities: visualize knowledge graphs, embeddings, quality metrics, analytics, and temporal data.\n",
|
||||
"Comprehensive visualization capabilities: visualize knowledge graphs, embeddings, analytics, and temporal data.\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/visualization/)\n",
|
||||
"\n",
|
||||
@@ -32,6 +25,15 @@
|
||||
"```\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -qU semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -40,14 +42,10 @@
|
||||
"source": [
|
||||
"from semantica.visualization import (\n",
|
||||
" KGVisualizer,\n",
|
||||
" EmbeddingVisualizer,\n",
|
||||
" QualityVisualizer,\n",
|
||||
" AnalyticsVisualizer,\n",
|
||||
" TemporalVisualizer\n",
|
||||
")\n",
|
||||
"from semantica.kg import GraphBuilder, GraphAnalyzer\n",
|
||||
"from semantica.embeddings import EmbeddingGenerator\n",
|
||||
|
||||
"import numpy as np\n"
|
||||
]
|
||||
},
|
||||
@@ -96,59 +94,14 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kg_visualizer = KGVisualizer(layout=\"force\", color_scheme=\"vibrant\")\n",
|
||||
"kg_visualizer.visualize_network(knowledge_graph, output=\"interactive\")\n"
|
||||
"kg_visualizer.visualize_network(knowledge_graph, output=\"interactive\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Generate Embeddings and Visualize\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"embedding_generator = EmbeddingGenerator()\n",
|
||||
"texts = [entity.get(\"name\", \"\") for entity in entities]\n",
|
||||
"embeddings = embedding_generator.generate_embeddings(texts, data_type=\"text\")\n",
|
||||
"\n",
|
||||
"labels = [entity.get(\"type\", \"Unknown\") for entity in entities]\n",
|
||||
"\n",
|
||||
"embedding_visualizer = EmbeddingVisualizer()\n",
|
||||
"embedding_visualizer.visualize_2d_projection(embeddings, labels, method=\"tsne\", output=\"interactive\", file_path=None)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Quality Metrics Visualization\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"quality_visualizer = QualityVisualizer()\n",
|
||||
"quality_report = {\n",
|
||||
" \"overall_score\": 0.85,\n",
|
||||
" \"consistency_score\": 0.90,\n",
|
||||
" \"completeness_score\": 0.80\n",
|
||||
"}\n",
|
||||
"quality_visualizer.visualize_dashboard(quality_report, output=\"interactive\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Graph Analytics Visualization\n"
|
||||
"## Step 3: Graph Analytics Visualization\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -206,7 +159,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 6: Temporal Data Visualization\n"
|
||||
"## Step 5: Temporal Data Visualization\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -215,50 +168,103 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import datetime\n",
|
||||
"from semantica.visualization import TemporalVisualizer\n",
|
||||
"import pandas as pd\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# 1. Setup Data: AI Research Lab Evolution (2020-2024)\n",
|
||||
"# This dataset simulates a growing network of researchers, papers, and grants\n",
|
||||
"\n",
|
||||
"start_date = datetime.date(2020, 1, 1)\n",
|
||||
"\n",
|
||||
"# Entities with lifespans\n",
|
||||
"entities = [\n",
|
||||
" {\"id\": \"Lab_Alpha\", \"type\": \"Organization\", \"start\": \"2020-01-01\", \"end\": \"2024-12-31\", \"properties\": {\"budget\": \"High\"}},\n",
|
||||
" {\"id\": \"Dr_Smith\", \"type\": \"Researcher\", \"start\": \"2020-01-15\", \"end\": \"2024-12-31\", \"properties\": {\"h_index\": 15}},\n",
|
||||
" {\"id\": \"Dr_Jones\", \"type\": \"Researcher\", \"start\": \"2020-03-01\", \"end\": \"2024-12-31\", \"properties\": {\"h_index\": 12}},\n",
|
||||
" {\"id\": \"Paper_X\", \"type\": \"Publication\", \"start\": \"2020-11-20\", \"end\": \"2024-12-31\", \"properties\": {\"citations\": 50}},\n",
|
||||
" {\"id\": \"Grant_A\", \"type\": \"Funding\", \"start\": \"2021-01-01\", \"end\": \"2022-12-31\", \"properties\": {\"amount\": 1000000}},\n",
|
||||
" {\"id\": \"Dr_Chen\", \"type\": \"Researcher\", \"start\": \"2021-06-01\", \"end\": \"2024-12-31\", \"properties\": {\"h_index\": 8}},\n",
|
||||
" {\"id\": \"Paper_Y\", \"type\": \"Publication\", \"start\": \"2022-03-15\", \"end\": \"2024-12-31\", \"properties\": {\"citations\": 25}},\n",
|
||||
" {\"id\": \"Startup_Beta\", \"type\": \"SpinOff\", \"start\": \"2023-01-01\", \"end\": \"2024-12-31\", \"properties\": {\"valuation\": \"5M\"}},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Relationships with timestamps\n",
|
||||
"relationships = [\n",
|
||||
" {\"source\": \"Dr_Smith\", \"target\": \"Lab_Alpha\", \"type\": \"WORKS_AT\", \"timestamp\": \"2020-01-15\"},\n",
|
||||
" {\"source\": \"Dr_Jones\", \"target\": \"Lab_Alpha\", \"type\": \"WORKS_AT\", \"timestamp\": \"2020-03-01\"},\n",
|
||||
" {\"source\": \"Dr_Smith\", \"target\": \"Paper_X\", \"type\": \"AUTHORED\", \"timestamp\": \"2020-11-20\"},\n",
|
||||
" {\"source\": \"Dr_Jones\", \"target\": \"Paper_X\", \"type\": \"AUTHORED\", \"timestamp\": \"2020-11-20\"},\n",
|
||||
" {\"source\": \"Lab_Alpha\", \"target\": \"Grant_A\", \"type\": \"RECEIVED\", \"timestamp\": \"2021-01-01\"},\n",
|
||||
" {\"source\": \"Dr_Chen\", \"target\": \"Lab_Alpha\", \"type\": \"WORKS_AT\", \"timestamp\": \"2021-06-01\"},\n",
|
||||
" {\"source\": \"Dr_Chen\", \"target\": \"Paper_Y\", \"type\": \"AUTHORED\", \"timestamp\": \"2022-03-15\"},\n",
|
||||
" {\"source\": \"Dr_Smith\", \"target\": \"Paper_Y\", \"type\": \"AUTHORED\", \"timestamp\": \"2022-03-15\"},\n",
|
||||
" {\"source\": \"Lab_Alpha\", \"target\": \"Startup_Beta\", \"type\": \"SPUN_OFF\", \"timestamp\": \"2023-01-01\"},\n",
|
||||
" {\"source\": \"Dr_Jones\", \"target\": \"Startup_Beta\", \"type\": \"CTO\", \"timestamp\": \"2023-02-01\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Metrics over time\n",
|
||||
"dates = pd.date_range(start=\"2020-01-01\", end=\"2024-01-01\", freq=\"M\")\n",
|
||||
"metrics = {\n",
|
||||
" \"dates\": [d.strftime(\"%Y-%m-%d\") for d in dates],\n",
|
||||
" \"funding_usd\": [100000 + (i * 50000) + (np.random.randint(-10000, 10000)) for i in range(len(dates))],\n",
|
||||
" \"team_size\": [2 + int(i/5) for i in range(len(dates))],\n",
|
||||
" \"publications\": [int(i/4) for i in range(len(dates))]\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# 4. Generate Timestamps Map (Required for TemporalVisualizer)\n",
|
||||
"# This maps each entity to the specific time points where it is \"active\" or relevant\n",
|
||||
"timestamps = {}\n",
|
||||
"\n",
|
||||
"# Collect all relevant dates (monthly granularity)\n",
|
||||
"all_dates = [d.strftime(\"%Y-%m-%d\") for d in dates]\n",
|
||||
"\n",
|
||||
"for entity in entities:\n",
|
||||
" eid = entity[\"id\"]\n",
|
||||
" start = entity.get(\"start\")\n",
|
||||
" end = entity.get(\"end\")\n",
|
||||
" \n",
|
||||
" # In a real app, you'd calculate overlap. Here we'll just assign all dates \n",
|
||||
" # that fall within the entity's lifespan\n",
|
||||
" entity_times = [d for d in all_dates if start <= d <= end]\n",
|
||||
" timestamps[eid] = entity_times\n",
|
||||
" \n",
|
||||
"temporal_kg = {\n",
|
||||
" \"entities\": entities,\n",
|
||||
" \"relationships\": relationships,\n",
|
||||
" \"timestamps\": {\n",
|
||||
" \"e1\": [2020, 2021, 2022],\n",
|
||||
" \"e2\": [2020, 2021],\n",
|
||||
" \"e3\": [2010, 2015, 2020, 2022],\n",
|
||||
" }\n",
|
||||
" \"metrics\": metrics,\n",
|
||||
" \"timestamps\": timestamps\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"entity_history = {\n",
|
||||
" \"e1\": [\n",
|
||||
" {\"timestamp\": 2020, \"properties\": {\"age\": 28}},\n",
|
||||
" {\"timestamp\": 2021, \"properties\": {\"age\": 29}},\n",
|
||||
" {\"timestamp\": 2022, \"properties\": {\"age\": 30}},\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"# 2. Initialize Visualizer\n",
|
||||
"viz = TemporalVisualizer()\n",
|
||||
"\n",
|
||||
"from semantica.kg import TemporalVersionManager\n",
|
||||
"temporal_visualizer = TemporalVisualizer()\n",
|
||||
"temporal_visualizer.visualize_timeline(temporal_kg, output=\"interactive\")\n",
|
||||
"# Convert entity history to metrics for visualization\n",
|
||||
"timestamps = [str(item[\"timestamp\"]) for item in entity_history[\"e1\"]]\n",
|
||||
"age_values = [item[\"properties\"][\"age\"] for item in entity_history[\"e1\"]]\n",
|
||||
"metrics_history = {\"age\": age_values}\n",
|
||||
"temporal_visualizer.visualize_metrics_evolution(metrics_history, timestamps, output=\"interactive\")\n",
|
||||
"print(\"1. Generating Temporal Dashboard...\")\n",
|
||||
"# This creates a combined view of lifecycles, activity, and metrics\n",
|
||||
"dashboard = viz.visualize_temporal_dashboard(\n",
|
||||
" temporal_kg,\n",
|
||||
" title=\"AI Research Lab Evolution (2020-2024)\",\n",
|
||||
" output=\"interactive\"\n",
|
||||
")\n",
|
||||
"dashboard.show()\n",
|
||||
"\n",
|
||||
"# Create versions for snapshot comparison\n",
|
||||
"version_manager = TemporalVersionManager()\n",
|
||||
"v1 = version_manager.create_version(temporal_kg, timestamp=\"2020-01-01\", version_label=\"v2020\")\n",
|
||||
"temporal_kg_v2 = {\n",
|
||||
" \"entities\": temporal_kg.get(\"entities\", []),\n",
|
||||
" \"relationships\": temporal_kg.get(\"relationships\", []) + [\n",
|
||||
" {\"source\": \"e1\", \"target\": \"e2\", \"type\": \"collaborated_with\", \"valid_from\": \"2023-01-01\"}\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"v2 = version_manager.create_version(temporal_kg_v2, timestamp=\"2023-01-01\", version_label=\"v2023\")\n",
|
||||
"snapshots = {v1[\"timestamp\"]: v1, v2[\"timestamp\"]: v2}\n",
|
||||
"temporal_visualizer.visualize_snapshot_comparison(snapshots, output=\"interactive\")\n",
|
||||
"version_history = [\n",
|
||||
" {\"version\": v1.get(\"label\"), \"timestamp\": v1.get(\"timestamp\")},\n",
|
||||
" {\"version\": v2.get(\"label\"), \"timestamp\": v2.get(\"timestamp\")}\n",
|
||||
"]\n",
|
||||
"temporal_visualizer.visualize_version_history(version_history, output=\"interactive\")\n"
|
||||
"print(\"2. Generating Network Evolution Animation...\")\n",
|
||||
"# This creates a playable animation of the network graph\n",
|
||||
"animation = viz.visualize_network_evolution(\n",
|
||||
" temporal_kg,\n",
|
||||
" title=\"Network Growth Over Time\",\n",
|
||||
" output=\"interactive\"\n",
|
||||
")\n",
|
||||
"animation.show()\n",
|
||||
"\n",
|
||||
"print(\"3. Generating Timeline View...\")\n",
|
||||
"timeline = viz.visualize_timeline(\n",
|
||||
" temporal_kg,\n",
|
||||
" title=\"Entity Lifecycles\",\n",
|
||||
" output=\"interactive\"\n",
|
||||
")\n",
|
||||
"timeline.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -270,15 +276,28 @@
|
||||
"All visualization types demonstrated:\n",
|
||||
"- Knowledge Graph Visualization\n",
|
||||
"- Embedding Visualization (t-SNE)\n",
|
||||
"- Quality Metrics Visualization\n",
|
||||
"- Graph Analytics Visualization (Centrality & Communities)\n",
|
||||
"- Temporal Data Visualization (Timeline & Evolution)\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.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -1,254 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Notice**: The `semantica.kg_qa` module is temporarily unavailable and will be reintroduced in a future release. Any quality assessment examples in this notebook are disabled."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/04_Conflict_Resolution_Strategies.ipynb)\n",
|
||||
"\n",
|
||||
"# Conflict Resolution Strategies\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"Detect conflicts in knowledge graphs, apply multiple resolution strategies, track sources, and maintain audit trails.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/conflicts/)\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",
|
||||
"## Workflow: Detect Conflicts → Multiple Resolution Strategies → Track Sources → Audit\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from datetime import datetime\n",
|
||||
"import json\n",
|
||||
"from semantica.conflicts import ConflictDetector, ConflictResolver, SourceTracker\n",
|
||||
"from semantica.conflicts.conflict_resolver import ResolutionStrategy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 1: Define Entities with Conflicting Data\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"entities = [\n",
|
||||
" {\n",
|
||||
" \"id\": \"e1\",\n",
|
||||
" \"type\": \"Person\",\n",
|
||||
" \"name\": \"John Doe\",\n",
|
||||
" \"age\": 30,\n",
|
||||
" \"location\": \"New York\",\n",
|
||||
" \"source\": \"source1\",\n",
|
||||
" \"confidence\": 0.8,\n",
|
||||
" \"metadata\": {\"timestamp\": datetime(2023, 1, 1)}\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"e1\",\n",
|
||||
" \"type\": \"Person\",\n",
|
||||
" \"name\": \"John Doe\",\n",
|
||||
" \"age\": 32,\n",
|
||||
" \"location\": \"Boston\",\n",
|
||||
" \"source\": \"source2\",\n",
|
||||
" \"confidence\": 0.9,\n",
|
||||
" \"metadata\": {\"timestamp\": datetime(2023, 6, 1)}\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"e2\",\n",
|
||||
" \"type\": \"Organization\",\n",
|
||||
" \"name\": \"Tech Corp\",\n",
|
||||
" \"founded\": 2010,\n",
|
||||
" \"employees\": 100,\n",
|
||||
" \"source\": \"source1\",\n",
|
||||
" \"confidence\": 0.9,\n",
|
||||
" \"metadata\": {\"timestamp\": datetime(2023, 1, 1)}\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"e2\",\n",
|
||||
" \"type\": \"Organization\",\n",
|
||||
" \"name\": \"Tech Corp\",\n",
|
||||
" \"founded\": 2012,\n",
|
||||
" \"employees\": 150,\n",
|
||||
" \"source\": \"source2\",\n",
|
||||
" \"confidence\": 0.7,\n",
|
||||
" \"metadata\": {\"timestamp\": datetime(2023, 3, 1)}\n",
|
||||
" }\n",
|
||||
"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Detect Conflicts\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Initialize detector\n",
|
||||
"detector = ConflictDetector(track_provenance=True)\n",
|
||||
"\n",
|
||||
"# Detect conflicts across all properties\n",
|
||||
"conflicts = detector.detect_entity_conflicts(entities)\n",
|
||||
"\n",
|
||||
"print(f\"Detected {len(conflicts)} conflicts:\")\n",
|
||||
"for i, conflict in enumerate(conflicts, 1):\n",
|
||||
" print(f\"\\nConflict {i}:\")\n",
|
||||
" print(f\" ID: {conflict.conflict_id}\")\n",
|
||||
" print(f\" Type: {conflict.conflict_type.value}\")\n",
|
||||
" print(f\" Entity: {conflict.entity_id}\")\n",
|
||||
" print(f\" Property: {conflict.property_name}\")\n",
|
||||
" print(f\" Values: {conflict.conflicting_values}\")\n",
|
||||
" print(f\" Severity: {conflict.severity}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Resolve Conflicts\n",
|
||||
"\n",
|
||||
"We can apply different strategies to resolve the conflicts:\n",
|
||||
"- **Voting**: Selects the most frequent value\n",
|
||||
"- **Most Recent**: Selects the value with the latest timestamp\n",
|
||||
"- **Highest Confidence**: Selects the value from the source with highest confidence\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Initialize resolver\n",
|
||||
"resolver = ConflictResolver()\n",
|
||||
"\n",
|
||||
"# Strategy 1: Voting\n",
|
||||
"print(\"--- Strategy: Voting ---\")\n",
|
||||
"results_voting = resolver.resolve_conflicts(conflicts, strategy=\"voting\")\n",
|
||||
"for r in results_voting:\n",
|
||||
" if r.resolved:\n",
|
||||
" print(f\"Resolved {r.conflict_id}: {r.resolved_value} (Confidence: {r.confidence:.2f})\")\n",
|
||||
"\n",
|
||||
"# Strategy 2: Most Recent\n",
|
||||
"print(\"\\n--- Strategy: Most Recent ---\")\n",
|
||||
"results_recent = resolver.resolve_conflicts(conflicts, strategy=\"most_recent\")\n",
|
||||
"for r in results_recent:\n",
|
||||
" if r.resolved:\n",
|
||||
" print(f\"Resolved {r.conflict_id}: {r.resolved_value}\")\n",
|
||||
"\n",
|
||||
"# Strategy 3: Highest Confidence\n",
|
||||
"print(\"\\n--- Strategy: Highest Confidence ---\")\n",
|
||||
"results_confidence = resolver.resolve_conflicts(conflicts, strategy=\"highest_confidence\")\n",
|
||||
"for r in results_confidence:\n",
|
||||
" if r.resolved:\n",
|
||||
" print(f\"Resolved {r.conflict_id}: {r.resolved_value} (Confidence: {r.confidence:.2f})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Track Sources\n",
|
||||
"\n",
|
||||
"The `ConflictDetector` tracks source provenance when `track_provenance=True`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"tracker = detector.source_tracker\n",
|
||||
"\n",
|
||||
"for conflict in conflicts:\n",
|
||||
" print(f\"\\nConflict: {conflict.conflict_id}\")\n",
|
||||
" # Get detailed source info for the property\n",
|
||||
" sources = tracker.get_property_sources(conflict.entity_id, conflict.property_name)\n",
|
||||
" if sources:\n",
|
||||
" print(f\" Entity: {conflict.entity_id}, Property: {conflict.property_name}\")\n",
|
||||
" print(f\" Sources found: {len(sources.sources)}\")\n",
|
||||
" for src in sources.sources:\n",
|
||||
" print(f\" - {src.document} (Confidence: {src.confidence})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Audit Trail\n",
|
||||
"\n",
|
||||
"The `ConflictResolver` maintains a history of all resolutions."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"history = resolver.get_resolution_history()\n",
|
||||
"\n",
|
||||
"print(f\"Resolution History ({len(history)} entries):\")\n",
|
||||
"for entry in history:\n",
|
||||
" print(f\"\\nConflict: {entry.conflict_id}\")\n",
|
||||
" print(f\" Strategy: {entry.resolution_strategy}\")\n",
|
||||
" print(f\" Resolved Value: {entry.resolved_value}\")\n",
|
||||
" print(f\" Notes: {entry.resolution_notes}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"Conflict resolution workflow:\n",
|
||||
"- Conflict Detection using `ConflictDetector`\n",
|
||||
"- Multiple Resolution Strategies (Voting, Most Recent, Highest Confidence)\n",
|
||||
"- Source Tracking with `SourceTracker`\n",
|
||||
"- Complete Audit Trail via `ConflictResolver`"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -48,6 +48,15 @@
|
||||
"```\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -312,7 +321,7 @@
|
||||
"- NumPy format\n",
|
||||
"- Binary format\n",
|
||||
"- FAISS format\n",
|
||||
"- Vector store integration (Pinecone, Weaviate, Qdrant)\n"
|
||||
"- Vector store integration (Weaviate, Qdrant)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -614,6 +623,11 @@
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,233 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/07_Pipeline_Orchestration.ipynb)\n",
|
||||
"\n",
|
||||
"# Pipeline Orchestration\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"Build complex pipelines, execute them, handle failures, enable parallel processing, and monitor execution.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/pipeline/)\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",
|
||||
"## Workflow: Build Pipelines → Execute → Handle Failures → Parallel Processing → Monitor\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.pipeline import (\n",
|
||||
" PipelineBuilder,\n",
|
||||
" ExecutionEngine,\n",
|
||||
" FailureHandler,\n",
|
||||
" ParallelismManager,\n",
|
||||
" RetryPolicy,\n",
|
||||
" RetryStrategy\n",
|
||||
")\n",
|
||||
"from semantica.ingest import FileIngestor\n",
|
||||
"from semantica.parse import DocumentParser\n",
|
||||
"from semantica.semantic_extract import NERExtractor\n",
|
||||
"from semantica.kg import GraphBuilder\n",
|
||||
"import time\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 1: Build Complex Pipelines\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"builder = PipelineBuilder()\n",
|
||||
"\n",
|
||||
"file_ingestor = FileIngestor()\n",
|
||||
"document_parser = DocumentParser()\n",
|
||||
"ner_extractor = NERExtractor()\n",
|
||||
"graph_builder = GraphBuilder()\n",
|
||||
"\n",
|
||||
"# Define handlers for each pipeline step\n",
|
||||
"def ingest_handler(data, **config):\n",
|
||||
" files = data.get(\"files\", [])\n",
|
||||
" if files:\n",
|
||||
" # Ingest first file as example\n",
|
||||
" file_obj = file_ingestor.ingest_file(files[0], read_content=True)\n",
|
||||
" return {**data, \"file\": file_obj}\n",
|
||||
" return data\n",
|
||||
"\n",
|
||||
"def parse_handler(data, **config):\n",
|
||||
" # If a file was ingested, try parsing; otherwise pass text through\n",
|
||||
" file_obj = data.get(\"file\")\n",
|
||||
" if file_obj and getattr(file_obj, \"path\", None):\n",
|
||||
" parsed = document_parser.parse_document(file_obj.path)\n",
|
||||
" text = parsed.get(\"text\") if isinstance(parsed, dict) else None\n",
|
||||
" return {**data, \"text\": text or data.get(\"text\")}\n",
|
||||
" return data\n",
|
||||
"\n",
|
||||
"def extract_handler(data, **config):\n",
|
||||
" text = data.get(\"text\", \"\")\n",
|
||||
" entities = ner_extractor.extract_entities(text)\n",
|
||||
" # Normalize to dict list for graph builder\n",
|
||||
" entity_dicts = [\n",
|
||||
" {\"id\": f\"e{i}\", \"name\": e.text, \"type\": e.label} for i, e in enumerate(entities)\n",
|
||||
" ]\n",
|
||||
" return {**data, \"entities\": entity_dicts}\n",
|
||||
"\n",
|
||||
"def build_graph_handler(data, **config):\n",
|
||||
" entities = data.get(\"entities\", [])\n",
|
||||
" graph = graph_builder.build({\"entities\": entities})\n",
|
||||
" return {**data, \"graph\": graph}\n",
|
||||
"\n",
|
||||
"# Build pipeline with proper handlers and dependencies\n",
|
||||
"pipeline = (\n",
|
||||
" builder\n",
|
||||
" .add_step(\"ingest\", \"ingest\", handler=ingest_handler)\n",
|
||||
" .add_step(\"parse\", \"parse\", dependencies=[\"ingest\"], handler=parse_handler)\n",
|
||||
" .add_step(\"extract\", \"extract\", dependencies=[\"parse\"], handler=extract_handler)\n",
|
||||
" .add_step(\"build_graph\", \"build_graph\", dependencies=[\"extract\"], handler=build_graph_handler)\n",
|
||||
").build()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Execute Pipeline\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"engine = ExecutionEngine()\n",
|
||||
"\n",
|
||||
"input_data = {\n",
|
||||
" \"text\": \"Alice works at Tech Corp. Bob is a friend of Alice.\",\n",
|
||||
" \"files\": []\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"start_time = time.time()\n",
|
||||
"result = engine.execute_pipeline(pipeline, input_data)\n",
|
||||
"execution_time = result.metrics.get(\"execution_time\", time.time() - start_time)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Handle Failures\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Configure retry policy for the 'extract' step type\n",
|
||||
"engine.failure_handler.set_retry_policy(\n",
|
||||
" \"extract\",\n",
|
||||
" RetryPolicy(max_retries=3, backoff_factor=2.0, strategy=RetryStrategy.EXPONENTIAL)\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"result = engine.execute_pipeline(pipeline, input_data)\n",
|
||||
"print(\"Pipeline executed with retry policy configured\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Parallel Processing\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"parallelism = ParallelismManager(max_workers=4)\n",
|
||||
"\n",
|
||||
"# Identify groups of steps that can run in parallel\n",
|
||||
"groups = parallelism.identify_parallelizable_steps(pipeline)\n",
|
||||
"\n",
|
||||
"# Execute first parallelizable group as a demonstration\n",
|
||||
"start_time = time.time()\n",
|
||||
"parallel_results = []\n",
|
||||
"for group in groups:\n",
|
||||
" parallel_results.extend(parallelism.execute_pipeline_steps_parallel(group, input_data, max_workers=4))\n",
|
||||
"parallel_time = time.time() - start_time\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Monitor Pipeline Execution\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Metrics from execution engine\n",
|
||||
"metrics = result.metrics\n",
|
||||
"progress = engine.get_progress(pipeline.name)\n",
|
||||
"\n",
|
||||
"print(f\"Duration: {metrics.get('execution_time', 0):.2f} seconds\")\n",
|
||||
"print(f\"Steps Executed: {metrics.get('steps_executed', 0)}\")\n",
|
||||
"print(f\"Steps Failed: {metrics.get('steps_failed', 0)}\")\n",
|
||||
"print(f\"Progress: {progress.get('progress_percentage', 0):.1f}% (status: {progress.get('status')})\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"Pipeline orchestration workflow:\n",
|
||||
"- Complex Pipeline Built\n",
|
||||
"- Pipeline Executed\n",
|
||||
"- Failure Handling Configured\n",
|
||||
"- Parallel Processing Enabled\n",
|
||||
"- Full Monitoring and Observability\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -1,336 +1,348 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/08_Reasoning_and_Inference.ipynb)\n",
|
||||
"\n",
|
||||
"# Reasoning and Inference\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"Build knowledge graphs, define rules, perform forward/backward chaining, and generate explanations for AI reasoning using the **Semantica Reasoning Module**.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/reasoning/)\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",
|
||||
"## Workflow: Build KG → Define Rules → Forward/Backward Chaining → Generate Explanations\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.kg import GraphBuilder\n",
|
||||
"from semantica.reasoning import InferenceEngine, RuleManager, ExplanationGenerator\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 1: Build Knowledge Graph\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"builder = GraphBuilder()\n",
|
||||
"\n",
|
||||
"entities = [\n",
|
||||
" {\"id\": \"alice\", \"type\": \"Person\", \"name\": \"Alice\"},\n",
|
||||
" {\"id\": \"bob\", \"type\": \"Person\", \"name\": \"Bob\"},\n",
|
||||
" {\"id\": \"charlie\", \"type\": \"Person\", \"name\": \"Charlie\"},\n",
|
||||
" {\"id\": \"sf\", \"type\": \"Location\", \"name\": \"San Francisco\"},\n",
|
||||
" {\"id\": \"california\", \"type\": \"Location\", \"name\": \"California\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"relationships = [\n",
|
||||
" {\"source\": \"alice\", \"target\": \"bob\", \"type\": \"parent_of\"},\n",
|
||||
" {\"source\": \"bob\", \"target\": \"charlie\", \"type\": \"parent_of\"},\n",
|
||||
" {\"source\": \"sf\", \"target\": \"california\", \"type\": \"located_in\"},\n",
|
||||
" {\"source\": \"alice\", \"target\": \"sf\", \"type\": \"lives_in\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"knowledge_graph = builder.build([{\"entities\": entities, \"relationships\": relationships}])\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Define Rules\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Initialize Inference Engine\n",
|
||||
"engine = InferenceEngine()\n",
|
||||
"\n",
|
||||
"# Define rules using logic syntax\n",
|
||||
"rules = [\n",
|
||||
" \"IF parent_of(?a, ?b) AND parent_of(?b, ?c) THEN grandparent_of(?a, ?c)\",\n",
|
||||
" \"IF lives_in(?x, ?y) AND located_in(?y, ?z) THEN lives_in(?x, ?z)\"\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"for rule in rules:\n",
|
||||
" engine.add_rule(rule)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Forward Chaining\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Load facts from relationships into the engine\n",
|
||||
"for rel in relationships:\n",
|
||||
" # Format: predicate(subject, object)\n",
|
||||
" fact_str = f\"{rel['type']}({rel['source']}, {rel['target']})\"\n",
|
||||
" engine.add_fact(fact_str)\n",
|
||||
"\n",
|
||||
"# Perform forward chaining to derive new facts\n",
|
||||
"results = engine.forward_chain()\n",
|
||||
"\n",
|
||||
"print(f\"Inferred {len(results)} new facts:\")\n",
|
||||
"for result in results:\n",
|
||||
" print(f\" - {result.conclusion} (Rule: {result.rule_used.name})\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Backward Chaining\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Define a goal to prove\n",
|
||||
"goal = \"grandparent_of(alice, charlie)\"\n",
|
||||
"\n",
|
||||
"# Perform backward chaining\n",
|
||||
"proof = engine.backward_chain(goal)\n",
|
||||
"\n",
|
||||
"if proof:\n",
|
||||
" print(f\"Goal '{goal}' proven successfully!\")\n",
|
||||
"else:\n",
|
||||
" print(f\"Could not prove goal '{goal}'.\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Generate Explanations\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"generator = ExplanationGenerator()\n",
|
||||
"\n",
|
||||
"# Explain the last forward chaining inference\n",
|
||||
"if results:\n",
|
||||
" explanation = generator.generate_explanation(results[0])\n",
|
||||
" print(\"Explanation for first inferred fact:\")\n",
|
||||
" print(explanation.natural_language)\n",
|
||||
"\n",
|
||||
"# If we have a proof from backward chaining, explain it\n",
|
||||
"if proof:\n",
|
||||
" proof_explanation = generator.generate_explanation(proof)\n",
|
||||
" print(\"\\nExplanation for backward chaining proof:\")\n",
|
||||
" print(proof_explanation.natural_language)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"Reasoning and inference workflow:\n",
|
||||
"- Knowledge Graph Built\n",
|
||||
"- Inference Rules Defined\n",
|
||||
"- Facts Loaded into Engine\n",
|
||||
"- Forward Chaining Performed\n",
|
||||
"- Backward Chaining Performed\n",
|
||||
"- Explanations Generated\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"### Deep Dive: Reasoning Module\n",
|
||||
"\n",
|
||||
"This section provides an in-depth guide to Semantica's reasoning capabilities. Learn rule syntax, fact formats, chaining strategies, and explanation generation with robust, reproducible examples.\n",
|
||||
"\n",
|
||||
"**What you'll practice**\n",
|
||||
"- Defining rules with variables and predicates\n",
|
||||
"- Loading facts in predicate form\n",
|
||||
"- Running forward and backward chaining\n",
|
||||
"- Generating human-readable explanations\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.kg import GraphBuilder\n",
|
||||
"from semantica.reasoning import InferenceEngine, ExplanationGenerator\n",
|
||||
"\n",
|
||||
"builder = GraphBuilder()\n",
|
||||
"engine = InferenceEngine()\n",
|
||||
"explainer = ExplanationGenerator()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Rule Syntax\n",
|
||||
"\n",
|
||||
"Rules use predicate logic with variables prefixed by `?`.\n",
|
||||
"\n",
|
||||
"- Example: `IF parent_of(?a, ?b) AND parent_of(?b, ?c) THEN grandparent_of(?a, ?c)`\n",
|
||||
"- Variables unify across predicates in the same rule\n",
|
||||
"- Conclusions are added as new facts when conditions match\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"entities = [\n",
|
||||
" {\"id\": \"alice\", \"type\": \"Person\", \"name\": \"Alice\"},\n",
|
||||
" {\"id\": \"bob\", \"type\": \"Person\", \"name\": \"Bob\"},\n",
|
||||
" {\"id\": \"charlie\", \"type\": \"Person\", \"name\": \"Charlie\"},\n",
|
||||
" {\"id\": \"sf\", \"type\": \"Location\", \"name\": \"San Francisco\"},\n",
|
||||
" {\"id\": \"california\", \"type\": \"Location\", \"name\": \"California\"}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"relationships = [\n",
|
||||
" {\"source\": \"alice\", \"target\": \"bob\", \"type\": \"parent_of\"},\n",
|
||||
" {\"source\": \"bob\", \"target\": \"charlie\", \"type\": \"parent_of\"},\n",
|
||||
" {\"source\": \"sf\", \"target\": \"california\", \"type\": \"located_in\"},\n",
|
||||
" {\"source\": \"alice\", \"target\": \"sf\", \"type\": \"lives_in\"}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"knowledge_graph = builder.build([{\"entities\": entities, \"relationships\": relationships}])\n",
|
||||
"print(len(knowledge_graph.get(\"entities\", [])))\n",
|
||||
"print(len(knowledge_graph.get(\"relationships\", [])))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rules = [\n",
|
||||
" \"IF parent_of(?a, ?b) AND parent_of(?b, ?c) THEN grandparent_of(?a, ?c)\",\n",
|
||||
" \"IF lives_in(?x, ?y) AND located_in(?y, ?z) THEN lives_in(?x, ?z)\"\n",
|
||||
"]\n",
|
||||
"for r in rules:\n",
|
||||
" engine.add_rule(r)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"for rel in relationships:\n",
|
||||
" fact = f\"{rel['type']}({rel['source']}, {rel['target']})\"\n",
|
||||
" engine.add_fact(fact)\n",
|
||||
"\n",
|
||||
"derived = engine.forward_chain()\n",
|
||||
"print(len(derived))\n",
|
||||
"for d in derived:\n",
|
||||
" print(d.conclusion)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"goals = [\n",
|
||||
" \"grandparent_of(alice, charlie)\",\n",
|
||||
" \"lives_in(alice, california)\"\n",
|
||||
"]\n",
|
||||
"for g in goals:\n",
|
||||
" proof = engine.backward_chain(g)\n",
|
||||
" print(g)\n",
|
||||
" print(bool(proof))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if derived:\n",
|
||||
" exp = explainer.generate_explanation(derived[0])\n",
|
||||
" print(exp.natural_language)\n",
|
||||
"\n",
|
||||
"goal = \"grandparent_of(alice, charlie)\"\n",
|
||||
"proof = engine.backward_chain(goal)\n",
|
||||
"if proof:\n",
|
||||
" pexp = explainer.generate_explanation(proof)\n",
|
||||
" print(pexp.natural_language)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/08_Reasoning_and_Inference.ipynb)\n",
|
||||
"\n",
|
||||
"# Reasoning and Inference\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"Build knowledge graphs, define rules, perform forward/backward chaining, and generate explanations for AI reasoning using the **Semantica Reasoning Module**.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/reasoning/)\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",
|
||||
"## Workflow: Build KG → Define Rules → Forward/Backward Chaining → Generate Explanations\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -qU semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.kg import GraphBuilder\n",
|
||||
"from semantica.reasoning import Reasoner, ExplanationGenerator\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 1: Build Knowledge Graph\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"builder = GraphBuilder()\n",
|
||||
"\n",
|
||||
"entities = [\n",
|
||||
" {\"id\": \"alice\", \"type\": \"Person\", \"name\": \"Alice\"},\n",
|
||||
" {\"id\": \"bob\", \"type\": \"Person\", \"name\": \"Bob\"},\n",
|
||||
" {\"id\": \"charlie\", \"type\": \"Person\", \"name\": \"Charlie\"},\n",
|
||||
" {\"id\": \"sf\", \"type\": \"Location\", \"name\": \"San Francisco\"},\n",
|
||||
" {\"id\": \"california\", \"type\": \"Location\", \"name\": \"California\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"relationships = [\n",
|
||||
" {\"source\": \"alice\", \"target\": \"bob\", \"type\": \"parent_of\"},\n",
|
||||
" {\"source\": \"bob\", \"target\": \"charlie\", \"type\": \"parent_of\"},\n",
|
||||
" {\"source\": \"sf\", \"target\": \"california\", \"type\": \"located_in\"},\n",
|
||||
" {\"source\": \"alice\", \"target\": \"sf\", \"type\": \"lives_in\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"knowledge_graph = builder.build([{\"entities\": entities, \"relationships\": relationships}])\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Define Rules\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Initialize Reasoner\n",
|
||||
"reasoner = Reasoner()\n",
|
||||
"\n",
|
||||
"# Define rules using logic syntax\n",
|
||||
"rules = [\n",
|
||||
" \"IF parent_of(?a, ?b) AND parent_of(?b, ?c) THEN grandparent_of(?a, ?c)\",\n",
|
||||
" \"IF lives_in(?x, ?y) AND located_in(?y, ?z) THEN lives_in(?x, ?z)\"\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"for rule in rules:\n",
|
||||
" reasoner.add_rule(rule)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Forward Chaining\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Perform forward chaining to derive new facts\n",
|
||||
"# The Reasoner can infer facts directly from the knowledge graph or a list of facts\n",
|
||||
"inferred_facts = reasoner.infer_facts(knowledge_graph)\n",
|
||||
"\n",
|
||||
"print(f\"Inferred {len(inferred_facts)} new facts:\")\n",
|
||||
"for fact in inferred_facts:\n",
|
||||
" print(f\" - {fact}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Backward Chaining\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Define a goal to prove\n",
|
||||
"goal = \"grandparent_of(alice, charlie)\"\n",
|
||||
"\n",
|
||||
"# Perform backward chaining\n",
|
||||
"proof = reasoner.backward_chain(goal)\n",
|
||||
"\n",
|
||||
"if proof:\n",
|
||||
" print(f\"Goal '{goal}' proven successfully!\")\n",
|
||||
"else:\n",
|
||||
" print(f\"Could not prove goal '{goal}'.\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Generate Explanations\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"generator = ExplanationGenerator()\n",
|
||||
"\n",
|
||||
"# If we have a proof from backward chaining, explain it\n",
|
||||
"if proof:\n",
|
||||
" proof_explanation = generator.generate_explanation(proof)\n",
|
||||
" print(\"Explanation for backward chaining proof:\")\n",
|
||||
" print(proof_explanation.natural_language)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"Reasoning and inference workflow:\n",
|
||||
"- Knowledge Graph Built\n",
|
||||
"- Inference Rules Defined\n",
|
||||
"- Facts Loaded into Engine\n",
|
||||
"- Forward Chaining Performed\n",
|
||||
"- Backward Chaining Performed\n",
|
||||
"- Explanations Generated\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"### Deep Dive: Reasoning Module\n",
|
||||
"\n",
|
||||
"This section provides an in-depth guide to Semantica's reasoning capabilities. Learn rule syntax, fact formats, chaining strategies, and explanation generation with robust, reproducible examples.\n",
|
||||
"\n",
|
||||
"**What you'll practice**\n",
|
||||
"- Defining rules with variables and predicates\n",
|
||||
"- Loading facts in predicate form\n",
|
||||
"- Running forward and backward chaining\n",
|
||||
"- Generating human-readable explanations\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.kg import GraphBuilder\n",
|
||||
"from semantica.reasoning import Reasoner, ExplanationGenerator\n",
|
||||
"\n",
|
||||
"builder = GraphBuilder()\n",
|
||||
"reasoner = Reasoner()\n",
|
||||
"explainer = ExplanationGenerator()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Rule Syntax\n",
|
||||
"\n",
|
||||
"Rules use predicate logic with variables prefixed by `?`.\n",
|
||||
"\n",
|
||||
"- Example: `IF parent_of(?a, ?b) AND parent_of(?b, ?c) THEN grandparent_of(?a, ?c)`\n",
|
||||
"- Variables unify across predicates in the same rule\n",
|
||||
"- Conclusions are added as new facts when conditions match\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"entities = [\n",
|
||||
" {\"id\": \"alice\", \"type\": \"Person\", \"name\": \"Alice\"},\n",
|
||||
" {\"id\": \"bob\", \"type\": \"Person\", \"name\": \"Bob\"},\n",
|
||||
" {\"id\": \"charlie\", \"type\": \"Person\", \"name\": \"Charlie\"},\n",
|
||||
" {\"id\": \"sf\", \"type\": \"Location\", \"name\": \"San Francisco\"},\n",
|
||||
" {\"id\": \"california\", \"type\": \"Location\", \"name\": \"California\"}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"relationships = [\n",
|
||||
" {\"source\": \"alice\", \"target\": \"bob\", \"type\": \"parent_of\"},\n",
|
||||
" {\"source\": \"bob\", \"target\": \"charlie\", \"type\": \"parent_of\"},\n",
|
||||
" {\"source\": \"sf\", \"target\": \"california\", \"type\": \"located_in\"},\n",
|
||||
" {\"source\": \"alice\", \"target\": \"sf\", \"type\": \"lives_in\"}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"knowledge_graph = builder.build([{\"entities\": entities, \"relationships\": relationships}])\n",
|
||||
"print(len(knowledge_graph.get(\"entities\", [])))\n",
|
||||
"print(len(knowledge_graph.get(\"relationships\", [])))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"rules = [\n",
|
||||
" \"IF parent_of(?a, ?b) AND parent_of(?b, ?c) THEN grandparent_of(?a, ?c)\",\n",
|
||||
" \"IF lives_in(?x, ?y) AND located_in(?y, ?z) THEN lives_in(?x, ?z)\"\n",
|
||||
"]\n",
|
||||
"for r in rules:\n",
|
||||
" reasoner.add_rule(r)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"for rel in relationships:\n",
|
||||
" fact = f\"{rel['type']}({rel['source']}, {rel['target']})\"\n",
|
||||
" reasoner.add_fact(fact)\n",
|
||||
"\n",
|
||||
"derived = reasoner.forward_chain()\n",
|
||||
"print(len(derived))\n",
|
||||
"for d in derived:\n",
|
||||
" print(d.conclusion)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"goals = [\n",
|
||||
" \"grandparent_of(alice, charlie)\",\n",
|
||||
" \"lives_in(alice, california)\"\n",
|
||||
"]\n",
|
||||
"for g in goals:\n",
|
||||
" proof = reasoner.backward_chain(g)\n",
|
||||
" print(g)\n",
|
||||
" print(bool(proof))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if derived:\n",
|
||||
" exp = explainer.generate_explanation(derived[0])\n",
|
||||
" print(exp.natural_language)\n",
|
||||
"\n",
|
||||
"goal = \"grandparent_of(alice, charlie)\"\n",
|
||||
"proof = reasoner.backward_chain(goal)\n",
|
||||
"if proof:\n",
|
||||
" pexp = explainer.generate_explanation(proof)\n",
|
||||
" print(pexp.natural_language)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"Build an enterprise semantic layer: construct knowledge graph, generate ontology, create semantic layer, export RDF, and store in triple store.\n",
|
||||
"Build an enterprise semantic layer: construct knowledge graph, generate ontology, create semantic layer, export RDF, and store in triplet store.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/concepts/)\n",
|
||||
@@ -25,7 +25,16 @@
|
||||
"pip install semantica[all]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"## Workflow: Build KG → Generate Ontology → Create Semantic Layer → Export RDF → Triple Store\n"
|
||||
"## Workflow: Build KG → Generate Ontology → Create Semantic Layer → Export RDF \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -qU semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -37,7 +46,7 @@
|
||||
"from semantica.kg import GraphBuilder\n",
|
||||
"from semantica.ontology import OntologyGenerator\n",
|
||||
"from semantica.export import RDFExporter\n",
|
||||
"from semantica.triple_store import TripleStore\n"
|
||||
"from semantica.triplet_store import TripletStore\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -155,24 +164,9 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"exporter = RDFExporter()\n",
|
||||
"exporter.export(knowledge_graph, ontology, \"semantic_layer.rdf\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Store in Triple Store\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"triple_store = TripleStore()\n",
|
||||
"triple_store.store(knowledge_graph, ontology)\n"
|
||||
"# Export Knowledge Graph\n",
|
||||
"exporter.export(knowledge_graph, \"knowledge_graph.ttl\", format=\"turtle\")\n",
|
||||
"print(\"Exported knowledge graph to knowledge_graph.ttl\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -185,14 +179,42 @@
|
||||
"- Knowledge Graph Built\n",
|
||||
"- Ontology Generated\n",
|
||||
"- Semantic Layer Created with Mappings\n",
|
||||
"- RDF Export Completed\n",
|
||||
"- Triple Store Storage Completed\n"
|
||||
"- RDF Export Completed\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"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.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -6,35 +6,29 @@
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/10_Temporal_Knowledge_Graphs.ipynb)\n",
|
||||
"\n",
|
||||
"# Temporal Knowledge Graphs\n",
|
||||
"# Deep Dive: Temporal Knowledge Graphs\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates advanced temporal knowledge graph capabilities using TemporalGraphQuery, TemporalPatternDetector, TemporalVersionManager, and TemporalVisualizer.\n",
|
||||
"This notebook provides a comprehensive deep dive into **Temporal Knowledge Graphs (TKGs)** using Semantica. Unlike static KGs, TKGs capture the evolution of facts, relationships, and entities over time. This capability is crucial for applications like:\n",
|
||||
"\n",
|
||||
"- **Corporate History Analysis**: Tracking mergers, acquisitions, and leadership changes.\n",
|
||||
"- **Supply Chain Monitoring**: Tracing product movement and status changes.\n",
|
||||
"- **Financial Fraud Detection**: Analyzing sequences of transactions.\n",
|
||||
"\n",
|
||||
"We will build a rich scenario modeling the history of a tech ecosystem, covering 40 years of evolution.\n",
|
||||
"\n",
|
||||
"### Key Components Covered\n",
|
||||
"\n",
|
||||
"1. **`GraphBuilder` (Temporal Mode)**: Constructing KGs with time-aware properties.\n",
|
||||
"2. **`TemporalGraphQuery`**: Performing point-in-time, interval, and path queries.\n",
|
||||
"3. **`TemporalPatternDetector`**: Identifying sequences and cyclic patterns.\n",
|
||||
"4. **`TemporalVersionManager`**: Managing snapshots and comparing graph states.\n",
|
||||
"5. **`TemporalVisualizer`**: Interactive timelines and evolution plots.\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/kg/)\n",
|
||||
"\n",
|
||||
"### Learning Objectives\n",
|
||||
"\n",
|
||||
"- Use TemporalGraphQuery for time-aware queries\n",
|
||||
"- Use TemporalPatternDetector to detect temporal patterns\n",
|
||||
"- Use TemporalVersionManager for temporal versioning and snapshots\n",
|
||||
"- Use TemporalVisualizer to visualize temporal data\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: Build Temporal KG → Time-Aware Queries → Pattern Detection → Version Management → Visualization\n"
|
||||
"## Installation\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -43,33 +37,123 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# !pip install semantica[all]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"from datetime import datetime\n",
|
||||
"from semantica.kg import GraphBuilder, TemporalGraphQuery, TemporalPatternDetector, TemporalVersionManager\n",
|
||||
"from semantica.visualization import TemporalVisualizer\n",
|
||||
"from datetime import datetime\n",
|
||||
"import plotly.offline as pyo\n",
|
||||
"pyo.init_notebook_mode(connected=True)\n",
|
||||
"\n",
|
||||
"builder = GraphBuilder()\n",
|
||||
"# Ensure consistent output for reproducibility\n",
|
||||
"import random\n",
|
||||
"random.seed(42)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 1: Scenario Definition & Data Preparation\n",
|
||||
"\n",
|
||||
"We define a dataset representing the history of \"TechCorp\" and \"InnovateInc\", including their founders, products, and eventual merger.\n",
|
||||
"\n",
|
||||
"**Temporal Properties**:\n",
|
||||
"- Entities have `founded`, `born`, `released` dates.\n",
|
||||
"- Relationships have `timestamp` (point event) or `valid_from`/`valid_to` (intervals).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 1. Define Entities with Temporal Metadata\n",
|
||||
"entities = [\n",
|
||||
" {\"id\": \"e1\", \"type\": \"Organization\", \"name\": \"Apple Inc.\", \"properties\": {\"founded\": \"1976\"}},\n",
|
||||
" {\"id\": \"e2\", \"type\": \"Person\", \"name\": \"Steve Jobs\", \"properties\": {\"born\": \"1955\"}}\n",
|
||||
" # Organizations\n",
|
||||
" {\"id\": \"org_1\", \"type\": \"Organization\", \"name\": \"TechCorp\", \"properties\": {\"founded\": \"1980-01-01\", \"industry\": \"Hardware\"}},\n",
|
||||
" {\"id\": \"org_2\", \"type\": \"Organization\", \"name\": \"InnovateInc\", \"properties\": {\"founded\": \"1995-06-15\", \"industry\": \"Software\"}},\n",
|
||||
" {\"id\": \"org_3\", \"type\": \"Organization\", \"name\": \"FutureSystems\", \"properties\": {\"founded\": \"2010-03-10\", \"industry\": \"AI\"}},\n",
|
||||
" \n",
|
||||
" # People\n",
|
||||
" {\"id\": \"per_1\", \"type\": \"Person\", \"name\": \"Alice Founder\", \"properties\": {\"born\": \"1955-05-20\"}},\n",
|
||||
" {\"id\": \"per_2\", \"type\": \"Person\", \"name\": \"Bob Coder\", \"properties\": {\"born\": \"1970-08-12\"}},\n",
|
||||
" {\"id\": \"per_3\", \"type\": \"Person\", \"name\": \"Charlie CEO\", \"properties\": {\"born\": \"1980-02-28\"}},\n",
|
||||
" \n",
|
||||
" # Products\n",
|
||||
" {\"id\": \"prod_1\", \"type\": \"Product\", \"name\": \"HomePC\", \"properties\": {\"released\": \"1985-11-20\"}},\n",
|
||||
" {\"id\": \"prod_2\", \"type\": \"Product\", \"name\": \"SoftOS\", \"properties\": {\"released\": \"1998-07-25\"}},\n",
|
||||
" {\"id\": \"prod_3\", \"type\": \"Product\", \"name\": \"SmartAI\", \"properties\": {\"released\": \"2015-01-10\"}}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# 2. Define Temporal Relationships\n",
|
||||
"relationships = [\n",
|
||||
" {\"source\": \"e2\", \"target\": \"e1\", \"type\": \"founded\", \"properties\": {\"timestamp\": \"1976-04-01\"}}\n",
|
||||
" # Founding Events (Point in time)\n",
|
||||
" {\"source\": \"per_1\", \"target\": \"org_1\", \"type\": \"founded\", \"timestamp\": \"1980-01-01\", \"properties\": {\"timestamp\": \"1980-01-01\"}},\n",
|
||||
" {\"source\": \"per_2\", \"target\": \"org_2\", \"type\": \"founded\", \"timestamp\": \"1995-06-15\", \"properties\": {\"timestamp\": \"1995-06-15\"}},\n",
|
||||
" \n",
|
||||
" # Employment (Intervals)\n",
|
||||
" {\"source\": \"per_1\", \"target\": \"org_1\", \"type\": \"ceo_of\", \"valid_from\": \"1980-01-01\", \"valid_to\": \"2000-01-01\", \"properties\": {\"role\": \"CEO\"}},\n",
|
||||
" {\"source\": \"per_3\", \"target\": \"org_1\", \"type\": \"ceo_of\", \"valid_from\": \"2000-01-02\", \"valid_to\": \"2023-01-01\", \"properties\": {\"role\": \"CEO\"}},\n",
|
||||
" {\"source\": \"per_2\", \"target\": \"org_2\", \"type\": \"cto_of\", \"valid_from\": \"1995-06-15\", \"valid_to\": \"2010-05-01\", \"properties\": {\"role\": \"CTO\"}},\n",
|
||||
" \n",
|
||||
" # Product Launches\n",
|
||||
" {\"source\": \"org_1\", \"target\": \"prod_1\", \"type\": \"launched\", \"timestamp\": \"1985-11-20\", \"properties\": {\"timestamp\": \"1985-11-20\"}},\n",
|
||||
" {\"source\": \"org_2\", \"target\": \"prod_2\", \"type\": \"launched\", \"timestamp\": \"1998-07-25\", \"properties\": {\"timestamp\": \"1998-07-25\"}},\n",
|
||||
" {\"source\": \"org_3\", \"target\": \"prod_3\", \"type\": \"launched\", \"timestamp\": \"2015-01-10\", \"properties\": {\"timestamp\": \"2015-01-10\"}},\n",
|
||||
" \n",
|
||||
" # Corporate Actions\n",
|
||||
" {\"source\": \"org_1\", \"target\": \"org_2\", \"type\": \"acquired\", \"timestamp\": \"2010-05-01\", \"properties\": {\"amount\": \"$5B\", \"timestamp\": \"2010-05-01\"}},\n",
|
||||
" {\"source\": \"org_1\", \"target\": \"org_3\", \"type\": \"invested_in\", \"timestamp\": \"2012-08-15\", \"properties\": {\"amount\": \"$100M\", \"timestamp\": \"2012-08-15\"}}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"print(f\"Defined {len(entities)} entities and {len(relationships)} temporal relationships.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Building the Temporal Graph\n",
|
||||
"\n",
|
||||
"We use `GraphBuilder` with `enable_temporal=True`. This instructs the builder to index temporal properties like `timestamp`, `valid_from`, and `valid_to`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"builder = GraphBuilder(\n",
|
||||
" enable_temporal=True,\n",
|
||||
" temporal_granularity=\"day\" # Can be 'year', 'month', 'day', 'hour'\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"temporal_kg = builder.build(entities, relationships)\n",
|
||||
"\n",
|
||||
"print(f\"Built temporal knowledge graph with {len(entities)} entities\")\n"
|
||||
"# The graph object now contains temporal indices\n",
|
||||
"print(\"Graph built successfully.\")\n",
|
||||
"print(f\"Nodes: {len(temporal_kg['entities'])}\")\n",
|
||||
"print(f\"Edges: {len(temporal_kg['relationships'])}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Time-Aware Queries\n",
|
||||
"## Step 3: Advanced Temporal Querying\n",
|
||||
"\n",
|
||||
"Query the graph at specific time points.\n"
|
||||
"We use `TemporalGraphQuery` to ask time-sensitive questions."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -78,25 +162,48 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"temporal_query = TemporalGraphQuery()\n",
|
||||
"query_engine = TemporalGraphQuery()\n",
|
||||
"\n",
|
||||
"query_result = temporal_query.query_time_range(\n",
|
||||
"# 1. Point-in-Time Query\n",
|
||||
"# \"Who was the CEO of TechCorp in 1990?\"\n",
|
||||
"ceo_1990 = query_engine.query_at_time(\n",
|
||||
" temporal_kg,\n",
|
||||
" query=\"Find the CEO of TechCorp\",\n",
|
||||
" at_time=\"1990-06-01\"\n",
|
||||
")\n",
|
||||
"print(\"CEO in 1990:\", [e['id'] for e in ceo_1990.get('entities', [])])\n",
|
||||
"\n",
|
||||
"# \"Who was the CEO of TechCorp in 2015?\"\n",
|
||||
"ceo_2015 = query_engine.query_at_time(\n",
|
||||
" temporal_kg,\n",
|
||||
" query=\"Find the CEO of TechCorp\",\n",
|
||||
" at_time=\"2015-06-01\"\n",
|
||||
")\n",
|
||||
"print(\"CEO in 2015:\", [e['id'] for e in ceo_2015.get('entities', [])])\n",
|
||||
"\n",
|
||||
"# 2. Temporal Path Finding\n",
|
||||
"# \"How did Alice (Founder) connect to SmartAI (Product released in 2015)?\"\n",
|
||||
"# This requires traversing through time: Alice -> founded TechCorp -> invested in FutureSystems -> launched SmartAI\n",
|
||||
"paths = query_engine.find_temporal_paths(\n",
|
||||
" graph=temporal_kg,\n",
|
||||
" query=\"Find entities founded in 1976\",\n",
|
||||
" start_time=\"1976-01-01\",\n",
|
||||
" end_time=\"1976-12-31\"\n",
|
||||
" source=\"per_1\", # Alice\n",
|
||||
" target=\"prod_3\", # SmartAI\n",
|
||||
" start_time=\"1980-01-01\",\n",
|
||||
" end_time=\"2020-01-01\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"Time-aware query returned {len(query_result.get('entities', []))} entities\")\n"
|
||||
"print(f\"\\nFound {len(paths)} temporal paths from Alice to SmartAI.\")\n",
|
||||
"for i, path in enumerate(paths):\n",
|
||||
" print(f\"Path {i+1}: {path}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Temporal Pattern Detection\n",
|
||||
"## Step 4: Graph Evolution Analysis\n",
|
||||
"\n",
|
||||
"Detect temporal patterns in the graph.\n"
|
||||
"We can analyze how the graph properties change over time using `analyze_evolution`."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -105,24 +212,56 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pattern_detector = TemporalPatternDetector()\n",
|
||||
"evolution_stats = query_engine.analyze_evolution(\n",
|
||||
" temporal_kg,\n",
|
||||
" start_time=\"1980-01-01\",\n",
|
||||
" end_time=\"2025-01-01\",\n",
|
||||
" metrics=[\"count\", \"diversity\", \"stability\"]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"patterns = pattern_detector.detect_temporal_patterns(\n",
|
||||
"print(\"\\nEvolution Statistics (1980-2025):\")\n",
|
||||
"print(f\"Total Relationships: {evolution_stats.get('count', 'N/A')}\")\n",
|
||||
"print(f\"Relationship Diversity: {evolution_stats.get('diversity', 'N/A')}\")\n",
|
||||
"print(f\"Graph Stability: {evolution_stats.get('stability', 'N/A')}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Temporal Pattern Detection\n",
|
||||
"\n",
|
||||
"We use `TemporalPatternDetector` to automatically find recurring structures, such as sequences (A -> B -> C) or cycles."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"detector = TemporalPatternDetector()\n",
|
||||
"\n",
|
||||
"# Detect sequential patterns (e.g., Founded -> Launched -> Acquired)\n",
|
||||
"sequences = detector.detect_temporal_patterns(\n",
|
||||
" temporal_kg,\n",
|
||||
" pattern_type=\"sequence\",\n",
|
||||
" min_frequency=1\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"Detected {len(patterns)} temporal patterns\")\n"
|
||||
"print(f\"\\nDetected {len(sequences)} sequential patterns.\")\n",
|
||||
"for seq in sequences[:3]: # Show top 3\n",
|
||||
" print(f\"Pattern: {seq.get('pattern')}\")\n",
|
||||
" print(f\"Support: {seq.get('support')}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Version Management\n",
|
||||
"## Step 6: Version Management & Comparisons\n",
|
||||
"\n",
|
||||
"Manage temporal versions and snapshots.\n"
|
||||
"In real-world scenarios, KGs are updated in batches. `TemporalVersionManager` handles these versions."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -133,19 +272,25 @@
|
||||
"source": [
|
||||
"version_manager = TemporalVersionManager()\n",
|
||||
"\n",
|
||||
"snapshot = version_manager.create_snapshot(temporal_kg, timestamp=datetime.now())\n",
|
||||
"# Create explicit versions\n",
|
||||
"v1_1990 = version_manager.create_version(temporal_kg, timestamp=\"1990-01-01\", version_label=\"v1.0 (Early Days)\")\n",
|
||||
"v2_2010 = version_manager.create_version(temporal_kg, timestamp=\"2010-01-01\", version_label=\"v2.0 (Post-Merger)\")\n",
|
||||
"\n",
|
||||
"print(f\"Created temporal snapshot at {snapshot.get('timestamp', 'N/A')}\")\n",
|
||||
"print(f\"Snapshot contains {len(snapshot.get('entities', []))} entities\")\n"
|
||||
"# Compare versions\n",
|
||||
"diff = version_manager.compare_versions(v1_1990, v2_2010)\n",
|
||||
"\n",
|
||||
"print(f\"\\nComparing {v1_1990['label']} vs {v2_2010['label']}:\")\n",
|
||||
"print(f\"New Entities: {diff.get('entities_added', 0)}\")\n",
|
||||
"print(f\"New Relationships: {diff.get('relationships_added', 0)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Temporal Visualization\n",
|
||||
"## Step 7: Visualizing the Timeline\n",
|
||||
"\n",
|
||||
"Visualize temporal data.\n"
|
||||
"Finally, `TemporalVisualizer` brings the data to life. We will create an interactive timeline and a snapshot comparison."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -154,9 +299,46 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"temporal_visualizer = TemporalVisualizer()\n",
|
||||
"visualizer = TemporalVisualizer()\n",
|
||||
"\n",
|
||||
"visualization = temporal_visualizer.visualize_timeline(temporal_kg, output=\"interactive\")\n"
|
||||
"# 1. Interactive Timeline\n",
|
||||
"# Prepare events for visualization (extract from KG)\n",
|
||||
"def extract_events(graph):\n",
|
||||
" events = []\n",
|
||||
" for rel in graph['relationships']:\n",
|
||||
" # Point events\n",
|
||||
" if rel.get('timestamp'):\n",
|
||||
" events.append({\n",
|
||||
" 'timestamp': rel['timestamp'],\n",
|
||||
" 'type': rel['type'],\n",
|
||||
" 'label': f\"{rel['source']} -> {rel['target']}\",\n",
|
||||
" 'entity': rel['source']\n",
|
||||
" })\n",
|
||||
" # Interval events (start)\n",
|
||||
" if rel.get('valid_from'):\n",
|
||||
" events.append({\n",
|
||||
" 'timestamp': rel['valid_from'],\n",
|
||||
" 'type': f\"{rel['type']} (start)\",\n",
|
||||
" 'label': f\"{rel['source']} -> {rel['target']}\",\n",
|
||||
" 'entity': rel['source']\n",
|
||||
" })\n",
|
||||
" return {'events': events}\n",
|
||||
"\n",
|
||||
"temporal_data = extract_events(temporal_kg)\n",
|
||||
"timeline_fig = visualizer.visualize_timeline(temporal_data, output=\"interactive\")\n",
|
||||
"# In a notebook, this would render a Plotly figure. \n",
|
||||
"timeline_fig.show()\n",
|
||||
"\n",
|
||||
"# 2. Version History Visualization\n",
|
||||
"history = [\n",
|
||||
" {\"version\": \"v1.0\", \"timestamp\": \"1990-01-01\", \"changes\": \"Founding Era\"},\n",
|
||||
" {\"version\": \"v2.0\", \"timestamp\": \"2010-01-01\", \"changes\": \"Expansion Era\"},\n",
|
||||
" {\"version\": \"v3.0\", \"timestamp\": \"2020-01-01\", \"changes\": \"AI Era\"}\n",
|
||||
"]\n",
|
||||
"history_fig = visualizer.visualize_version_history(history, output=\"interactive\")\n",
|
||||
"history_fig.show()\n",
|
||||
"\n",
|
||||
"print(\"Visualizations generated (render requires Jupyter environment).\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -165,66 +347,38 @@
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"You've learned advanced temporal knowledge graph capabilities:\n",
|
||||
"In this deep dive, we:\n",
|
||||
"1. **modeled** a complex corporate history with temporal metadata.\n",
|
||||
"2. **Built** a time-aware knowledge graph using `GraphBuilder`.\n",
|
||||
"3. **Queried** specific time slices and intervals to reconstruct history.\n",
|
||||
"4. **Traced** temporal paths to understand indirect connections.\n",
|
||||
"5. **Analyzed** the graph's evolution metrics.\n",
|
||||
"6. **Managed** versions and visualized the timeline.\n",
|
||||
"7. **Visualized** the data with `TemporalVisualizer`.\n",
|
||||
"\n",
|
||||
"- **TemporalGraphQuery**: Time-aware graph querying\n",
|
||||
"- **TemporalPatternDetector**: Temporal pattern detection\n",
|
||||
"- **TemporalVersionManager**: Temporal versioning and snapshots\n",
|
||||
"- **TemporalVisualizer**: Temporal data visualization\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Snapshot Comparison and Version History\n",
|
||||
"\n",
|
||||
"Compare graph snapshots across time and visualize version history."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Create multiple versions\n",
|
||||
"version_manager = TemporalVersionManager()\n",
|
||||
"version_2020 = version_manager.create_version(temporal_kg, timestamp=\"2020-01-01\", version_label=\"v2020\")\n",
|
||||
"# Simulate changes for 2023\n",
|
||||
"temporal_kg_updated = {\n",
|
||||
" \"entities\": temporal_kg.get(\"entities\", []),\n",
|
||||
" \"relationships\": temporal_kg.get(\"relationships\", []) + [\n",
|
||||
" {\"source\": \"e1\", \"target\": \"e2\", \"type\": \"collaborated_with\", \"valid_from\": \"2023-01-01\"}\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"version_2023 = version_manager.create_version(temporal_kg_updated, timestamp=\"2023-01-01\", version_label=\"v2023\")\n",
|
||||
"\n",
|
||||
"# Build snapshots dict for comparison\n",
|
||||
"snapshots = {\n",
|
||||
" version_2020[\"timestamp\"]: version_2020,\n",
|
||||
" version_2023[\"timestamp\"]: version_2023\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# Visualize snapshot comparison\n",
|
||||
"fig_snapshots = temporal_visualizer.visualize_snapshot_comparison(snapshots, output=\"interactive\")\n",
|
||||
"\n",
|
||||
"# Build version history list\n",
|
||||
"version_history = [\n",
|
||||
" {\"version\": version_2020.get(\"label\", \"v2020\"), \"timestamp\": version_2020.get(\"timestamp\"), \"changes\": f\"Entities: {len(version_2020.get('entities', []))}, Relationships: {len(version_2020.get('relationships', []))}\"},\n",
|
||||
" {\"version\": version_2023.get(\"label\", \"v2023\"), \"timestamp\": version_2023.get(\"timestamp\"), \"changes\": f\"Entities: {len(version_2023.get('entities', []))}, Relationships: {len(version_2023.get('relationships', []))}\"}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Visualize version history\n",
|
||||
"fig_versions = temporal_visualizer.visualize_version_history(version_history, output=\"interactive\")\n"
|
||||
"This workflow forms the backbone of temporal intelligence applications in Semantica."
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
|
||||
@@ -4,222 +4,497 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/11_Advanced_Context_Engineering.ipynb)\n",
|
||||
"# Advanced Context Engineering: The Agent's Brain\n",
|
||||
"\n",
|
||||
"# Advanced Context Engineering\n",
|
||||
"Welcome to the **Master Class** on Semantica Context Engineering. This notebook demonstrates how to build a production-grade memory system for your AI agents.\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"Unlike simple chatbots that forget everything after a session, a **Context-Aware Agent** needs:\n",
|
||||
"* **Long-term Memory**: To recall facts from weeks ago.\n",
|
||||
"* **Structured Knowledge**: To understand how entities (People, Projects, Topics) are connected.\n",
|
||||
"* **Hybrid Retrieval**: To combine fuzzy text search with precise graph traversal.\n",
|
||||
"\n",
|
||||
"This notebook covers advanced topics in context engineering using Semantica. We will explore custom memory management strategies, tuning hybrid retrieval, and extending the system with custom graph builders.\n",
|
||||
"## Learning Objectives\n",
|
||||
"\n",
|
||||
"### Learning Objectives\n",
|
||||
"In this walkthrough, we will:\n",
|
||||
"1. **Initialize Production Stores**: Replace toy examples with real **Vector Stores** (FAISS) and **Graph Stores** (Neo4j).\n",
|
||||
"2. **Build the Agent Context**: Configure the central brain that orchestrates memory.\n",
|
||||
"3. **Ingest Knowledge**: Store complex documents and auto-extract entities.\n",
|
||||
"4. **Inject Relationships**: Manually teach the agent about connections in the world.\n",
|
||||
"5. **Perform GraphRAG**: Execute advanced queries that \"hop\" through the knowledge graph to find answers standard RAG misses.\n",
|
||||
"6. **Manage Lifecycle**: Learn to prune old memories and keep the system healthy.\n",
|
||||
"\n",
|
||||
"- **Custom Memory Pruning**: Implement importance-based pruning instead of FIFO.\n",
|
||||
"- **Hybrid Retrieval Tuning**: Optimize weights for vector, graph, and keyword search.\n",
|
||||
"- **Custom Extensions**: Register custom graph building methods.\n",
|
||||
"- **Performance Optimization**: Balance token limits and retrieval latency.\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## 1. Setup\n",
|
||||
"\n",
|
||||
"We'll start by setting up a mock vector store and importing necessary components."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import List, Dict, Any, Optional\n",
|
||||
"from semantica.context import AgentMemory, AgentContext, ContextGraph, ContextRetriever, VectorStore\n",
|
||||
"from semantica.context import registry\n",
|
||||
"\n",
|
||||
"# Mock Vector Store (same as in introduction)\n",
|
||||
"class MockVectorStore(VectorStore):\n",
|
||||
" def __init__(self):\n",
|
||||
" self.items = {}\n",
|
||||
" self.counter = 0\n",
|
||||
" def add(self, texts, metadata=None, **kwargs):\n",
|
||||
" ids = []\n",
|
||||
" for i, text in enumerate(texts):\n",
|
||||
" id_ = f\"id_{self.counter}\"\n",
|
||||
" self.items[id_] = {\"text\": text, \"metadata\": metadata[i] if metadata else {}}\n",
|
||||
" ids.append(id_)\n",
|
||||
" self.counter += 1\n",
|
||||
" return ids\n",
|
||||
" def search(self, query, limit=5, **kwargs):\n",
|
||||
" return [{\n",
|
||||
" \"id\": k, \"content\": v[\"text\"], \"score\": 0.85, \"metadata\": v[\"metadata\"]\n",
|
||||
" } for k, v in list(self.items.items())[:limit]]\n",
|
||||
" def delete(self, ids, **kwargs):\n",
|
||||
" return True\n",
|
||||
"\n",
|
||||
"vs = MockVectorStore()\n",
|
||||
"kg = ContextGraph()"
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2cf97cbc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Custom Memory Pruning Strategy\n",
|
||||
"## 1. Installation\n",
|
||||
"\n",
|
||||
"By default, `AgentMemory` uses a FIFO (First-In-First-Out) strategy combined with a token limit to prune short-term memory. However, you might want to keep \"important\" memories longer regardless of their age.\n",
|
||||
"To get started, simply install the package:\n",
|
||||
"\n",
|
||||
"Let's subclass `AgentMemory` to implement an importance-based pruning strategy."
|
||||
"```bash\n",
|
||||
"pip install semantica\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "88491af5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class ImportanceAwareMemory(AgentMemory):\n",
|
||||
" def _prune_short_term_memory(self):\n",
|
||||
" \"\"\"\n",
|
||||
" Custom pruning: Always keep items marked as 'important' in metadata,\n",
|
||||
" then prune others based on token limits.\n",
|
||||
" \"\"\"\n",
|
||||
" if not self.short_term_memory:\n",
|
||||
" return\n",
|
||||
"!pip install -qU semantica "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d6401d91",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"import os\n",
|
||||
"import time\n",
|
||||
"from typing import Any, List, Dict, Optional\n",
|
||||
"\n",
|
||||
" # Separate important items\n",
|
||||
" important_items = [item for item in self.short_term_memory if item.metadata.get(\"important\")]\n",
|
||||
" other_items = [item for item in self.short_term_memory if not item.metadata.get(\"important\")]\n",
|
||||
" \n",
|
||||
" # Calculate tokens used by important items\n",
|
||||
" important_tokens = sum(self._count_tokens(item.content) for item in important_items)\n",
|
||||
" \n",
|
||||
" # Calculate remaining budget\n",
|
||||
" remaining_tokens = max(0, self.token_limit - important_tokens)\n",
|
||||
" \n",
|
||||
" # Prune other items to fit remaining budget\n",
|
||||
" kept_others = []\n",
|
||||
" current_tokens = 0\n",
|
||||
" \n",
|
||||
" # Iterate in reverse (newest first) to keep recent items\n",
|
||||
" for item in reversed(other_items):\n",
|
||||
" item_tokens = self._count_tokens(item.content)\n",
|
||||
" if current_tokens + item_tokens <= remaining_tokens:\n",
|
||||
" kept_others.insert(0, item)\n",
|
||||
" current_tokens += item_tokens\n",
|
||||
" else:\n",
|
||||
" break # Stop once we hit the limit\n",
|
||||
" \n",
|
||||
" # Reconstruct memory: Important items + kept recent items\n",
|
||||
" # Sort by timestamp to maintain order\n",
|
||||
" all_kept = sorted(important_items + kept_others, key=lambda x: x.timestamp)\n",
|
||||
" self.short_term_memory = all_kept\n",
|
||||
"# Add project root to path to import semantica\n",
|
||||
"sys.path.append(os.path.abspath(os.path.join(os.getcwd(), \"../../\")))\n",
|
||||
"\n",
|
||||
"# Test the custom memory\n",
|
||||
"memory = ImportanceAwareMemory(vector_store=vs, token_limit=100)\n",
|
||||
"# Core Imports\n",
|
||||
"from semantica.context import AgentContext, ContextGraph, AgentMemory\n",
|
||||
"from semantica.vector_store import VectorStore\n",
|
||||
"from semantica.graph_store import GraphStore\n",
|
||||
"\n",
|
||||
"# Add an old important memory\n",
|
||||
"memory.store(\"IMPORTANT: User's name is Alice\", metadata={\"important\": True})\n",
|
||||
"\n",
|
||||
"# Fill with filler memories\n",
|
||||
"for i in range(20):\n",
|
||||
" memory.store(f\"Filler memory {i} \" * 5) # Consumes tokens\n",
|
||||
"\n",
|
||||
"print(f\"Short-term items: {len(memory.short_term_memory)}\")\n",
|
||||
"print(\"First item (should be the important one):\", memory.short_term_memory[0].content)"
|
||||
"print(\"Libraries imported successfully.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7e263672",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Tuning Hybrid Retrieval\n",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "dbad46dd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Initialize Storage Backends\n",
|
||||
"\n",
|
||||
"Hybrid retrieval combines scores from vector search and graph traversal. You can tune the `hybrid_alpha` parameter to weight these components.\n",
|
||||
"We will now connect to our persistent storage layers. Semantica abstracts these behind unified interfaces, so you can swap backends (e.g., switch from FAISS to Weaviate) without changing your application logic.\n",
|
||||
"\n",
|
||||
"- `hybrid_alpha = 0.0`: Pure Vector Search\n",
|
||||
"- `hybrid_alpha = 1.0`: Pure Graph Search\n",
|
||||
"- `hybrid_alpha = 0.5`: Balanced (Default)\n",
|
||||
"\n",
|
||||
"Additionally, `max_expansion_hops` controls how far we traverse the graph from retrieved nodes."
|
||||
"### Vector Store (The Library)\n",
|
||||
"Holds the *content* of memories and documents, indexed by semantic meaning."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "812158a5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Populate graph with some structure\n",
|
||||
"kg.add_node(\"python\", \"concept\", \"Python\")\n",
|
||||
"kg.add_node(\"ml\", \"concept\", \"Machine Learning\")\n",
|
||||
"kg.add_edge(\"python\", \"ml\", \"used_for\")\n",
|
||||
"try:\n",
|
||||
" # Initialize FAISS Vector Store\n",
|
||||
" # You can also use: backend=\"weaviate\", backend=\"qdrant\", etc.\n",
|
||||
" vs = VectorStore(backend=\"faiss\", dimension=768)\n",
|
||||
" print(\"VectorStore initialized (Backend: FAISS)\")\n",
|
||||
"except ImportError:\n",
|
||||
" print(\"FAISS not installed. Using in-memory fallback (not persistent).\")\n",
|
||||
" vs = VectorStore(backend=\"inmemory\", dimension=768)\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"VectorStore Error: {e}\")\n",
|
||||
" vs = None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8933cfef",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Graph Store (The Map)\n",
|
||||
"Holds the *connections* between entities. This is crucial for reasoning."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7c2aa896",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"try:\n",
|
||||
" # Initialize Neo4j Graph Store\n",
|
||||
" # Ensure your Docker container is running!\n",
|
||||
" gs = GraphStore(\n",
|
||||
" backend=\"neo4j\",\n",
|
||||
" uri=\"bolt://localhost:7687\",\n",
|
||||
" user=\"neo4j\",\n",
|
||||
" password=\"password\"\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" # Test connection\n",
|
||||
" if gs.connect():\n",
|
||||
" print(\"GraphStore connected (Backend: Neo4j)\")\n",
|
||||
" else:\n",
|
||||
" raise ConnectionError(\"Could not connect to Neo4j\")\n",
|
||||
"\n",
|
||||
"retriever = ContextRetriever(\n",
|
||||
" memory_store=memory,\n",
|
||||
" knowledge_graph=kg,\n",
|
||||
" vector_store=vs,\n",
|
||||
" hybrid_alpha=0.7, # Favor graph connections\n",
|
||||
" max_expansion_hops=2 # Traverse deeper\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"GraphStore Connection Failed: {e}\")\n",
|
||||
" print(\" Switching to in-memory ContextGraph (Non-persistent fallback)\")\n",
|
||||
" gs = ContextGraph() # Fallback implementation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e17b7765",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cebbe65f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. The Agent Context\n",
|
||||
"\n",
|
||||
"The `AgentContext` is the high-level orchestrator. It sits on top of the Vector and Graph stores and manages the flow of information.\n",
|
||||
"\n",
|
||||
"**Configuration for GraphRAG:**\n",
|
||||
"* `use_graph_expansion=True`: When retrieving, don't just look at the doc, look at its neighbors.\n",
|
||||
"* `max_expansion_hops=2`: How far to traverse? (e.g., A -> B -> C).\n",
|
||||
"* `hybrid_alpha=0.6`: Weighting. 0.0 is pure Vector, 1.0 is pure Graph. 0.6 favors graph slightly."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f3b2eff6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"if vs:\n",
|
||||
" context = AgentContext(\n",
|
||||
" vector_store=vs,\n",
|
||||
" knowledge_graph=gs,\n",
|
||||
" retention_days=90, # Remember things for 3 months\n",
|
||||
" use_graph_expansion=True, # Enable GraphRAG\n",
|
||||
" max_expansion_hops=2, # 2-Hop reasoning\n",
|
||||
" hybrid_alpha=0.6 # Balanced retrieval\n",
|
||||
" )\n",
|
||||
" print(\"Agent Context is online and ready.\")\n",
|
||||
"else:\n",
|
||||
" print(\"Cannot proceed without VectorStore.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2db1ef53",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b7efb347",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Ingestion: Teaching the Agent\n",
|
||||
"\n",
|
||||
"We can store different types of information. The system is smart enough to distinguish between a conversational memory and a factual document.\n",
|
||||
"\n",
|
||||
"### A. Episodic Memory (Conversations)\n",
|
||||
"These are raw logs of interactions. They provide the \"personal\" history."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "71adf433",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"user_id = \"user_123\"\n",
|
||||
"session_id = \"session_alpha\"\n",
|
||||
"\n",
|
||||
"# Store a user preference\n",
|
||||
"mem_id = context.store(\n",
|
||||
" content=\"I am working on a new project called 'Project Apollo' which uses Python and React.\",\n",
|
||||
" conversation_id=session_id,\n",
|
||||
" user_id=user_id,\n",
|
||||
" metadata={\"type\": \"user_preference\"}\n",
|
||||
")\n",
|
||||
"print(f\"Memory Stored: {mem_id}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "00179ec6",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### B. Semantic Knowledge (Documents)\n",
|
||||
"When we feed documents, we want to **extract entities** and **link them**. \n",
|
||||
"\n",
|
||||
"*(Note: In a real setup, this uses an LLM to parse entities. Here we use the context module's native extraction capabilities.)*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3a98ca53",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"documents = [\n",
|
||||
" {\n",
|
||||
" \"content\": \"Project Apollo is a next-gen web framework designed for high scalability.\",\n",
|
||||
" \"metadata\": {\"source\": \"internal_wiki\", \"category\": \"projects\"}\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"content\": \"Python 3.12 introduces significant performance improvements for async workloads.\",\n",
|
||||
" \"metadata\": {\"source\": \"tech_news\", \"category\": \"languages\"}\n",
|
||||
" }\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Store documents and trigger graph build\n",
|
||||
"stats = context.store(\n",
|
||||
" documents,\n",
|
||||
" extract_entities=True, # Extract entities from text\n",
|
||||
" extract_relationships=True, # Infer relationships\n",
|
||||
" link_entities=True # Connect to existing graph nodes\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"results = retriever.retrieve(\"Python\")\n",
|
||||
"for res in results:\n",
|
||||
" print(f\"Source: {res.source}, Score: {res.score:.2f}\")"
|
||||
"print(\"Knowledge Ingestion Stats:\", stats)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "912bb201",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Extending with Custom Methods\n",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c2632192",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Graph Engineering: Manual Injection\n",
|
||||
"\n",
|
||||
"Semantica's registry system allows you to plug in custom logic. Let's register a custom graph builder that creates a star graph topology."
|
||||
"Sometimes automatic extraction isn't enough. You want to enforce specific business logic or relationships. We can use `build_graph` to manually inject nodes and edges.\n",
|
||||
"\n",
|
||||
"**We will define:**\n",
|
||||
"* **User** (Alice)\n",
|
||||
"* **Role** (Admin)\n",
|
||||
"* **Project** (Apollo)\n",
|
||||
"* **Relationship**: Alice *MANAGES* Project Apollo."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "970b605c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def star_graph_builder(center_entity, satellites, **kwargs):\n",
|
||||
" \"\"\"\n",
|
||||
" Builds a star graph where all satellites connect to the center.\n",
|
||||
" \"\"\"\n",
|
||||
" nodes = []\n",
|
||||
" edges = []\n",
|
||||
"# 1. Define Nodes\n",
|
||||
"entities = [\n",
|
||||
" {\"id\": \"alice\", \"type\": \"PERSON\", \"text\": \"Alice\", \"properties\": {\"role\": \"Admin\"}},\n",
|
||||
" {\"id\": \"project_apollo\", \"type\": \"PROJECT\", \"text\": \"Project Apollo\"},\n",
|
||||
" {\"id\": \"python\", \"type\": \"TECH\", \"text\": \"Python\"},\n",
|
||||
" {\"id\": \"react\", \"type\": \"TECH\", \"text\": \"React\"}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# 2. Define Edges (The Knowledge)\n",
|
||||
"relationships = [\n",
|
||||
" {\"source\": \"alice\", \"target\": \"project_apollo\", \"type\": \"MANAGES\", \"weight\": 1.0},\n",
|
||||
" {\"source\": \"project_apollo\", \"target\": \"python\", \"type\": \"USES_TECH\", \"weight\": 1.0},\n",
|
||||
" {\"source\": \"project_apollo\", \"target\": \"react\", \"type\": \"USES_TECH\", \"weight\": 1.0}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# 3. Inject into Graph\n",
|
||||
"graph_stats = context.build_graph(\n",
|
||||
" entities=entities,\n",
|
||||
" relationships=relationships\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"Manual Graph Build Complete:\", graph_stats)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "bf04b4a0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Visualizing the Graph Logic\n",
|
||||
"Let's query the graph directly to see what \"Project Apollo\" looks like."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "dc61c324",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Helper to print graph neighbors\n",
|
||||
"def inspect_node(node_id):\n",
|
||||
" if hasattr(gs, \"get_neighbors\"):\n",
|
||||
" neighbors = gs.get_neighbors(node_id)\n",
|
||||
" print(f\"\\nNeighbors of '{node_id}':\")\n",
|
||||
" for n in neighbors:\n",
|
||||
" # Handle different return formats between stores\n",
|
||||
" rel_type = n.get('relationship') or n.get('type') or 'linked'\n",
|
||||
" target = n.get('id') or n.get('node_id')\n",
|
||||
" print(f\" └── [{rel_type}] ──> {target}\")\n",
|
||||
" else:\n",
|
||||
" print(\"Graph store does not support neighbor inspection.\")\n",
|
||||
"\n",
|
||||
"inspect_node(\"project_apollo\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a163434b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "51261f5f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 6. Hybrid Retrieval (GraphRAG)\n",
|
||||
"\n",
|
||||
"Now for the magic. We ask a question that requires connecting the dots.\n",
|
||||
"\n",
|
||||
"**Query**: *\"Who is responsible for the Python web framework project?\"*\n",
|
||||
"\n",
|
||||
"**Logic Flow:**\n",
|
||||
"1. **Vector Search**: Finds \"Project Apollo\" (described as web framework).\n",
|
||||
"2. **Graph Expansion**: Looks at \"Project Apollo\" in the graph.\n",
|
||||
"3. **Discovery**: Sees `(Alice)-[MANAGES]->(Project Apollo)`.\n",
|
||||
"4. **Result**: Returns Alice, even though her name wasn't in the project description text!"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "69381e8c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"query = \"Who is responsible for the Python web framework project?\"\n",
|
||||
"print(f\"Asking: '{query}'...\\n\")\n",
|
||||
"\n",
|
||||
"results = context.retrieve(\n",
|
||||
" query,\n",
|
||||
" max_results=3,\n",
|
||||
" use_graph=True, # Vital for finding Alice\n",
|
||||
" expand_graph=True, # Hop to neighbors\n",
|
||||
" include_entities=True # Return structured entity data\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"Retrieved {len(results)} context items:\\n\")\n",
|
||||
"\n",
|
||||
"for i, res in enumerate(results, 1):\n",
|
||||
" print(f\"{i}. [Score: {res['score']:.2f}] {res['content'][:120]}...\")\n",
|
||||
" \n",
|
||||
" # Center node\n",
|
||||
" nodes.append({\"id\": \"center\", \"label\": center_entity, \"type\": \"CENTER\"})\n",
|
||||
" \n",
|
||||
" for i, sat in enumerate(satellites):\n",
|
||||
" sat_id = f\"sat_{i}\"\n",
|
||||
" nodes.append({\"id\": sat_id, \"label\": sat, \"type\": \"SATELLITE\"})\n",
|
||||
" edges.append({\"source\": \"center\", \"target\": sat_id, \"relation\": \"connects_to\"})\n",
|
||||
" \n",
|
||||
" return {\"nodes\": nodes, \"edges\": edges}\n",
|
||||
" # Did we find graph connections?\n",
|
||||
" if 'related_entities' in res and res['related_entities']:\n",
|
||||
" print(\" Graph Insights:\")\n",
|
||||
" for ent in res['related_entities'][:3]:\n",
|
||||
" print(f\" - {ent.get('text', 'Entity')} ({ent.get('type', 'Unknown')})\")\n",
|
||||
" print(\"\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c21fbb00",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c18870af",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 7. Lifecycle Management\n",
|
||||
"\n",
|
||||
"# Register the method\n",
|
||||
"registry.method_registry.register(\"graph\", \"star_builder\", star_graph_builder)\n",
|
||||
"A production system needs maintenance. You can query history, check health, and prune old data.\n",
|
||||
"\n",
|
||||
"# Verify registration\n",
|
||||
"print(\"Available graph methods:\", registry.method_registry.list_all(\"graph\"))\n",
|
||||
"### Conversation History"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0574b1b7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Get recent chat history for context window\n",
|
||||
"history = context.conversation(\n",
|
||||
" conversation_id=session_id,\n",
|
||||
" limit=5\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Use it (conceptual - typically used via build_context_graph wrapper)\n",
|
||||
"graph_data = star_graph_builder(\"Central Hub\", [\"Spoke 1\", \"Spoke 2\"])\n",
|
||||
"print(f\"Created graph with {len(graph_data['nodes'])} nodes and {len(graph_data['edges'])} edges.\")"
|
||||
"print(f\"Chat History for {session_id}:\")\n",
|
||||
"for msg in history:\n",
|
||||
" print(f\" - {msg['content']}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a40483fc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### System Health & Stats"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cd472495",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"stats = context.stats()\n",
|
||||
"print(\"System Vital Signs:\")\n",
|
||||
"print(f\" - Total Memories: {stats.get('total_items', 0)}\")\n",
|
||||
"print(f\" - Graph Nodes: {stats.get('graph_stats', {}).get('node_count', 'N/A')}\")\n",
|
||||
"print(f\" - Graph Edges: {stats.get('graph_stats', {}).get('edge_count', 'N/A')}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Best Practices for Production\n",
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"1. **Token Limits**: Align `token_limit` with your LLM's context window minus the prompt template size.\n",
|
||||
"2. **Vector Store**: Use a production-grade vector store (e.g., Pinecone, Weaviate, Qdrant) instead of the mock store.\n",
|
||||
"3. **Asynchronous Operations**: For high-throughput systems, consider wrapping storage operations in async tasks (though the core logic is synchronous for simplicity).\n",
|
||||
"4. **Entity Resolution**: Implement a robust `EntityLinker` strategy to prevent graph fragmentation (e.g., \"Alice\" vs \"Alice S.\")."
|
||||
"You have successfully built a **Context-Aware Agent** using Semantica's production modules.\n",
|
||||
"\n",
|
||||
"**Key Achievements:**\n",
|
||||
"1. **Persistence**: Swapped in FAISS and Neo4j for real-world storage.\n",
|
||||
"2. **GraphRAG**: Demonstrated how graph relationships improve retrieval accuracy.\n",
|
||||
"3. **Entity Injection**: Manually taught the agent about business relationships.\n",
|
||||
"\n",
|
||||
"This architecture is ready to scale to millions of vectors and graph nodes."
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
@@ -1,286 +1,311 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/12_Unstructured_to_Ontology.ipynb)\n",
|
||||
"\n",
|
||||
"# Advanced: Unstructured Text to Ontology\n",
|
||||
"\n",
|
||||
"Welcome to the advanced guide on extracting structured ontologies from unstructured text. This notebook explores two powerful paradigms available in Semantica:\n",
|
||||
"\n",
|
||||
"1. **Classical NLP Pipeline**: Using Named Entity Recognition (NER) and Relation Extraction.\n",
|
||||
"2. **Generative AI Pipeline**: Using Large Language Models (LLMs) for direct conceptual modeling.\n",
|
||||
"\n",
|
||||
"We will compare both approaches, visualize the results, and validate the generated ontologies.\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/ontology/)\n",
|
||||
"\n",
|
||||
"## Setup and Installation\n",
|
||||
"\n",
|
||||
"Ensure you have Semantica installed with all dependencies."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# !pip install semantica[all]\n",
|
||||
"\n",
|
||||
"from semantica.utils.logging import get_logger\n",
|
||||
"\n",
|
||||
"logger = get_logger(\"unstructured_guide\")\n",
|
||||
"print(\"Environment setup complete.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## The Input Text\n",
|
||||
"\n",
|
||||
"We will use a rich paragraph of text describing a technology company to test both extraction methods."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"text_corpus = \"\"\"\n",
|
||||
"QuantumDynamics is a leading AI research lab founded by Dr. Elena Rostova in 2018. \n",
|
||||
"The lab is headquartered in Zurich, Switzerland, and focuses on quantum computing algorithms. \n",
|
||||
"Dr. Rostova serves as the Chief Scientist. \n",
|
||||
"The lab has released products like the Q-1 Processor and the NeuralBridge SDK. \n",
|
||||
"QuantumDynamics collaborates with major universities such as MIT and ETH Zurich.\n",
|
||||
"\"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Approach 1: The Classical NLP Pipeline\n",
|
||||
"\n",
|
||||
"This approach builds the ontology from the bottom up:\n",
|
||||
"1. **Extract Entities**: Identify nouns/proper nouns (e.g., \"QuantumDynamics\", \"Zurich\").\n",
|
||||
"2. **Extract Relations**: Identify verbs connecting them (e.g., \"headquartered in\").\n",
|
||||
"3. **Generate Ontology**: Map these triplets to Classes and Properties.\n",
|
||||
"\n",
|
||||
"**Pros**: Deterministic, traceable, works offline.\n",
|
||||
"**Cons**: Dependent on the underlying NLP model's vocabulary and flexibility."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.semantic_extract import NERExtractor, RelationExtractor\n",
|
||||
"from semantica.ontology import OntologyGenerator, OntologyOptimizer\n",
|
||||
"\n",
|
||||
"# 1. Initialize Extractors\n",
|
||||
"ner = NERExtractor()\n",
|
||||
"re = RelationExtractor()\n",
|
||||
"\n",
|
||||
"# 2. Extract Entities\n",
|
||||
"print(\"Extracting entities...\")\n",
|
||||
"entities = ner.extract(text_corpus)\n",
|
||||
"print(f\"Found {len(entities)} entities: {[e['text'] for e in entities]}\")\n",
|
||||
"\n",
|
||||
"# 3. Extract Relationships\n",
|
||||
"print(\"Extracting relationships...\")\n",
|
||||
"relationships = re.extract(text_corpus, entities)\n",
|
||||
"for r in relationships:\n",
|
||||
" print(f\" - {r['source']} -> {r['type']} -> {r['target']}\")\n",
|
||||
"\n",
|
||||
"# 4. Generate Structure\n",
|
||||
"generator = OntologyGenerator()\n",
|
||||
"nlp_ontology = generator.generate(entities, relationships, name=\"QuantumOntologyNLP\")\n",
|
||||
"\n",
|
||||
"# 5. Optimize (Clean up)\n",
|
||||
"optimizer = OntologyOptimizer()\n",
|
||||
"nlp_ontology = optimizer.optimize_ontology(nlp_ontology, remove_redundancy=True)\n",
|
||||
"\n",
|
||||
"print(f\"\\nGenerated NLP Ontology with {len(nlp_ontology['classes'])} classes and {len(nlp_ontology['properties'])} properties.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Approach 2: The Generative AI Pipeline (LLM)\n",
|
||||
"\n",
|
||||
"This approach uses a Large Language Model to \"read\" the text and directly propose a schema.\n",
|
||||
"\n",
|
||||
"**Pros**: Context-aware, can handle ambiguity, generates human-like class names.\n",
|
||||
"**Cons**: Non-deterministic, requires API access.\n",
|
||||
"\n",
|
||||
"*Note: This step requires a configured LLM provider (e.g., OpenAI).* "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ontology import LLMOntologyGenerator\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" # Initialize LLM Generator (ensure OPENAI_API_KEY is set in env)\n",
|
||||
" llm_gen = LLMOntologyGenerator(provider=\"openai\", model=\"gpt-4\")\n",
|
||||
" \n",
|
||||
" print(\"Generating ontology with LLM...\")\n",
|
||||
" llm_ontology = llm_gen.generate_ontology_from_text(\n",
|
||||
" text=text_corpus,\n",
|
||||
" name=\"QuantumOntologyLLM\"\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" print(f\"Generated LLM Ontology with {len(llm_ontology['classes'])} classes and {len(llm_ontology['properties'])} properties.\")\n",
|
||||
" print(\"Classes detected:\", [c['name'] for c in llm_ontology['classes']])\n",
|
||||
" \n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Skipping LLM generation: {e}\")\n",
|
||||
" llm_ontology = None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Comparing Results with Visualization\n",
|
||||
"\n",
|
||||
"Let's visualize both ontologies side-by-side (if available) to see the difference in structure. The NLP model tends to be more literal, while the LLM model tends to be more conceptual."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.visualization import OntologyVisualizer\n",
|
||||
"\n",
|
||||
"visualizer = OntologyVisualizer()\n",
|
||||
"\n",
|
||||
"print(\"--- NLP Approach Visualization ---\")\n",
|
||||
"fig_nlp = visualizer.visualize_structure(nlp_ontology, output=\"interactive\")\n",
|
||||
"if fig_nlp: fig_nlp.show()\n",
|
||||
"\n",
|
||||
"if llm_ontology:\n",
|
||||
" print(\"--- LLM Approach Visualization ---\")\n",
|
||||
" fig_llm = visualizer.visualize_structure(llm_ontology, output=\"interactive\")\n",
|
||||
" if fig_llm: fig_llm.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Validation\n",
|
||||
"\n",
|
||||
"No matter the method, validation is crucial. We check for structural integrity and logical consistency."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ontology import OntologyValidator\n",
|
||||
"\n",
|
||||
"validator = OntologyValidator()\n",
|
||||
"\n",
|
||||
"def print_report(name, ont):\n",
|
||||
" if not ont: return\n",
|
||||
" res = validator.validate_ontology(ont)\n",
|
||||
" print(f\"[{name}] Valid: {res.valid}, Errors: {len(res.errors)}\")\n",
|
||||
" if res.metrics:\n",
|
||||
" print(f\" Depth: {res.metrics.get('hierarchy_depth')}, Concepts: {res.metrics.get('class_count')}\")\n",
|
||||
"\n",
|
||||
"print_report(\"Classical NLP\", nlp_ontology)\n",
|
||||
"print_report(\"Generative AI\", llm_ontology)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Export to OWL\n",
|
||||
"\n",
|
||||
"Finally, we choose the best model (or merge them using `ReuseManager`, covered in other guides) and export it."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.export import OWLExporter\n",
|
||||
"\n",
|
||||
"exporter = OWLExporter()\n",
|
||||
"\n",
|
||||
"# Export the NLP ontology by default, or the LLM one if preferred\n",
|
||||
"target_ontology = llm_ontology if llm_ontology else nlp_ontology\n",
|
||||
"\n",
|
||||
"output_file = \"quantum_ontology.ttl\"\n",
|
||||
"exporter.export(target_ontology, output_file, format=\"turtle\")\n",
|
||||
"print(f\"Successfully exported ontology to {output_file}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"You have learned to:\n",
|
||||
"1. **Extract Ontologies Programmatically**: Using `NERExtractor` for reliable, data-driven modeling.\n",
|
||||
"2. **Generate Ontologies with AI**: Using `LLMOntologyGenerator` for conceptual, high-level modeling.\n",
|
||||
"3. **Visualize and Compare**: Using `OntologyVisualizer` to inspect the structural differences.\n",
|
||||
"4. **Validate and Export**: Ensuring quality before saving to OWL standards."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.10"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/12_Unstructured_to_Ontology.ipynb)\n",
|
||||
"\n",
|
||||
"# Unstructured Text to Ontology\n",
|
||||
"\n",
|
||||
"Welcome to the advanced guide on extracting structured ontologies from unstructured text. This notebook explores two powerful paradigms available in Semantica:\n",
|
||||
"\n",
|
||||
"1. **Classical NLP Pipeline**: Using Named Entity Recognition (NER) and Relation Extraction.\n",
|
||||
"2. **Generative AI Pipeline**: Using Large Language Models (LLMs) for direct conceptual modeling.\n",
|
||||
"\n",
|
||||
"We will compare both approaches, visualize the results, and validate the generated ontologies.\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/ontology/)\n",
|
||||
"\n",
|
||||
"## Setup and Installation\n",
|
||||
"\n",
|
||||
"Ensure you have Semantica installed with all dependencies."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9c21e116",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -qU semantica"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"\n",
|
||||
"from semantica.utils.logging import get_logger\n",
|
||||
"\n",
|
||||
"logger = get_logger(\"unstructured_guide\")\n",
|
||||
"print(\"Environment setup complete.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## The Input Text\n",
|
||||
"\n",
|
||||
"We will use a rich paragraph of text describing a technology company to test both extraction methods."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"text_corpus = \"\"\"\n",
|
||||
"QuantumDynamics is a leading AI research lab founded by Dr. Elena Rostova in 2018. \n",
|
||||
"The lab is headquartered in Zurich, Switzerland, and focuses on quantum computing algorithms. \n",
|
||||
"Dr. Rostova serves as the Chief Scientist. \n",
|
||||
"The lab has released products like the Q-1 Processor and the NeuralBridge SDK. \n",
|
||||
"QuantumDynamics collaborates with major universities such as MIT and ETH Zurich.\n",
|
||||
"\"\"\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Approach 1: The Classical NLP Pipeline\n",
|
||||
"\n",
|
||||
"This approach builds the ontology from the bottom up:\n",
|
||||
"1. **Extract Entities**: Identify nouns/proper nouns (e.g., \"QuantumDynamics\", \"Zurich\").\n",
|
||||
"2. **Extract Relations**: Identify verbs connecting them (e.g., \"headquartered in\").\n",
|
||||
"3. **Generate Ontology**: Map these triplets to Classes and Properties.\n",
|
||||
"\n",
|
||||
"**Pros**: Deterministic, traceable, works offline.\n",
|
||||
"**Cons**: Dependent on the underlying NLP model's vocabulary and flexibility."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "75f896b9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.semantic_extract import NERExtractor, RelationExtractor\n",
|
||||
"from semantica.ontology import OntologyGenerator, OntologyOptimizer\n",
|
||||
"\n",
|
||||
"# 1. Initialize Extractors\n",
|
||||
"ner = NERExtractor()\n",
|
||||
"re = RelationExtractor()\n",
|
||||
"\n",
|
||||
"# 2. Extract Entities\n",
|
||||
"print(\"Extracting entities...\")\n",
|
||||
"entities = ner.extract(text_corpus)\n",
|
||||
"\n",
|
||||
"# Note: entities are returned as Entity objects (dataclasses), not dictionaries.\n",
|
||||
"# We access properties using dot notation (e.g., entity.text, entity.label).\n",
|
||||
"print(f\"Found {len(entities)} entities.\")\n",
|
||||
"for e in entities[:5]:\n",
|
||||
" print(f\" - {e.text} ({e.label}) [Conf: {e.confidence}]\")\n",
|
||||
"\n",
|
||||
"# 3. Extract Relationships\n",
|
||||
"print(\"\\nExtracting relationships...\")\n",
|
||||
"relationships = re.extract(text_corpus, entities)\n",
|
||||
"\n",
|
||||
"# Note: relationships are returned as Relation objects.\n",
|
||||
"print(f\"Found {len(relationships)} relationships.\")\n",
|
||||
"for r in relationships:\n",
|
||||
" print(f\" - {r.subject.text} -> {r.predicate} -> {r.object.text}\")\n",
|
||||
"\n",
|
||||
"# 4. Prepare Data for Ontology Generation\n",
|
||||
"# The OntologyGenerator expects dictionaries, so we convert our objects.\n",
|
||||
"# We also ensure we handle both object attributes and potential dictionary keys for robustness.\n",
|
||||
"entities_data = []\n",
|
||||
"for e in entities:\n",
|
||||
" if hasattr(e, 'to_dict'):\n",
|
||||
" entities_data.append(e.to_dict())\n",
|
||||
" else:\n",
|
||||
" # Manual conversion for dataclasses without to_dict\n",
|
||||
" entities_data.append({\n",
|
||||
" \"id\": getattr(e, \"text\", str(e)),\n",
|
||||
" \"text\": getattr(e, \"text\", str(e)),\n",
|
||||
" \"type\": getattr(e, \"label\", getattr(e, \"type\", \"Unknown\")),\n",
|
||||
" \"confidence\": getattr(e, \"confidence\", 1.0)\n",
|
||||
" })\n",
|
||||
"\n",
|
||||
"relationships_data = []\n",
|
||||
"for r in relationships:\n",
|
||||
" if hasattr(r, 'to_dict'):\n",
|
||||
" relationships_data.append(r.to_dict())\n",
|
||||
" else:\n",
|
||||
" # Manual conversion for dataclasses without to_dict\n",
|
||||
" # Handle nested Entity objects in subject/object fields\n",
|
||||
" subj = r.subject\n",
|
||||
" obj = r.object\n",
|
||||
" subj_text = getattr(subj, \"text\", str(subj))\n",
|
||||
" obj_text = getattr(obj, \"text\", str(obj))\n",
|
||||
" \n",
|
||||
" relationships_data.append({\n",
|
||||
" \"source\": subj_text,\n",
|
||||
" \"target\": obj_text,\n",
|
||||
" \"type\": getattr(r, \"predicate\", getattr(r, \"type\", \"related_to\")),\n",
|
||||
" \"confidence\": getattr(r, \"confidence\", 1.0)\n",
|
||||
" })\n",
|
||||
"\n",
|
||||
"# 5. Generate Structure\n",
|
||||
"generator = OntologyGenerator()\n",
|
||||
"nlp_ontology = generator.generate_ontology(\n",
|
||||
" {\"entities\": entities_data, \"relationships\": relationships_data},\n",
|
||||
" name=\"QuantumOntologyNLP\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# 6. Optimize (Clean up)\n",
|
||||
"optimizer = OntologyOptimizer()\n",
|
||||
"nlp_ontology = optimizer.optimize_ontology(nlp_ontology, remove_redundancy=True)\n",
|
||||
"\n",
|
||||
"print(f\"\\nGenerated NLP Ontology with {len(nlp_ontology['classes'])} classes and {len(nlp_ontology['properties'])} properties.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Approach 2: The Generative AI Pipeline (LLM)\n",
|
||||
"\n",
|
||||
"This approach uses a Large Language Model to \"read\" the text and directly propose a schema.\n",
|
||||
"\n",
|
||||
"**Pros**: Context-aware, can handle ambiguity, generates human-like class names.\n",
|
||||
"**Cons**: Non-deterministic, requires API access.\n",
|
||||
"\n",
|
||||
"*Note: This step requires a configured LLM provider (e.g., OpenAI).* "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ontology import LLMOntologyGenerator\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" # Initialize LLM Generator (ensure OPENAI_API_KEY is set in env)\n",
|
||||
" llm_gen = LLMOntologyGenerator(provider=\"openai\", model=\"gpt-4\")\n",
|
||||
" \n",
|
||||
" print(\"Generating ontology with LLM...\")\n",
|
||||
" llm_ontology = llm_gen.generate_ontology_from_text(\n",
|
||||
" text=text_corpus,\n",
|
||||
" name=\"QuantumOntologyLLM\"\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
" print(f\"Generated LLM Ontology with {len(llm_ontology['classes'])} classes and {len(llm_ontology['properties'])} properties.\")\n",
|
||||
" print(\"Classes detected:\", [c['name'] for c in llm_ontology['classes']])\n",
|
||||
" \n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Skipping LLM generation: {e}\")\n",
|
||||
" llm_ontology = None"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Comparing Results with Visualization\n",
|
||||
"\n",
|
||||
"Let's visualize both ontologies side-by-side (if available) to see the difference in structure. The NLP model tends to be more literal, while the LLM model tends to be more conceptual."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.visualization import OntologyVisualizer\n",
|
||||
"\n",
|
||||
"visualizer = OntologyVisualizer()\n",
|
||||
"\n",
|
||||
"print(\"--- NLP Approach Visualization ---\")\n",
|
||||
"fig_nlp = visualizer.visualize_structure(nlp_ontology, output=\"interactive\")\n",
|
||||
"if fig_nlp: fig_nlp.show()\n",
|
||||
"\n",
|
||||
"if llm_ontology:\n",
|
||||
" print(\"--- LLM Approach Visualization ---\")\n",
|
||||
" fig_llm = visualizer.visualize_structure(llm_ontology, output=\"interactive\")\n",
|
||||
" if fig_llm: fig_llm.show()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Export to OWL\n",
|
||||
"\n",
|
||||
"Finally, we choose the best model (or merge them using `ReuseManager`, covered in other guides) and export it."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.export import OWLExporter\n",
|
||||
"\n",
|
||||
"exporter = OWLExporter()\n",
|
||||
"\n",
|
||||
"# Export the NLP ontology by default, or the LLM one if preferred\n",
|
||||
"target_ontology = llm_ontology if llm_ontology else nlp_ontology\n",
|
||||
"\n",
|
||||
"output_file = \"quantum_ontology.ttl\"\n",
|
||||
"exporter.export(target_ontology, output_file, format=\"turtle\")\n",
|
||||
"print(f\"Successfully exported ontology to {output_file}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"You have learned to:\n",
|
||||
"1. **Extract Ontologies Programmatically**: Using `NERExtractor` for reliable, data-driven modeling.\n",
|
||||
"2. **Generate Ontologies with AI**: Using `LLMOntologyGenerator` for conceptual, high-level modeling.\n",
|
||||
"3. **Visualize and Compare**: Using `OntologyVisualizer` to inspect the structural differences.\n",
|
||||
"4. **Validate and Export**: Ensuring quality before saving to OWL standards."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.10"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
|
||||
@@ -1,371 +1,380 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/Advanced_Vector_Store_and_Search.ipynb)\n",
|
||||
"\n",
|
||||
"# Advanced Vector Store - Made Easy\n",
|
||||
"\n",
|
||||
"## What You'll Learn\n",
|
||||
"\n",
|
||||
"This notebook shows you **practical ways** to use vector stores in real applications. Each example is simple and ready to use.\n",
|
||||
"\n",
|
||||
"### Topics\n",
|
||||
"\n",
|
||||
"1. **Choosing the Right Index** - Which one to use and when\n",
|
||||
"2. **Smart Filtering** - Find exactly what you need\n",
|
||||
"3. **Combining Results** - Merge searches from different sources\n",
|
||||
"4. **Organizing Data** - Keep different users' data separate\n",
|
||||
"\n",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 0: Setup Embeddings\n",
|
||||
"\n",
|
||||
"First, let's select our embedding provider and model. Semantica supports multiple providers like Sentence Transformers and FastEmbed.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.embeddings import TextEmbedder\n",
|
||||
"\n",
|
||||
"# Choose provider and model\n",
|
||||
"embedder = TextEmbedder(method=\"fastembed\", model_name=\"BAAI/bge-small-en-v1.5\")\n",
|
||||
"dimension = embedder.get_embedding_dimension()\n",
|
||||
"\n",
|
||||
"print(f\"Selected model: {embedder.get_model_info()['model_name']}\")\n",
|
||||
"print(f\"Embedding dimension: {dimension}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 1: Choosing the Right Index\n",
|
||||
"\n",
|
||||
"Think of an index like choosing a filing system:\n",
|
||||
"- **Flat**: Like a small notebook - slow but perfect\n",
|
||||
"- **HNSW**: Like a well-organized library - fast and accurate\n",
|
||||
"- **IVF**: Like a warehouse with sections - very fast for huge collections\n",
|
||||
"\n",
|
||||
"### Simple Rule\n",
|
||||
"- Less than 10,000 items? Use **Flat**\n",
|
||||
"- Between 10,000 and 1 million? Use **HNSW** ✅ (recommended)\n",
|
||||
"- More than 1 million? Use **IVF**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.vector_store import FAISSAdapter\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# Create some example vectors (like document embeddings)\n",
|
||||
"vectors = np.random.rand(5000, 768).astype('float32')\n",
|
||||
"query = np.random.rand(768).astype('float32')\n",
|
||||
"\n",
|
||||
"adapter = FAISSAdapter(dimension=768)\n",
|
||||
"\n",
|
||||
"# HNSW Index - Best for most cases\n",
|
||||
"index = adapter.create_index(index_type=\"hnsw\", metric=\"L2\", m=16)\n",
|
||||
"adapter.add_vectors(index, vectors, ids=[f\"doc_{i}\" for i in range(len(vectors))])\n",
|
||||
"\n",
|
||||
"# Search for similar vectors\n",
|
||||
"distances, indices = adapter.search(index, query, k=5)\n",
|
||||
"\n",
|
||||
"print(\"Found 5 most similar documents:\")\n",
|
||||
"for i, (dist, idx) in enumerate(zip(distances, indices), 1):\n",
|
||||
" print(f\" {i}. Document {idx} (distance: {dist:.3f})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 2: Smart Filtering with Metadata\n",
|
||||
"\n",
|
||||
"Imagine searching for \"similar articles\" but only from 2024 and only in the \"Technology\" category. That's what metadata filtering does!\n",
|
||||
"\n",
|
||||
"### Real-World Example\n",
|
||||
"You're building a document search where users want:\n",
|
||||
"- Similar documents (vector search)\n",
|
||||
"- From specific categories (metadata filter)\n",
|
||||
"- From recent years (metadata filter)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.vector_store import HybridSearch, MetadataFilter\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# Create sample documents with metadata\n",
|
||||
"documents = [\n",
|
||||
" {\"id\": 0, \"text\": \"AI in Healthcare\", \"category\": \"Technology\", \"year\": 2024},\n",
|
||||
" {\"id\": 1, \"text\": \"Machine Learning Basics\", \"category\": \"Technology\", \"year\": 2023},\n",
|
||||
" {\"id\": 2, \"text\": \"Business Strategy\", \"category\": \"Business\", \"year\": 2024},\n",
|
||||
" {\"id\": 3, \"text\": \"Data Science Guide\", \"category\": \"Technology\", \"year\": 2024},\n",
|
||||
" {\"id\": 4, \"text\": \"Marketing Tips\", \"category\": \"Business\", \"year\": 2023},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Create vectors for each document\n",
|
||||
"vectors = [np.random.rand(768) for _ in documents]\n",
|
||||
"metadata = [{\"category\": d[\"category\"], \"year\": d[\"year\"]} for d in documents]\n",
|
||||
"vector_ids = [f\"doc_{d['id']}\" for d in documents]\n",
|
||||
"\n",
|
||||
"# Create search\n",
|
||||
"search = HybridSearch()\n",
|
||||
"query = np.random.rand(768)\n",
|
||||
"\n",
|
||||
"# Example 1: Find Technology articles from 2024\n",
|
||||
"filter1 = MetadataFilter().eq(\"category\", \"Technology\").eq(\"year\", 2024)\n",
|
||||
"results = search.search(query, vectors, metadata, vector_ids, filter=filter1, k=10)\n",
|
||||
"\n",
|
||||
"print(\"Technology articles from 2024:\")\n",
|
||||
"for r in results:\n",
|
||||
" doc_id = int(r['id'].split('_')[1])\n",
|
||||
" print(f\" - {documents[doc_id]['text']}\")\n",
|
||||
"\n",
|
||||
"# Example 2: Find any article from 2024\n",
|
||||
"filter2 = MetadataFilter().eq(\"year\", 2024)\n",
|
||||
"results2 = search.search(query, vectors, metadata, vector_ids, filter=filter2, k=10)\n",
|
||||
"\n",
|
||||
"print(\"\\nAll articles from 2024:\")\n",
|
||||
"for r in results2:\n",
|
||||
" doc_id = int(r['id'].split('_')[1])\n",
|
||||
" print(f\" - {documents[doc_id]['text']} ({documents[doc_id]['category']})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 3: Combining Search Results\n",
|
||||
"\n",
|
||||
"Sometimes you want to search in multiple places and combine the results. Like searching both your email and documents, then showing the best matches from both.\n",
|
||||
"\n",
|
||||
"### When to Use This\n",
|
||||
"- Searching multiple databases\n",
|
||||
"- Combining different search strategies\n",
|
||||
"- Giving more weight to certain sources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.vector_store import SearchRanker\n",
|
||||
"\n",
|
||||
"# Simulate two different searches\n",
|
||||
"# Search 1: Recent documents\n",
|
||||
"recent_results = [\n",
|
||||
" {\"id\": \"doc_3\", \"score\": 0.95, \"source\": \"recent\"},\n",
|
||||
" {\"id\": \"doc_0\", \"score\": 0.90, \"source\": \"recent\"},\n",
|
||||
" {\"id\": \"doc_2\", \"score\": 0.85, \"source\": \"recent\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Search 2: Popular documents\n",
|
||||
"popular_results = [\n",
|
||||
" {\"id\": \"doc_1\", \"score\": 0.92, \"source\": \"popular\"},\n",
|
||||
" {\"id\": \"doc_3\", \"score\": 0.88, \"source\": \"popular\"},\n",
|
||||
" {\"id\": \"doc_4\", \"score\": 0.80, \"source\": \"popular\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Method 1: Fair combination (RRF)\n",
|
||||
"ranker = SearchRanker(strategy=\"reciprocal_rank_fusion\")\n",
|
||||
"combined = ranker.rank([recent_results, popular_results])\n",
|
||||
"\n",
|
||||
"print(\"Combined results (fair ranking):\")\n",
|
||||
"for i, result in enumerate(combined[:3], 1):\n",
|
||||
" doc_id = int(result['id'].split('_')[1])\n",
|
||||
" print(f\" {i}. {documents[doc_id]['text']} (score: {result['score']:.3f})\")\n",
|
||||
"\n",
|
||||
"# Method 2: Prefer recent documents (70% recent, 30% popular)\n",
|
||||
"weighted_ranker = SearchRanker(strategy=\"weighted_average\")\n",
|
||||
"weighted_combined = weighted_ranker.rank(\n",
|
||||
" [recent_results, popular_results],\n",
|
||||
" weights=[0.7, 0.3]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"\\nCombined results (prefer recent):\")\n",
|
||||
"for i, result in enumerate(weighted_combined[:3], 1):\n",
|
||||
" doc_id = int(result['id'].split('_')[1])\n",
|
||||
" print(f\" {i}. {documents[doc_id]['text']} (score: {result['score']:.3f})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 4: Keeping User Data Separate\n",
|
||||
"\n",
|
||||
"If you're building an app with multiple users or companies, you need to keep their data separate. Namespaces do this automatically.\n",
|
||||
"\n",
|
||||
"### Real Example\n",
|
||||
"You're building a SaaS app where:\n",
|
||||
"- Company A has their documents\n",
|
||||
"- Company B has their documents\n",
|
||||
"- They should never see each other's data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.vector_store import NamespaceManager\n",
|
||||
"\n",
|
||||
"# Create manager\n",
|
||||
"manager = NamespaceManager()\n",
|
||||
"\n",
|
||||
"# Create separate spaces for each company\n",
|
||||
"company_a = manager.create_namespace(\"company_a\", \"Company A's documents\")\n",
|
||||
"company_b = manager.create_namespace(\"company_b\", \"Company B's documents\")\n",
|
||||
"\n",
|
||||
"# Add documents to Company A\n",
|
||||
"for i in range(10):\n",
|
||||
" manager.add_vector_to_namespace(f\"company_a_doc_{i}\", \"company_a\")\n",
|
||||
"\n",
|
||||
"# Add documents to Company B\n",
|
||||
"for i in range(15):\n",
|
||||
" manager.add_vector_to_namespace(f\"company_b_doc_{i}\", \"company_b\")\n",
|
||||
"\n",
|
||||
"# Get each company's documents\n",
|
||||
"a_docs = manager.get_namespace_vectors(\"company_a\")\n",
|
||||
"b_docs = manager.get_namespace_vectors(\"company_b\")\n",
|
||||
"\n",
|
||||
"print(f\"Company A has {len(a_docs)} documents\")\n",
|
||||
"print(f\"Company B has {len(b_docs)} documents\")\n",
|
||||
"\n",
|
||||
"# Set permissions (who can access what)\n",
|
||||
"company_a.set_access_control(\"admin@companya.com\", [\"read\", \"write\", \"delete\"])\n",
|
||||
"company_a.set_access_control(\"user@companya.com\", [\"read\"]) # Read-only\n",
|
||||
"\n",
|
||||
"# Check permissions\n",
|
||||
"print(f\"\\nAdmin can delete: {company_a.has_permission('admin@companya.com', 'delete')}\")\n",
|
||||
"print(f\"User can delete: {company_a.has_permission('user@companya.com', 'delete')}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Quick Reference Guide\n",
|
||||
"\n",
|
||||
"### Which Index Should I Use?\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# Small dataset (< 10,000 items)\n",
|
||||
"index = adapter.create_index(index_type=\"flat\", metric=\"L2\")\n",
|
||||
"\n",
|
||||
"# Medium dataset (10,000 - 1,000,000 items) ✅ RECOMMENDED\n",
|
||||
"index = adapter.create_index(index_type=\"hnsw\", metric=\"L2\", m=16)\n",
|
||||
"\n",
|
||||
"# Large dataset (> 1,000,000 items)\n",
|
||||
"index = adapter.create_index(index_type=\"ivf\", metric=\"L2\", nlist=100)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### How Do I Filter Results?\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# Single condition\n",
|
||||
"filter = MetadataFilter().eq(\"category\", \"Technology\")\n",
|
||||
"\n",
|
||||
"# Multiple conditions (AND)\n",
|
||||
"filter = MetadataFilter() \\\n",
|
||||
" .eq(\"category\", \"Technology\") \\\n",
|
||||
" .eq(\"year\", 2024)\n",
|
||||
"\n",
|
||||
"# Greater than / Less than\n",
|
||||
"filter = MetadataFilter().gt(\"year\", 2020)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### How Do I Combine Results?\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# Fair combination\n",
|
||||
"ranker = SearchRanker(strategy=\"reciprocal_rank_fusion\")\n",
|
||||
"combined = ranker.rank([results1, results2])\n",
|
||||
"\n",
|
||||
"# Weighted combination (prefer first source)\n",
|
||||
"ranker = SearchRanker(strategy=\"weighted_average\")\n",
|
||||
"combined = ranker.rank([results1, results2], weights=[0.7, 0.3])\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### How Do I Separate User Data?\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# Create namespace for each user/company\n",
|
||||
"manager = NamespaceManager()\n",
|
||||
"user_space = manager.create_namespace(\"user_123\", \"User 123's data\")\n",
|
||||
"\n",
|
||||
"# Add data to namespace\n",
|
||||
"manager.add_vector_to_namespace(\"doc_1\", \"user_123\")\n",
|
||||
"\n",
|
||||
"# Get user's data\n",
|
||||
"user_docs = manager.get_namespace_vectors(\"user_123\")\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"You've learned:\n",
|
||||
"\n",
|
||||
"1. ✅ **Index Selection**: Use HNSW for most cases\n",
|
||||
"2. ✅ **Smart Filtering**: Combine vector search with metadata\n",
|
||||
"3. ✅ **Result Fusion**: Merge searches from different sources\n",
|
||||
"4. ✅ **Data Isolation**: Keep users' data separate\n",
|
||||
"\n",
|
||||
"### Next Steps\n",
|
||||
"\n",
|
||||
"- Try these examples with your own data\n",
|
||||
"- Experiment with different filters\n",
|
||||
"- Build a multi-user application\n",
|
||||
"- Explore the [introduction notebook](../introduction/13_Vector_Store.ipynb) for more basics\n",
|
||||
"\n",
|
||||
"**Need Help?** Check our [documentation](https://semantica.readthedocs.io) or ask on [GitHub](https://github.com/Hawksight-AI/semantica)."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/advanced/Advanced_Vector_Store_and_Search.ipynb)\n",
|
||||
"\n",
|
||||
"# Advanced Vector Store - Made Easy\n",
|
||||
"\n",
|
||||
"## What You'll Learn\n",
|
||||
"\n",
|
||||
"This notebook shows you **practical ways** to use vector stores in real applications. Each example is simple and ready to use.\n",
|
||||
"\n",
|
||||
"### Topics\n",
|
||||
"\n",
|
||||
"1. **Choosing the Right Index** - Which one to use and when\n",
|
||||
"2. **Smart Filtering** - Find exactly what you need\n",
|
||||
"3. **Combining Results** - Merge searches from different sources\n",
|
||||
"4. **Organizing Data** - Keep different users' data separate\n",
|
||||
"\n",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 0: Setup Embeddings\n",
|
||||
"\n",
|
||||
"First, let's select our embedding provider and model. Semantica supports multiple providers like Sentence Transformers and FastEmbed.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.embeddings import TextEmbedder\n",
|
||||
"\n",
|
||||
"# Choose provider and model\n",
|
||||
"embedder = TextEmbedder(method=\"fastembed\", model_name=\"BAAI/bge-small-en-v1.5\")\n",
|
||||
"dimension = embedder.get_embedding_dimension()\n",
|
||||
"\n",
|
||||
"print(f\"Selected model: {embedder.get_model_info()['model_name']}\")\n",
|
||||
"print(f\"Embedding dimension: {dimension}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 1: Choosing the Right Index\n",
|
||||
"\n",
|
||||
"Think of an index like choosing a filing system:\n",
|
||||
"- **Flat**: Like a small notebook - slow but perfect\n",
|
||||
"- **HNSW**: Like a well-organized library - fast and accurate\n",
|
||||
"- **IVF**: Like a warehouse with sections - very fast for huge collections\n",
|
||||
"\n",
|
||||
"### Simple Rule\n",
|
||||
"- Less than 10,000 items? Use **Flat**\n",
|
||||
"- Between 10,000 and 1 million? Use **HNSW** ✅ (recommended)\n",
|
||||
"- More than 1 million? Use **IVF**"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.vector_store import FAISSStore\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# Create some example vectors (like document embeddings)\n",
|
||||
"vectors = np.random.rand(5000, 768).astype('float32')\n",
|
||||
"query = np.random.rand(768).astype('float32')\n",
|
||||
"\n",
|
||||
"adapter = FAISSStore(dimension=768)\n",
|
||||
"\n",
|
||||
"# HNSW Index - Best for most cases\n",
|
||||
"index = adapter.create_index(index_type=\"hnsw\", metric=\"L2\", m=16)\n",
|
||||
"adapter.add_vectors(vectors, ids=[f\"doc_{i}\" for i in range(len(vectors))])\n",
|
||||
"\n",
|
||||
"# Search for similar vectors\n",
|
||||
"results = adapter.search_similar(query, k=5)\n",
|
||||
"\n",
|
||||
"print(\"Found 5 most similar documents:\")\n",
|
||||
"for i, result in enumerate(results, 1):\n",
|
||||
" print(f\" {i}. Document {result['id']} (distance: {result['distance']:.3f})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 2: Smart Filtering with Metadata\n",
|
||||
"\n",
|
||||
"Imagine searching for \"similar articles\" but only from 2024 and only in the \"Technology\" category. That's what metadata filtering does!\n",
|
||||
"\n",
|
||||
"### Real-World Example\n",
|
||||
"You're building a document search where users want:\n",
|
||||
"- Similar documents (vector search)\n",
|
||||
"- From specific categories (metadata filter)\n",
|
||||
"- From recent years (metadata filter)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.vector_store import HybridSearch, MetadataFilter\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"# Create sample documents with metadata\n",
|
||||
"documents = [\n",
|
||||
" {\"id\": 0, \"text\": \"AI in Healthcare\", \"category\": \"Technology\", \"year\": 2024},\n",
|
||||
" {\"id\": 1, \"text\": \"Machine Learning Basics\", \"category\": \"Technology\", \"year\": 2023},\n",
|
||||
" {\"id\": 2, \"text\": \"Business Strategy\", \"category\": \"Business\", \"year\": 2024},\n",
|
||||
" {\"id\": 3, \"text\": \"Data Science Guide\", \"category\": \"Technology\", \"year\": 2024},\n",
|
||||
" {\"id\": 4, \"text\": \"Marketing Tips\", \"category\": \"Business\", \"year\": 2023},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Create vectors for each document\n",
|
||||
"vectors = [np.random.rand(768) for _ in documents]\n",
|
||||
"metadata = [{\"category\": d[\"category\"], \"year\": d[\"year\"]} for d in documents]\n",
|
||||
"vector_ids = [f\"doc_{d['id']}\" for d in documents]\n",
|
||||
"\n",
|
||||
"# Create search\n",
|
||||
"search = HybridSearch()\n",
|
||||
"query = np.random.rand(768)\n",
|
||||
"\n",
|
||||
"# Example 1: Find Technology articles from 2024\n",
|
||||
"filter1 = MetadataFilter().eq(\"category\", \"Technology\").eq(\"year\", 2024)\n",
|
||||
"results = search.search(query, vectors, metadata, vector_ids, filter=filter1, k=10)\n",
|
||||
"\n",
|
||||
"print(\"Technology articles from 2024:\")\n",
|
||||
"for r in results:\n",
|
||||
" doc_id = int(r['id'].split('_')[1])\n",
|
||||
" print(f\" - {documents[doc_id]['text']}\")\n",
|
||||
"\n",
|
||||
"# Example 2: Find any article from 2024\n",
|
||||
"filter2 = MetadataFilter().eq(\"year\", 2024)\n",
|
||||
"results2 = search.search(query, vectors, metadata, vector_ids, filter=filter2, k=10)\n",
|
||||
"\n",
|
||||
"print(\"\\nAll articles from 2024:\")\n",
|
||||
"for r in results2:\n",
|
||||
" doc_id = int(r['id'].split('_')[1])\n",
|
||||
" print(f\" - {documents[doc_id]['text']} ({documents[doc_id]['category']})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 3: Combining Search Results\n",
|
||||
"\n",
|
||||
"Sometimes you want to search in multiple places and combine the results. Like searching both your email and documents, then showing the best matches from both.\n",
|
||||
"\n",
|
||||
"### When to Use This\n",
|
||||
"- Searching multiple databases\n",
|
||||
"- Combining different search strategies\n",
|
||||
"- Giving more weight to certain sources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.vector_store import SearchRanker\n",
|
||||
"\n",
|
||||
"# Simulate two different searches\n",
|
||||
"# Search 1: Recent documents\n",
|
||||
"recent_results = [\n",
|
||||
" {\"id\": \"doc_3\", \"score\": 0.95, \"source\": \"recent\"},\n",
|
||||
" {\"id\": \"doc_0\", \"score\": 0.90, \"source\": \"recent\"},\n",
|
||||
" {\"id\": \"doc_2\", \"score\": 0.85, \"source\": \"recent\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Search 2: Popular documents\n",
|
||||
"popular_results = [\n",
|
||||
" {\"id\": \"doc_1\", \"score\": 0.92, \"source\": \"popular\"},\n",
|
||||
" {\"id\": \"doc_3\", \"score\": 0.88, \"source\": \"popular\"},\n",
|
||||
" {\"id\": \"doc_4\", \"score\": 0.80, \"source\": \"popular\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Method 1: Fair combination (RRF)\n",
|
||||
"ranker = SearchRanker(strategy=\"reciprocal_rank_fusion\")\n",
|
||||
"combined = ranker.rank([recent_results, popular_results])\n",
|
||||
"\n",
|
||||
"print(\"Combined results (fair ranking):\")\n",
|
||||
"for i, result in enumerate(combined[:3], 1):\n",
|
||||
" doc_id = int(result['id'].split('_')[1])\n",
|
||||
" print(f\" {i}. {documents[doc_id]['text']} (score: {result['score']:.3f})\")\n",
|
||||
"\n",
|
||||
"# Method 2: Prefer recent documents (70% recent, 30% popular)\n",
|
||||
"weighted_ranker = SearchRanker(strategy=\"weighted_average\")\n",
|
||||
"weighted_combined = weighted_ranker.rank(\n",
|
||||
" [recent_results, popular_results],\n",
|
||||
" weights=[0.7, 0.3]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"\\nCombined results (prefer recent):\")\n",
|
||||
"for i, result in enumerate(weighted_combined[:3], 1):\n",
|
||||
" doc_id = int(result['id'].split('_')[1])\n",
|
||||
" print(f\" {i}. {documents[doc_id]['text']} (score: {result['score']:.3f})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 4: Keeping User Data Separate\n",
|
||||
"\n",
|
||||
"If you're building an app with multiple users or companies, you need to keep their data separate. Namespaces do this automatically.\n",
|
||||
"\n",
|
||||
"### Real Example\n",
|
||||
"You're building a SaaS app where:\n",
|
||||
"- Company A has their documents\n",
|
||||
"- Company B has their documents\n",
|
||||
"- They should never see each other's data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.vector_store import NamespaceManager\n",
|
||||
"\n",
|
||||
"# Create manager\n",
|
||||
"manager = NamespaceManager()\n",
|
||||
"\n",
|
||||
"# Create separate spaces for each company\n",
|
||||
"company_a = manager.create_namespace(\"company_a\", \"Company A's documents\")\n",
|
||||
"company_b = manager.create_namespace(\"company_b\", \"Company B's documents\")\n",
|
||||
"\n",
|
||||
"# Add documents to Company A\n",
|
||||
"for i in range(10):\n",
|
||||
" manager.add_vector_to_namespace(f\"company_a_doc_{i}\", \"company_a\")\n",
|
||||
"\n",
|
||||
"# Add documents to Company B\n",
|
||||
"for i in range(15):\n",
|
||||
" manager.add_vector_to_namespace(f\"company_b_doc_{i}\", \"company_b\")\n",
|
||||
"\n",
|
||||
"# Get each company's documents\n",
|
||||
"a_docs = manager.get_namespace_vectors(\"company_a\")\n",
|
||||
"b_docs = manager.get_namespace_vectors(\"company_b\")\n",
|
||||
"\n",
|
||||
"print(f\"Company A has {len(a_docs)} documents\")\n",
|
||||
"print(f\"Company B has {len(b_docs)} documents\")\n",
|
||||
"\n",
|
||||
"# Set permissions (who can access what)\n",
|
||||
"company_a.set_access_control(\"admin@companya.com\", [\"read\", \"write\", \"delete\"])\n",
|
||||
"company_a.set_access_control(\"user@companya.com\", [\"read\"]) # Read-only\n",
|
||||
"\n",
|
||||
"# Check permissions\n",
|
||||
"print(f\"\\nAdmin can delete: {company_a.has_permission('admin@companya.com', 'delete')}\")\n",
|
||||
"print(f\"User can delete: {company_a.has_permission('user@companya.com', 'delete')}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Quick Reference Guide\n",
|
||||
"\n",
|
||||
"### Which Index Should I Use?\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# Small dataset (< 10,000 items)\n",
|
||||
"index = adapter.create_index(index_type=\"flat\", metric=\"L2\")\n",
|
||||
"\n",
|
||||
"# Medium dataset (10,000 - 1,000,000 items) ✅ RECOMMENDED\n",
|
||||
"index = adapter.create_index(index_type=\"hnsw\", metric=\"L2\", m=16)\n",
|
||||
"\n",
|
||||
"# Large dataset (> 1,000,000 items)\n",
|
||||
"index = adapter.create_index(index_type=\"ivf\", metric=\"L2\", nlist=100)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### How Do I Filter Results?\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# Single condition\n",
|
||||
"filter = MetadataFilter().eq(\"category\", \"Technology\")\n",
|
||||
"\n",
|
||||
"# Multiple conditions (AND)\n",
|
||||
"filter = MetadataFilter() \\\n",
|
||||
" .eq(\"category\", \"Technology\") \\\n",
|
||||
" .eq(\"year\", 2024)\n",
|
||||
"\n",
|
||||
"# Greater than / Less than\n",
|
||||
"filter = MetadataFilter().gt(\"year\", 2020)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### How Do I Combine Results?\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# Fair combination\n",
|
||||
"ranker = SearchRanker(strategy=\"reciprocal_rank_fusion\")\n",
|
||||
"combined = ranker.rank([results1, results2])\n",
|
||||
"\n",
|
||||
"# Weighted combination (prefer first source)\n",
|
||||
"ranker = SearchRanker(strategy=\"weighted_average\")\n",
|
||||
"combined = ranker.rank([results1, results2], weights=[0.7, 0.3])\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### How Do I Separate User Data?\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# Create namespace for each user/company\n",
|
||||
"manager = NamespaceManager()\n",
|
||||
"user_space = manager.create_namespace(\"user_123\", \"User 123's data\")\n",
|
||||
"\n",
|
||||
"# Add data to namespace\n",
|
||||
"manager.add_vector_to_namespace(\"doc_1\", \"user_123\")\n",
|
||||
"\n",
|
||||
"# Get user's data\n",
|
||||
"user_docs = manager.get_namespace_vectors(\"user_123\")\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"You've learned:\n",
|
||||
"\n",
|
||||
"1. ✅ **Index Selection**: Use HNSW for most cases\n",
|
||||
"2. ✅ **Smart Filtering**: Combine vector search with metadata\n",
|
||||
"3. ✅ **Result Fusion**: Merge searches from different sources\n",
|
||||
"4. ✅ **Data Isolation**: Keep users' data separate\n",
|
||||
"\n",
|
||||
"### Next Steps\n",
|
||||
"\n",
|
||||
"- Try these examples with your own data\n",
|
||||
"- Experiment with different filters\n",
|
||||
"- Build a multi-user application\n",
|
||||
"- Explore the [introduction notebook](../introduction/13_Vector_Store.ipynb) for more basics\n",
|
||||
"\n",
|
||||
"**Need Help?** Check our [documentation](https://semantica.readthedocs.io) or ask on [GitHub](https://github.com/Hawksight-AI/semantica)."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<e1> a <Person> ;
|
||||
semantica:text "" ;
|
||||
semantica:confidence 1.0 .
|
||||
|
||||
<e2> a <Person> ;
|
||||
semantica:text "" ;
|
||||
semantica:confidence 1.0 .
|
||||
|
||||
<e3> a <Organization> ;
|
||||
semantica:text "" ;
|
||||
semantica:confidence 1.0 .
|
||||
|
||||
<e4> a <Project> ;
|
||||
semantica:text "" ;
|
||||
semantica:confidence 1.0 .
|
||||
|
||||
<e1> <reports_to> <e2> .
|
||||
<e1> <works_for> <e3> .
|
||||
<e2> <works_for> <e3> .
|
||||
<e1> <works_on> <e4> .
|
||||
@@ -0,0 +1,21 @@
|
||||
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
||||
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
||||
@prefix ont: <https://semantica.dev/ontology/> .
|
||||
|
||||
<https://semantica.dev/ontology/> a owl:Ontology ;
|
||||
rdfs:label "QuantumOntologyNLP" ;
|
||||
owl:versionInfo "1.0" .
|
||||
|
||||
<> a owl:Class ;
|
||||
rdfs:label "Org" .
|
||||
rdfs:comment "Class representing org entities" .
|
||||
|
||||
<> a owl:Class ;
|
||||
rdfs:label "Person" .
|
||||
rdfs:comment "Class representing person entities" .
|
||||
|
||||
<> a owl:Class ;
|
||||
rdfs:label "Gpe" .
|
||||
rdfs:comment "Class representing gpe entities" .
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,430 +1,515 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/introduction/02_Data_Ingestion.ipynb)\n",
|
||||
"\n",
|
||||
"# Data Ingestion - Comprehensive Guide\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook provides a comprehensive guide to Semantica's data ingestion capabilities. It covers all submodules, classes, and helper functions available in the `semantica.ingest` module.\n",
|
||||
"\n",
|
||||
"**Documentation**: [Ingest API Reference](https://semantica.readthedocs.io/reference/ingest/)\n",
|
||||
"\n",
|
||||
"### Table of Contents\n",
|
||||
"\n",
|
||||
"1. **Unified Ingestion**: `ingest` function\n",
|
||||
"2. **File Ingestion**: `FileIngestor`, `FileTypeDetector`, `CloudStorageIngestor`\n",
|
||||
"3. **Web Ingestion**: `WebIngestor`, `ContentExtractor`, `SitemapCrawler`, `RobotsChecker`\n",
|
||||
"4. **Feed Ingestion**: `FeedIngestor`, `FeedMonitor`\n",
|
||||
"5. **Stream Ingestion**: `StreamIngestor`, `StreamMonitor`\n",
|
||||
"6. **Repository Ingestion**: `RepoIngestor`, `CodeExtractor`, `GitAnalyzer`\n",
|
||||
"7. **Email Ingestion**: `EmailIngestor`, `AttachmentProcessor`\n",
|
||||
"8. **Database Ingestion**: `DBIngestor`, `DatabaseConnector`\n",
|
||||
"9. **MCP Ingestion**: `MCPIngestor`\n",
|
||||
"10. **Configuration**: `IngestConfig`\n",
|
||||
"\n",
|
||||
"## Installation\n",
|
||||
"\n",
|
||||
"Install Semantica with all dependencies:\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"pip install semantica[all]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## 1. Unified Ingestion\n",
|
||||
"\n",
|
||||
"The `ingest` function is the main entry point for quick data loading. It automatically detects the source type.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import ingest\n",
|
||||
"import tempfile\n",
|
||||
"import os\n",
|
||||
"import json\n",
|
||||
"\n",
|
||||
"# Setup temporary directory for examples\n",
|
||||
"temp_dir = tempfile.mkdtemp()\n",
|
||||
"sample_file = os.path.join(temp_dir, \"sample.txt\")\n",
|
||||
"with open(sample_file, 'w') as f:\n",
|
||||
" f.write(\"Semantica Unified Ingestion Example\")\n",
|
||||
"\n",
|
||||
"# Auto-detect file source\n",
|
||||
"result = ingest(sample_file)\n",
|
||||
"print(f\"Ingested: {result.name} (Type: {result.file_type})\")\n",
|
||||
"\n",
|
||||
"# Explicit source type\n",
|
||||
"result_explicit = ingest(sample_file, source_type=\"file\")\n",
|
||||
"print(f\"Explicit Ingest: {result_explicit.name}\")\n",
|
||||
"\n",
|
||||
"# Ingest web URL (auto-detected)\n",
|
||||
"# Note: This will fail if no internet connection\n",
|
||||
"try:\n",
|
||||
" result_web = ingest(\"https://example.com\")\n",
|
||||
" print(f\"Ingested Web: {result_web.title}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Web ingestion skipped: {e}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. File Ingestion\n",
|
||||
"\n",
|
||||
"Detailed control over file processing using `FileIngestor` and helper classes.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import FileIngestor, FileTypeDetector, CloudStorageIngestor\n",
|
||||
"\n",
|
||||
"# --- FileTypeDetector ---\n",
|
||||
"detector = FileTypeDetector()\n",
|
||||
"detected_type = detector.detect_type(sample_file)\n",
|
||||
"print(f\"Detected Type: {detected_type}\")\n",
|
||||
"\n",
|
||||
"# --- FileIngestor ---\n",
|
||||
"file_ingestor = FileIngestor()\n",
|
||||
"\n",
|
||||
"# Ingest Directory\n",
|
||||
"subdir = os.path.join(temp_dir, \"docs\")\n",
|
||||
"os.makedirs(subdir, exist_ok=True)\n",
|
||||
"with open(os.path.join(subdir, \"note.md\"), 'w') as f:\n",
|
||||
" f.write(\"# Note\\nThis is a markdown file.\")\n",
|
||||
"\n",
|
||||
"files = file_ingestor.ingest_directory(temp_dir, recursive=True)\n",
|
||||
"print(f\"Ingested {len(files)} files from directory\")\n",
|
||||
"\n",
|
||||
"# --- CloudStorageIngestor (Mock Config) ---\n",
|
||||
"s3_config = {\n",
|
||||
" \"aws_access_key_id\": \"mock_key\",\n",
|
||||
" \"aws_secret_access_key\": \"mock_secret\",\n",
|
||||
" \"region_name\": \"us-east-1\"\n",
|
||||
"}\n",
|
||||
"cloud_ingestor = CloudStorageIngestor(provider=\"s3\", **s3_config)\n",
|
||||
"\n",
|
||||
"# Example call (will raise error without real credentials)\n",
|
||||
"try:\n",
|
||||
" result = cloud_ingestor.ingest(\"s3://my-bucket/data.csv\")\n",
|
||||
" print(f\"Cloud Ingest: {result.name}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Cloud ingestion skipped (Mock Config): {e}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Web Ingestion\n",
|
||||
"\n",
|
||||
"Scraping and crawling with `WebIngestor`, `ContentExtractor`, and `SitemapCrawler`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import WebIngestor, ContentExtractor, SitemapCrawler, RobotsChecker\n",
|
||||
"\n",
|
||||
"# --- ContentExtractor ---\n",
|
||||
"extractor = ContentExtractor()\n",
|
||||
"html_content = \"<html><body><h1>Hello World</h1><p>This is a test.</p><a href='/link'>Link</a></body></html>\"\n",
|
||||
"text = extractor.extract_text(html_content)\n",
|
||||
"links = extractor.extract_links(html_content, base_url=\"https://example.com\")\n",
|
||||
"print(f\"Extracted Text: {text}\")\n",
|
||||
"print(f\"Extracted Links: {links}\")\n",
|
||||
"\n",
|
||||
"# --- RobotsChecker ---\n",
|
||||
"checker = RobotsChecker()\n",
|
||||
"can_fetch = checker.can_fetch(\"https://www.google.com/search\", \"MyBot\")\n",
|
||||
"print(f\"Can fetch google search? {can_fetch}\")\n",
|
||||
"\n",
|
||||
"# --- WebIngestor ---\n",
|
||||
"web_ingestor = WebIngestor(delay=1.0)\n",
|
||||
"try:\n",
|
||||
" web_content = web_ingestor.ingest_url(\"https://example.com\")\n",
|
||||
" print(f\"Web Content Title: {web_content.title}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Web ingest failed: {e}\")\n",
|
||||
"\n",
|
||||
"# --- SitemapCrawler ---\n",
|
||||
"crawler = SitemapCrawler()\n",
|
||||
"try:\n",
|
||||
" urls = crawler.parse_sitemap(\"https://www.google.com/sitemap.xml\")\n",
|
||||
" print(f\"Found {len(urls)} URLs in sitemap\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Sitemap crawl failed: {e}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Feed Ingestion\n",
|
||||
"\n",
|
||||
"Consuming RSS/Atom feeds with `FeedIngestor` and monitoring with `FeedMonitor`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import FeedIngestor, FeedMonitor\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"# --- FeedIngestor ---\n",
|
||||
"feed_ingestor = FeedIngestor()\n",
|
||||
"try:\n",
|
||||
" feed_data = feed_ingestor.ingest_feed(\"https://feeds.feedburner.com/oreilly/radar\")\n",
|
||||
" print(f\"Feed Title: {feed_data.title}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Feed ingest failed: {e}\")\n",
|
||||
"\n",
|
||||
"# --- FeedMonitor ---\n",
|
||||
"def feed_callback(feed_data):\n",
|
||||
" print(f\"Feed Updated: {feed_data.title} with {len(feed_data.items)} items\")\n",
|
||||
"\n",
|
||||
"monitor = FeedMonitor(check_interval=5)\n",
|
||||
"try:\n",
|
||||
" monitor.monitor(\"https://feeds.feedburner.com/oreilly/radar\", callback=feed_callback)\n",
|
||||
" time.sleep(2) # Let it run briefly\n",
|
||||
" monitor.stop()\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Feed monitor failed: {e}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Stream Ingestion\n",
|
||||
"\n",
|
||||
"Real-time processing with `StreamIngestor` and `StreamMonitor`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import StreamIngestor, StreamMonitor\n",
|
||||
"\n",
|
||||
"stream_ingestor = StreamIngestor()\n",
|
||||
"\n",
|
||||
"# --- Kafka Processor ---\n",
|
||||
"kafka_config = {\"bootstrap_servers\": [\"localhost:9092\"]}\n",
|
||||
"kafka_processor = stream_ingestor.ingest_kafka(\"my-topic\", **kafka_config)\n",
|
||||
"\n",
|
||||
"# --- RabbitMQ Processor ---\n",
|
||||
"rabbitmq_processor = stream_ingestor.ingest_rabbitmq(\"my-queue\", \"amqp://guest:guest@localhost:5672/\")\n",
|
||||
"\n",
|
||||
"# --- Stream Monitor ---\n",
|
||||
"monitor = stream_ingestor.monitor\n",
|
||||
"health = monitor.check_health()\n",
|
||||
"print(f\"Stream Health: {health['overall']}\")\n",
|
||||
"print(f\"Processors: {list(health['processors'].keys())}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 6. Repository Ingestion\n",
|
||||
"\n",
|
||||
"Analyzing codebases with `RepoIngestor`, `CodeExtractor`, and `GitAnalyzer`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import RepoIngestor, CodeExtractor, GitAnalyzer\n",
|
||||
"\n",
|
||||
"# --- CodeExtractor ---\n",
|
||||
"code_extractor = CodeExtractor()\n",
|
||||
"py_code = \"class MyClass:\\n def my_method(self):\\n pass\"\n",
|
||||
"structure = code_extractor.extract_structure(py_code, language=\"python\")\n",
|
||||
"print(f\"Classes: {structure.get('classes')}\")\n",
|
||||
"print(f\"Functions: {structure.get('functions')}\")\n",
|
||||
"\n",
|
||||
"# --- RepoIngestor ---\n",
|
||||
"repo_ingestor = RepoIngestor()\n",
|
||||
"try:\n",
|
||||
" repo_data = repo_ingestor.ingest_repository(\"https://github.com/Hawksight-AI/semantica.git\")\n",
|
||||
" print(f\"Repo Name: {repo_data['name']}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Repo ingest failed: {e}\")\n",
|
||||
"\n",
|
||||
"# --- GitAnalyzer ---\n",
|
||||
"try:\n",
|
||||
" analyzer = GitAnalyzer(\".\")\n",
|
||||
" stats = analyzer.get_statistics()\n",
|
||||
" print(f\"Commits in current repo: {stats.get('total_commits', 'N/A')}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Git analysis failed: {e}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 7. Email Ingestion\n",
|
||||
"\n",
|
||||
"Processing emails with `EmailIngestor` and `AttachmentProcessor`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import EmailIngestor, AttachmentProcessor\n",
|
||||
"\n",
|
||||
"# --- AttachmentProcessor ---\n",
|
||||
"att_processor = AttachmentProcessor()\n",
|
||||
"dummy_content = b\"PDF Content\"\n",
|
||||
"saved_path = att_processor.save_attachment(dummy_content, \"doc.pdf\", temp_dir)\n",
|
||||
"print(f\"Saved attachment to: {saved_path}\")\n",
|
||||
"\n",
|
||||
"# --- EmailIngestor ---\n",
|
||||
"email_ingestor = EmailIngestor()\n",
|
||||
"try:\n",
|
||||
" email_ingestor.connect_imap(\"imap.gmail.com\", \"user\", \"pass\")\n",
|
||||
" emails = email_ingestor.ingest_mailbox(\"INBOX\", max_emails=5)\n",
|
||||
" print(f\"Fetched {len(emails)} emails\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Email ingest failed (Auth required): {e}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 8. Database Ingestion\n",
|
||||
"\n",
|
||||
"Connecting to SQL databases with `DBIngestor` and `DatabaseConnector`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import DBIngestor, DatabaseConnector\n",
|
||||
"import sqlite3\n",
|
||||
"\n",
|
||||
"# Setup SQLite DB\n",
|
||||
"db_path = os.path.join(temp_dir, \"test.db\")\n",
|
||||
"conn = sqlite3.connect(db_path)\n",
|
||||
"conn.execute(\"CREATE TABLE items (id INT, name TEXT)\")\n",
|
||||
"conn.execute(\"INSERT INTO items VALUES (1, 'Item 1'), (2, 'Item 2')\")\n",
|
||||
"conn.commit()\n",
|
||||
"conn.close()\n",
|
||||
"\n",
|
||||
"# --- DatabaseConnector ---\n",
|
||||
"connector = DatabaseConnector()\n",
|
||||
"engine = connector.create_engine(f\"sqlite:///{db_path}\")\n",
|
||||
"print(f\"Connected to DB: {engine.name}\")\n",
|
||||
"\n",
|
||||
"# --- DBIngestor ---\n",
|
||||
"db_ingestor = DBIngestor()\n",
|
||||
"table_data = db_ingestor.ingest_database(f\"sqlite:///{db_path}\", table=\"items\")\n",
|
||||
"print(f\"Table: {table_data.table_name}\")\n",
|
||||
"print(f\"Rows: {table_data.row_count}\")\n",
|
||||
"for row in table_data.rows:\n",
|
||||
" print(f\" - {row}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 9. MCP Ingestion\n",
|
||||
"\n",
|
||||
"Integrating with Model Context Protocol servers using `MCPIngestor`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import MCPIngestor\n",
|
||||
"\n",
|
||||
"mcp_ingestor = MCPIngestor()\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" # Connect\n",
|
||||
" mcp_ingestor.connect(\"weather_server\", url=\"http://localhost:8000/mcp\")\n",
|
||||
"\n",
|
||||
" # Ingest Resources\n",
|
||||
" resources = mcp_ingestor.ingest_resources(\"weather_server\")\n",
|
||||
" print(f\"Resources: {len(resources)}\")\n",
|
||||
"\n",
|
||||
" # Call Tool\n",
|
||||
" result = mcp_ingestor.ingest_tool_output(\"weather_server\", \"get_forecast\", {\"city\": \"NYC\"})\n",
|
||||
" print(f\"Tool Result: {result.content}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"MCP ingest failed (Server required): {e}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 10. Configuration\n",
|
||||
"\n",
|
||||
"Managing ingestion settings with `IngestConfig`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import IngestConfig, ingest_config\n",
|
||||
"\n",
|
||||
"# Global config\n",
|
||||
"print(f\"Default Source Type: {ingest_config.get('default_source_type')}\")\n",
|
||||
"\n",
|
||||
"# Custom config instance\n",
|
||||
"config = IngestConfig()\n",
|
||||
"config.set(\"max_file_size\", 1024 * 1024) # 1MB\n",
|
||||
"print(f\"Max File Size: {config.get('max_file_size')} bytes\")\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/introduction/02_Data_Ingestion.ipynb)\n",
|
||||
"\n",
|
||||
"# Data Ingestion - Comprehensive Guide\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook provides a comprehensive guide to Semantica's data ingestion capabilities. It covers all submodules, classes, and helper functions available in the `semantica.ingest` module.\n",
|
||||
"\n",
|
||||
"**Documentation**: [Ingest API Reference](https://semantica.readthedocs.io/reference/ingest/)\n",
|
||||
"\n",
|
||||
"### Table of Contents\n",
|
||||
"\n",
|
||||
"1. **Unified Ingestion**: `ingest` function\n",
|
||||
"2. **File Ingestion**: `FileIngestor`, `FileTypeDetector`, `CloudStorageIngestor`\n",
|
||||
"3. **Web Ingestion**: `WebIngestor`, `ContentExtractor`, `SitemapCrawler`, `RobotsChecker`\n",
|
||||
"4. **Feed Ingestion**: `FeedIngestor`, `FeedMonitor`\n",
|
||||
"5. **Stream Ingestion**: `StreamIngestor`, `StreamMonitor`\n",
|
||||
"6. **Repository Ingestion**: `RepoIngestor`, `CodeExtractor`, `GitAnalyzer`\n",
|
||||
"7. **Email Ingestion**: `EmailIngestor`, `AttachmentProcessor`\n",
|
||||
"8. **Database Ingestion**: `DBIngestor`, `DatabaseConnector`\n",
|
||||
"9. **MCP Ingestion**: `MCPIngestor`\n",
|
||||
"10. **Configuration**: `IngestConfig`\n",
|
||||
"\n",
|
||||
"## Installation\n",
|
||||
"\n",
|
||||
"Install Semantica with all dependencies:\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"pip install semantica[all]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## 1. Unified Ingestion\n",
|
||||
"\n",
|
||||
"The `ingest` function is the main entry point for quick data loading. It automatically detects the source type.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. File Ingestion\n",
|
||||
"\n",
|
||||
"Detailed control over file processing using `FileIngestor` and helper classes.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"import tempfile\n",
|
||||
"from semantica.ingest import FileIngestor, FileTypeDetector, CloudStorageIngestor\n",
|
||||
"\n",
|
||||
"# Ensure dependencies from previous cells are available\n",
|
||||
"if 'temp_dir' not in locals():\n",
|
||||
" temp_dir = tempfile.mkdtemp()\n",
|
||||
" print(f\"Created temporary directory: {temp_dir}\")\n",
|
||||
"\n",
|
||||
"if 'sample_file' not in locals():\n",
|
||||
" sample_file = os.path.join(temp_dir, \"sample_large.txt\")\n",
|
||||
"\n",
|
||||
"if not os.path.exists(sample_file):\n",
|
||||
" # Create a sample file with a lot of info\n",
|
||||
" with open(sample_file, 'w') as f:\n",
|
||||
" f.write(\"# Semantica Data Ingestion Guide\\n\\n\")\n",
|
||||
" f.write(\"Semantica is a powerful framework for semantic data processing.\\n\")\n",
|
||||
" # ... (more content) ...\n",
|
||||
" print(f\"Created sample file: {sample_file}\")\n",
|
||||
"\n",
|
||||
"# --- FileTypeDetector ---\n",
|
||||
"detector = FileTypeDetector()\n",
|
||||
"detected_type = detector.detect_type(sample_file)\n",
|
||||
"print(f\"Detected Type: {detected_type}\")\n",
|
||||
"# ..."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Web Ingestion\n",
|
||||
"\n",
|
||||
"Scraping and crawling with `WebIngestor`, `ContentExtractor`, and `SitemapCrawler`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import requests\n",
|
||||
"from semantica.ingest import WebIngestor, ContentExtractor, SitemapCrawler, RobotsChecker\n",
|
||||
"\n",
|
||||
"# --- ContentExtractor ---\n",
|
||||
"# Demonstrating extraction from a real, content-rich web page\n",
|
||||
"extractor = ContentExtractor()\n",
|
||||
"url = \"https://en.wikipedia.org/wiki/Artificial_intelligence\"\n",
|
||||
"try:\n",
|
||||
" # Wikipedia requires a User-Agent header\n",
|
||||
" headers = {'User-Agent': 'Semantica/1.0 (Education/Example)'}\n",
|
||||
" response = requests.get(url, headers=headers)\n",
|
||||
" html_content = response.text\n",
|
||||
" print(f\"Fetched content from {url}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Failed to fetch {url}: {e}\")\n",
|
||||
" # Fallback content\n",
|
||||
" html_content = \"<html><body><h1>Hello World</h1><p>This is a test.</p><a href='/link'>Link</a></body></html>\"\n",
|
||||
"\n",
|
||||
"text = extractor.extract_text(html_content)\n",
|
||||
"links = extractor.extract_links(html_content, base_url=url)\n",
|
||||
"print(f\"Extracted Text (excerpt): {text[:200]}...\")\n",
|
||||
"print(f\"Found {len(links)} links\")\n",
|
||||
"\n",
|
||||
"# --- RobotsChecker ---\n",
|
||||
"# Initialize with user agent\n",
|
||||
"checker = RobotsChecker(user_agent=\"SemanticaBot\")\n",
|
||||
"# Check if we can fetch a specific page (e.g. Wikipedia Special pages are often restricted)\n",
|
||||
"check_url = \"https://en.wikipedia.org/wiki/Special:Search\"\n",
|
||||
"can_fetch = checker.can_fetch(check_url)\n",
|
||||
"print(f\"Can fetch {check_url}? {can_fetch}\")\n",
|
||||
"\n",
|
||||
"# --- WebIngestor ---\n",
|
||||
"# Configure WebIngestor to be polite but allow the demo to run\n",
|
||||
"web_ingestor = WebIngestor(\n",
|
||||
" delay=1.0,\n",
|
||||
" user_agent=\"Semantica/1.0 (Education/Example)\",\n",
|
||||
" respect_robots=False # Disabled for this demo to ensure Wikipedia access\n",
|
||||
")\n",
|
||||
"try:\n",
|
||||
" web_content = web_ingestor.ingest_url(url)\n",
|
||||
" print(f\"Web Content Title: {web_content.title}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Web ingest failed: {e}\")\n",
|
||||
"\n",
|
||||
"# --- SitemapCrawler ---\n",
|
||||
"crawler = SitemapCrawler()\n",
|
||||
"try:\n",
|
||||
" # Using FastAPI documentation sitemap as a clean, technical example\n",
|
||||
" sitemap_url = \"https://fastapi.tiangolo.com/sitemap.xml\"\n",
|
||||
" urls = crawler.parse_sitemap(sitemap_url)\n",
|
||||
" print(f\"Found {len(urls)} URLs in sitemap: {sitemap_url}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Sitemap crawl failed: {e}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Feed Ingestion\n",
|
||||
"\n",
|
||||
"Consuming RSS/Atom feeds with `FeedIngestor` and monitoring with `FeedMonitor`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import FeedIngestor, FeedMonitor\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"# --- FeedIngestor ---\n",
|
||||
"feed_ingestor = FeedIngestor()\n",
|
||||
"# Using Lilian Weng's AI Blog RSS feed as a reliable source\n",
|
||||
"feed_url = \"https://lilianweng.github.io/index.xml\"\n",
|
||||
"try:\n",
|
||||
" feed_data = feed_ingestor.ingest_feed(feed_url)\n",
|
||||
" print(f\"Feed Title: {feed_data.title}\")\n",
|
||||
" if feed_data.items:\n",
|
||||
" print(f\"Latest Post: {feed_data.items[0].title}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Feed ingest failed: {e}\")\n",
|
||||
"\n",
|
||||
"# --- FeedMonitor ---\n",
|
||||
"def feed_callback(feed_url, new_items):\n",
|
||||
" print(f\"Feed Updated: {feed_url} with {len(new_items)} new items\")\n",
|
||||
"\n",
|
||||
"monitor = FeedMonitor(check_interval=5)\n",
|
||||
"try:\n",
|
||||
" monitor.add_feed(feed_url)\n",
|
||||
" monitor.set_update_callback(feed_callback)\n",
|
||||
" monitor.start_monitoring()\n",
|
||||
" time.sleep(2) # Let it run briefly\n",
|
||||
" monitor.stop_monitoring()\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Feed monitor failed: {e}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Stream Ingestion\n",
|
||||
"\n",
|
||||
"Real-time processing with `StreamIngestor` and `StreamMonitor`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import StreamIngestor, StreamMonitor\n",
|
||||
"\n",
|
||||
"stream_ingestor = StreamIngestor()\n",
|
||||
"\n",
|
||||
"# --- Kafka Processor ---\n",
|
||||
"# Note: This requires a running Kafka instance. We wrap it in try-except for the demo.\n",
|
||||
"kafka_config = {\"bootstrap_servers\": [\"localhost:9092\"]}\n",
|
||||
"try:\n",
|
||||
" kafka_processor = stream_ingestor.ingest_kafka(\"my-topic\", **kafka_config)\n",
|
||||
" print(\"Kafka processor initialized.\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Kafka ingest skipped (requires active broker): {e}\")\n",
|
||||
"\n",
|
||||
"# --- RabbitMQ Processor ---\n",
|
||||
"# Note: This requires a running RabbitMQ instance. We wrap it in try-except for the demo.\n",
|
||||
"try:\n",
|
||||
" rabbitmq_processor = stream_ingestor.ingest_rabbitmq(\"my-queue\", \"amqp://guest:guest@localhost:5672/\")\n",
|
||||
" print(\"RabbitMQ processor initialized.\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"RabbitMQ ingest skipped (requires active broker): {e}\")\n",
|
||||
"\n",
|
||||
"# --- Stream Monitor ---\n",
|
||||
"monitor = stream_ingestor.monitor\n",
|
||||
"health = monitor.check_health()\n",
|
||||
"print(f\"Stream Health: {health['overall']}\")\n",
|
||||
"print(f\"Processors: {list(health['processors'].keys())}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 6. Repository Ingestion\n",
|
||||
"\n",
|
||||
"Analyzing codebases with `RepoIngestor`, `CodeExtractor`, and `GitAnalyzer`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import RepoIngestor, CodeExtractor, GitAnalyzer\n",
|
||||
"from pathlib import Path\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# --- CodeExtractor ---\n",
|
||||
"code_extractor = CodeExtractor()\n",
|
||||
"py_code = \"class MyClass:\\n def my_method(self):\\n pass\"\n",
|
||||
"# Note: Using internal method _extract_structure for demonstration on string input\n",
|
||||
"structure = code_extractor._extract_structure(py_code, language=\"python\")\n",
|
||||
"print(f\"Classes: {structure.get('classes')}\")\n",
|
||||
"print(f\"Functions: {structure.get('functions')}\")\n",
|
||||
"\n",
|
||||
"# --- RepoIngestor ---\n",
|
||||
"repo_ingestor = RepoIngestor()\n",
|
||||
"try:\n",
|
||||
" # Ingesting a public repository (requests) for reliable demonstration\n",
|
||||
" repo_data = repo_ingestor.ingest_repository(\"https://github.com/psf/requests.git\")\n",
|
||||
" # Accessing repo info from the returned dictionary\n",
|
||||
" repo_info = repo_data.get('repository_info', {})\n",
|
||||
" print(f\"Ingested Repo URL: {repo_info.get('url')}\")\n",
|
||||
" print(f\"Branches: {repo_info.get('branches')[:5]}...\") # Show first 5 branches\n",
|
||||
" repo_ingestor.cleanup() # Clean up temp files\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Repo ingest failed: {e}\")\n",
|
||||
"\n",
|
||||
"# --- GitAnalyzer ---\n",
|
||||
"try:\n",
|
||||
" # Initialize analyzer\n",
|
||||
" analyzer = GitAnalyzer()\n",
|
||||
" \n",
|
||||
" # Use current directory for demonstration\n",
|
||||
" current_path = Path(\".\")\n",
|
||||
" \n",
|
||||
" # Metrics calculation\n",
|
||||
" metrics = analyzer.calculate_metrics(current_path)\n",
|
||||
" print(f\"Total Files (recursive): {metrics.get('total_files')}\")\n",
|
||||
" print(f\"Total Lines: {metrics.get('total_lines')}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Git analysis failed: {e}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 7. Email Ingestion\n",
|
||||
"\n",
|
||||
"Processing emails with `EmailIngestor` and `AttachmentProcessor`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import EmailIngestor, AttachmentProcessor\n",
|
||||
"import tempfile\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# Create a temporary directory if not exists (though AttachmentProcessor handles its own temp dir)\n",
|
||||
"temp_dir = tempfile.gettempdir()\n",
|
||||
"\n",
|
||||
"# --- AttachmentProcessor ---\n",
|
||||
"att_processor = AttachmentProcessor()\n",
|
||||
"dummy_content = b\"PDF Content\"\n",
|
||||
"# Use the correct method 'process_attachment' instead of 'save_attachment'\n",
|
||||
"# This method saves the file and returns metadata including the saved path\n",
|
||||
"att_info = att_processor.process_attachment(dummy_content, \"doc.pdf\", \"application/pdf\")\n",
|
||||
"print(f\"Saved attachment to: {att_info.get('saved_path')}\")\n",
|
||||
"\n",
|
||||
"# --- EmailIngestor ---\n",
|
||||
"email_ingestor = EmailIngestor()\n",
|
||||
"try:\n",
|
||||
" # Note: This will fail without real credentials, identifying it as an example\n",
|
||||
" # We wrap it in a try-block to allow the notebook to proceed\n",
|
||||
" email_ingestor.connect_imap(\"imap.gmail.com\", \"user\", \"pass\")\n",
|
||||
" emails = email_ingestor.ingest_mailbox(\"INBOX\", max_emails=5)\n",
|
||||
" print(f\"Fetched {len(emails)} emails\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"Email ingest skipped (Auth required): {e}\")\n",
|
||||
"\n",
|
||||
"# Cleanup any temp files creation by attachment processor\n",
|
||||
"att_processor.cleanup_attachments()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 8. Database Ingestion\n",
|
||||
"\n",
|
||||
"Connecting to SQL databases with `DBIngestor` and `DatabaseConnector`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import DBIngestor, DatabaseConnector\n",
|
||||
"import sqlite3\n",
|
||||
"import os\n",
|
||||
"import tempfile\n",
|
||||
"\n",
|
||||
"# Setup SQLite DB in temp dir\n",
|
||||
"temp_dir = tempfile.gettempdir()\n",
|
||||
"db_path = os.path.join(temp_dir, \"test.db\")\n",
|
||||
"if os.path.exists(db_path):\n",
|
||||
" os.remove(db_path)\n",
|
||||
"\n",
|
||||
"conn = sqlite3.connect(db_path)\n",
|
||||
"conn.execute(\"CREATE TABLE items (id INT, name TEXT)\")\n",
|
||||
"conn.execute(\"INSERT INTO items VALUES (1, 'Item 1'), (2, 'Item 2')\")\n",
|
||||
"conn.commit()\n",
|
||||
"conn.close()\n",
|
||||
"\n",
|
||||
"# --- DatabaseConnector ---\n",
|
||||
"connector = DatabaseConnector()\n",
|
||||
"# Fix: Use 'connect' method, not 'create_engine'\n",
|
||||
"engine = connector.connect(f\"sqlite:///{db_path}\")\n",
|
||||
"# engine.name for sqlite is 'sqlite'\n",
|
||||
"print(f\"Connected to DB Driver: {engine.name}\")\n",
|
||||
"connector.disconnect()\n",
|
||||
"\n",
|
||||
"# --- DBIngestor ---\n",
|
||||
"db_ingestor = DBIngestor()\n",
|
||||
"# Fix: Use 'export_table' to get a single TableData object, matching the variable usage\n",
|
||||
"table_data = db_ingestor.export_table(f\"sqlite:///{db_path}\", table_name=\"items\")\n",
|
||||
"print(f\"Table: {table_data.table_name}\")\n",
|
||||
"print(f\"Rows: {table_data.row_count}\")\n",
|
||||
"print(f\"Data: {table_data.rows}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 9. MCP Ingestion\n",
|
||||
"\n",
|
||||
"Integrating with Model Context Protocol servers using `MCPIngestor`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import MCPIngestor\n",
|
||||
"import logging\n",
|
||||
"\n",
|
||||
"# --- MCPIngestor ---\n",
|
||||
"mcp_ingestor = MCPIngestor()\n",
|
||||
"\n",
|
||||
"# Public Daemon MCP Server\n",
|
||||
"# Source: https://danielmiessler.com/p/daemon-mcp-server\n",
|
||||
"mcp_server_url = \"https://mcp.daemon.danielmiessler.com\"\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" print(f\"Connecting to public MCP server: {mcp_server_url}...\")\n",
|
||||
" \n",
|
||||
" # This server supports standard JSON-RPC over HTTP\n",
|
||||
" mcp_ingestor.connect(\"daemon_server\", url=mcp_server_url)\n",
|
||||
"\n",
|
||||
" # 1. List Available Tools\n",
|
||||
" print(\"\\n--- Available Tools ---\")\n",
|
||||
" tools = mcp_ingestor.list_available_tools(\"daemon_server\")\n",
|
||||
" for tool in tools:\n",
|
||||
" # Print first 5 tools to avoid clutter\n",
|
||||
" if tools.index(tool) < 5:\n",
|
||||
" print(f\"- {tool.name}: {tool.description or 'No description'}\")\n",
|
||||
" if len(tools) > 5:\n",
|
||||
" print(f\"... and {len(tools) - 5} more.\")\n",
|
||||
"\n",
|
||||
" # 2. Call Tool (get_about)\n",
|
||||
" tool_name = \"get_about\"\n",
|
||||
" print(f\"\\n--- Calling Tool '{tool_name}' ---\")\n",
|
||||
" \n",
|
||||
" result = mcp_ingestor.ingest_tool_output(\"daemon_server\", tool_name, {})\n",
|
||||
" \n",
|
||||
" # Parse content\n",
|
||||
" content = result.content.get('content', [])\n",
|
||||
" if content and isinstance(content, list):\n",
|
||||
" for block in content:\n",
|
||||
" if block.get('type') == 'text':\n",
|
||||
" # Truncate if too long\n",
|
||||
" text = block.get('text', '')\n",
|
||||
" preview = text[:200] + \"...\" if len(text) > 200 else text\n",
|
||||
" print(f\"Result: {preview}\")\n",
|
||||
" else:\n",
|
||||
" print(f\"Raw Result: {result.content}\")\n",
|
||||
"\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"MCP Ingestion failed: {e}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 10. Configuration\n",
|
||||
"\n",
|
||||
"Managing ingestion settings with `IngestConfig`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import IngestConfig, ingest_config\n",
|
||||
"\n",
|
||||
"# Global config\n",
|
||||
"print(f\"Default Source Type: {ingest_config.get('default_source_type')}\")\n",
|
||||
"\n",
|
||||
"# Custom config instance\n",
|
||||
"config = IngestConfig()\n",
|
||||
"config.set(\"max_file_size\", 1024 * 1024) # 1MB\n",
|
||||
"print(f\"Max File Size: {config.get('max_file_size')} bytes\")\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
|
||||
@@ -38,6 +38,15 @@
|
||||
"Parse various document formats using the general DocumentParser.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -163,7 +172,7 @@
|
||||
"\n",
|
||||
"xml_data = xml_parser.parse(xml_file)\n",
|
||||
"\n",
|
||||
"print(f\"Parsed XML with {len(xml_data.elements)} elements\")\n",
|
||||
"print(f\"Parsed XML with {len(xml_data.root.children)} elements\")\n",
|
||||
"print(f\"Root element: {xml_data.root.tag if xml_data.root else 'None'}\")\n"
|
||||
]
|
||||
},
|
||||
@@ -251,6 +260,11 @@
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
|
||||
@@ -40,6 +40,15 @@
|
||||
"Normalize text content for consistency.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -127,6 +136,10 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import importlib\n",
|
||||
"import semantica.normalize.number_normalizer\n",
|
||||
"importlib.reload(semantica.normalize.number_normalizer)\n",
|
||||
"\n",
|
||||
"from semantica.normalize import NumberNormalizer\n",
|
||||
"\n",
|
||||
"number_normalizer = NumberNormalizer()\n",
|
||||
@@ -225,6 +238,11 @@
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
|
||||
@@ -52,6 +52,15 @@
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -204,7 +213,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.semantic_extract.methods import get_entity_method\n",
|
||||
"from semantica.semantic_extract import NERExtractor\n",
|
||||
"\n",
|
||||
"sample_text = \"Apple Inc. was founded by Steve Jobs in Cupertino, California in 1976.\"\n",
|
||||
"\n",
|
||||
@@ -219,8 +228,8 @@
|
||||
" print(f\"\\n Method: {method_name.upper()}\")\n",
|
||||
" print(\"-\" * 40)\n",
|
||||
" \n",
|
||||
" method = get_entity_method(method_name)\n",
|
||||
" entities = method(sample_text)\n",
|
||||
" extractor = NERExtractor(method=method_name)\n",
|
||||
" entities = extractor.extract(sample_text)\n",
|
||||
" \n",
|
||||
" print(f\"Found {len(entities)} entities:\")\n",
|
||||
" for entity in entities[:5]: # Show first 5\n",
|
||||
@@ -633,9 +642,9 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.0"
|
||||
"version": "3.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook provides a **comprehensive guide** to extracting relationships between entities and building RDF triples using Semantica's relation extraction modules. You'll learn to identify connections, extract structured triples, and prepare data for knowledge graphs.\n",
|
||||
"This notebook provides a **comprehensive guide** to extracting relationships between entities and building RDF triplets using Semantica's relation extraction modules. You'll learn to identify connections, extract structured triplets, and prepare data for knowledge graphs.\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/semantic_extract/)\n",
|
||||
"\n",
|
||||
@@ -21,21 +21,17 @@
|
||||
"- Extract relationships using `RelationExtractor`\n",
|
||||
"- Understand different extraction methods (pattern, dependency, co-occurrence, HuggingFace, LLM)\n",
|
||||
"- Configure extraction parameters for optimal results\n",
|
||||
"- Extract RDF triples with `TripleExtractor`\n",
|
||||
"- Validate triples using `TripleValidator`\n",
|
||||
"- Serialize triples to RDF formats with `RDFSerializer`\n",
|
||||
"- Assess triple quality with `TripleQualityChecker`\n",
|
||||
"- Build complete entity → relation → triple pipelines\n",
|
||||
"- Extract RDF triplets with `TripletExtractor`\n",
|
||||
"- Serialize triplets to RDF formats with `RDFSerializer`\n",
|
||||
"- Build complete entity → relation → triplet pipelines\n",
|
||||
"\n",
|
||||
"### What You'll Learn\n",
|
||||
"\n",
|
||||
"| Component | Purpose | When to Use |\n",
|
||||
"|-----------|---------|-------------|\n",
|
||||
"| `RelationExtractor` | Extract entity relationships | Finding connections |\n",
|
||||
"| `TripleExtractor` | Extract RDF triples | Building knowledge graphs |\n",
|
||||
"| `TripleValidator` | Validate triple quality | Quality assurance |\n",
|
||||
"| `TripletExtractor` | Extract RDF triplets | Building knowledge graphs |\n",
|
||||
"| `RDFSerializer` | Serialize to RDF formats | Data export |\n",
|
||||
"| `TripleQualityChecker` | Assess triple quality | Quality metrics |\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
@@ -52,6 +48,15 @@
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -180,7 +185,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.semantic_extract.methods import get_relation_method\n",
|
||||
"from semantica.semantic_extract import RelationExtractor\n",
|
||||
"\n",
|
||||
"sample_text = \"Apple Inc. was founded by Steve Jobs in Cupertino, California.\"\n",
|
||||
"sample_entities = ner_extractor.extract(sample_text)\n",
|
||||
@@ -196,8 +201,8 @@
|
||||
" print(f\"\\n Method: {method_name.upper()}\")\n",
|
||||
" print(\"-\" * 40)\n",
|
||||
" \n",
|
||||
" method = get_relation_method(method_name)\n",
|
||||
" relations = method(sample_text, sample_entities)\n",
|
||||
" extractor = RelationExtractor(method=method_name)\n",
|
||||
" relations = extractor.extract(sample_text, sample_entities)\n",
|
||||
" \n",
|
||||
" print(f\"Found {len(relations)} relations:\")\n",
|
||||
" for rel in relations[:3]: # Show first 3\n",
|
||||
@@ -327,20 +332,20 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Triple Extraction\n",
|
||||
"## Step 5: Triplet Extraction\n",
|
||||
"\n",
|
||||
"Extract RDF triples using `TripleExtractor`. Triples are the foundation of knowledge graphs.\n",
|
||||
"Extract RDF triplets using `TripletExtractor`. Triplets are the foundation of knowledge graphs.\n",
|
||||
"\n",
|
||||
"### What are RDF Triples?\n",
|
||||
"### What are RDF Triplets?\n",
|
||||
"\n",
|
||||
"RDF (Resource Description Framework) triples are statements with three parts:\n",
|
||||
"RDF (Resource Description Framework) triplets are statements with three parts:\n",
|
||||
"- **Subject**: What we're talking about\n",
|
||||
"- **Predicate**: The property or relationship\n",
|
||||
"- **Object**: The value or target\n",
|
||||
"\n",
|
||||
"Example: `(Apple Inc., founded_by, Steve Jobs)`\n",
|
||||
"\n",
|
||||
"### Why Use Triples?\n",
|
||||
"### Why Use Triplets?\n",
|
||||
"\n",
|
||||
"- **Standardized format** for knowledge representation\n",
|
||||
"- **Compatible** with RDF databases and semantic web\n",
|
||||
@@ -354,37 +359,37 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.semantic_extract import TripleExtractor\n",
|
||||
"from semantica.semantic_extract import TripletExtractor\n",
|
||||
"\n",
|
||||
"# Initialize triple extractor\n",
|
||||
"triple_extractor = TripleExtractor(\n",
|
||||
"# Initialize triplet extractor\n",
|
||||
"triplet_extractor = TripletExtractor(\n",
|
||||
" include_temporal=True, # Include temporal information\n",
|
||||
" include_provenance=True # Track source sentences\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Sample text\n",
|
||||
"triple_text = \"\"\"\n",
|
||||
"triplet_text = \"\"\"\n",
|
||||
"Apple Inc. was founded by Steve Jobs in 1976. The company is based in Cupertino, California.\n",
|
||||
"Tim Cook became CEO in 2011. Apple develops the iPhone and MacBook products.\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"# Extract triples\n",
|
||||
"triples = triple_extractor.extract_triples(triple_text)\n",
|
||||
"# Extract triplets\n",
|
||||
"triplets = triplet_extractor.extract_triplets(triplet_text)\n",
|
||||
"\n",
|
||||
"print(f\" Extracted {len(triples)} RDF Triples:\\n\")\n",
|
||||
"print(f\" Extracted {len(triplets)} RDF Triplets:\\n\")\n",
|
||||
"print(\"=\" * 80)\n",
|
||||
"\n",
|
||||
"for i, triple in enumerate(triples, 1):\n",
|
||||
" subject = triple.get('subject', '') if isinstance(triple, dict) else triple.subject\n",
|
||||
" predicate = triple.get('predicate', '') if isinstance(triple, dict) else triple.predicate\n",
|
||||
" obj = triple.get('object', '') if isinstance(triple, dict) else triple.object\n",
|
||||
" confidence = triple.get('confidence', 1.0) if isinstance(triple, dict) else getattr(triple, 'confidence', 1.0)\n",
|
||||
"for i, triplet in enumerate(triplets, 1):\n",
|
||||
" subject = triplet.get('subject', '') if isinstance(triplet, dict) else triplet.subject\n",
|
||||
" predicate = triplet.get('predicate', '') if isinstance(triplet, dict) else triplet.predicate\n",
|
||||
" obj = triplet.get('object', '') if isinstance(triplet, dict) else triplet.object\n",
|
||||
" confidence = triplet.get('confidence', 1.0) if isinstance(triplet, dict) else getattr(triplet, 'confidence', 1.0)\n",
|
||||
" \n",
|
||||
" print(f\"{i:2d}. ({subject}, {predicate}, {obj})\")\n",
|
||||
" print(f\" Confidence: {confidence:.2f}\")\n",
|
||||
" \n",
|
||||
" # Show temporal info if available\n",
|
||||
" metadata = triple.get('metadata', {}) if isinstance(triple, dict) else getattr(triple, 'metadata', {})\n",
|
||||
" metadata = triplet.get('metadata', {}) if isinstance(triplet, dict) else getattr(triplet, 'metadata', {})\n",
|
||||
" if metadata.get('temporal'):\n",
|
||||
" print(f\" Temporal: {metadata['temporal']}\")\n",
|
||||
" print()\n",
|
||||
@@ -396,69 +401,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 6: Triple Validation\n",
|
||||
"## Step 6: RDF Serialization\n",
|
||||
"\n",
|
||||
"Validate extracted triples using `TripleValidator` and assess quality with `TripleQualityChecker`.\n",
|
||||
"\n",
|
||||
"### Why Validate Triples?\n",
|
||||
"\n",
|
||||
"- **Ensure completeness**: All parts (subject, predicate, object) present\n",
|
||||
"- **Check confidence**: Filter low-quality extractions\n",
|
||||
"- **Verify consistency**: No contradictory statements\n",
|
||||
"- **Assess quality**: Overall extraction quality metrics"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.semantic_extract import TripleValidator, TripleQualityChecker\n",
|
||||
"\n",
|
||||
"# Initialize validator and quality checker\n",
|
||||
"validator = TripleValidator()\n",
|
||||
"quality_checker = TripleQualityChecker()\n",
|
||||
"\n",
|
||||
"print(\" Triple Validation:\\n\")\n",
|
||||
"print(\"=\" * 80)\n",
|
||||
"\n",
|
||||
"# Validate triples\n",
|
||||
"valid_triples = validator.validate_triples(triples, min_confidence=0.5)\n",
|
||||
"\n",
|
||||
"print(f\"\\n Validation Results:\")\n",
|
||||
"print(f\" Total triples: {len(triples)}\")\n",
|
||||
"print(f\" Valid triples: {len(valid_triples)}\")\n",
|
||||
"print(f\" Filtered out: {len(triples) - len(valid_triples)}\")\n",
|
||||
"\n",
|
||||
"# Check quality\n",
|
||||
"quality_scores = quality_checker.calculate_quality_scores(valid_triples)\n",
|
||||
"\n",
|
||||
"print(f\"\\n Quality Metrics:\")\n",
|
||||
"print(\"-\" * 40)\n",
|
||||
"for metric, value in quality_scores.items():\n",
|
||||
" if isinstance(value, float):\n",
|
||||
" print(f\" {metric}: {value:.2f}\")\n",
|
||||
" else:\n",
|
||||
" print(f\" {metric}: {value}\")\n",
|
||||
"\n",
|
||||
"# Check consistency\n",
|
||||
"consistency_report = validator.check_triple_consistency(valid_triples)\n",
|
||||
"\n",
|
||||
"print(f\"\\n Consistency Check:\")\n",
|
||||
"print(f\" Consistent: {consistency_report.get('consistent', True)}\")\n",
|
||||
"print(f\" Issues found: {len(consistency_report.get('issues', []))}\")\n",
|
||||
"\n",
|
||||
"print(\"\\n\" + \"=\" * 80)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 7: RDF Serialization\n",
|
||||
"\n",
|
||||
"Serialize triples to various RDF formats using `RDFSerializer`.\n",
|
||||
"Serialize triplets to various RDF formats using `RDFSerializer`.\n",
|
||||
"\n",
|
||||
"### Supported Formats:\n",
|
||||
"\n",
|
||||
@@ -492,7 +437,7 @@
|
||||
" print(\"-\" * 40)\n",
|
||||
" \n",
|
||||
" try:\n",
|
||||
" serialized = serializer.serialize_to_rdf(valid_triples[:3], format=fmt) # Show first 3\n",
|
||||
" serialized = serializer.serialize_to_rdf(triplets[:3], format=fmt) # Show first 3\n",
|
||||
" \n",
|
||||
" # Show preview (first 300 chars)\n",
|
||||
" preview = serialized[:300] + \"...\" if len(serialized) > 300 else serialized\n",
|
||||
@@ -508,9 +453,9 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 8: Complete Extraction Pipeline\n",
|
||||
"## Step 7: Complete Extraction Pipeline\n",
|
||||
"\n",
|
||||
"Let's build a complete pipeline: **Entities → Relations → Triples**\n",
|
||||
"Let's build a complete pipeline: **Entities → Relations → Triplets**\n",
|
||||
"\n",
|
||||
"This demonstrates the full workflow for knowledge graph construction."
|
||||
]
|
||||
@@ -529,7 +474,7 @@
|
||||
" text: Input text\n",
|
||||
" \n",
|
||||
" Returns:\n",
|
||||
" dict: Extracted entities, relations, and triples\n",
|
||||
" dict: Extracted entities, relations, and triplets\n",
|
||||
" \"\"\"\n",
|
||||
" # Step 1: Extract entities\n",
|
||||
" entities = ner_extractor.extract(text)\n",
|
||||
@@ -537,16 +482,13 @@
|
||||
" # Step 2: Extract relations\n",
|
||||
" relations = relation_extractor.extract(text, entities)\n",
|
||||
" \n",
|
||||
" # Step 3: Extract triples\n",
|
||||
" triples = triple_extractor.extract_triples(text, entities=entities, relationships=relations)\n",
|
||||
" \n",
|
||||
" # Step 4: Validate triples\n",
|
||||
" valid_triples = validator.validate_triples(triples)\n",
|
||||
" # Step 3: Extract triplets\n",
|
||||
" triplets = triplet_extractor.extract_triplets(text, entities=entities, relationships=relations)\n",
|
||||
" \n",
|
||||
" return {\n",
|
||||
" 'entities': entities,\n",
|
||||
" 'relations': relations,\n",
|
||||
" 'triples': valid_triples\n",
|
||||
" 'triplets': triplets\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"# Sample knowledge-rich text\n",
|
||||
@@ -567,13 +509,13 @@
|
||||
"print(\"-\" * 40)\n",
|
||||
"print(f\"Entities extracted: {len(result['entities'])}\")\n",
|
||||
"print(f\"Relations extracted: {len(result['relations'])}\")\n",
|
||||
"print(f\"Triples extracted: {len(result['triples'])}\")\n",
|
||||
"print(f\"Triplets extracted: {len(result['triplets'])}\")\n",
|
||||
"\n",
|
||||
"print(f\"\\n Sample Triples:\")\n",
|
||||
"for i, triple in enumerate(result['triples'][:5], 1):\n",
|
||||
" subject = triple.get('subject', '') if isinstance(triple, dict) else triple.subject\n",
|
||||
" predicate = triple.get('predicate', '') if isinstance(triple, dict) else triple.predicate\n",
|
||||
" obj = triple.get('object', '') if isinstance(triple, dict) else triple.object\n",
|
||||
"print(f\"\\n Sample Triplets:\")\n",
|
||||
"for i, triplet in enumerate(result['triplets'][:5], 1):\n",
|
||||
" subject = triplet.get('subject', '') if isinstance(triplet, dict) else triplet.subject\n",
|
||||
" predicate = triplet.get('predicate', '') if isinstance(triplet, dict) else triplet.predicate\n",
|
||||
" obj = triplet.get('object', '') if isinstance(triplet, dict) else triplet.object\n",
|
||||
" print(f\" {i}. ({subject}, {predicate}, {obj})\")\n",
|
||||
"\n",
|
||||
"print(\"\\n\" + \"=\" * 80)"
|
||||
@@ -583,7 +525,7 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 9: Best Practices & Tips\n",
|
||||
"## Step 8: Best Practices & Tips\n",
|
||||
"\n",
|
||||
"### Choosing the Right Method\n",
|
||||
"\n",
|
||||
@@ -597,32 +539,27 @@
|
||||
"- **Set confidence thresholds** (0.6-0.7 for production)\n",
|
||||
"- **Specify relation_types** to focus extraction\n",
|
||||
"- **Adjust max_distance** based on text structure\n",
|
||||
"- **Validate triples** before using in knowledge graphs\n",
|
||||
"\n",
|
||||
"### Common Pitfalls to Avoid\n",
|
||||
"\n",
|
||||
"- **Don't** skip entity extraction (relations need entities)\n",
|
||||
"- **Don't** use very low confidence thresholds\n",
|
||||
"- **Don't** ignore relation validation\n",
|
||||
"- **Don't** forget to serialize triples for storage\n",
|
||||
"- **Don't** forget to serialize triplets for storage\n",
|
||||
"\n",
|
||||
"### When to Use Each Component\n",
|
||||
"\n",
|
||||
"| Use Case | Recommended Component |\n",
|
||||
"|----------|----------------------|\n",
|
||||
"| Find entity connections | `RelationExtractor` |\n",
|
||||
"| Build knowledge graphs | `TripleExtractor` |\n",
|
||||
"| Quality assurance | `TripleValidator` |\n",
|
||||
"| Build knowledge graphs | `TripletExtractor` |\n",
|
||||
"| Export to RDF | `RDFSerializer` |\n",
|
||||
"| Assess extraction quality | `TripleQualityChecker` |\n",
|
||||
"\n",
|
||||
"### Performance Tips\n",
|
||||
"\n",
|
||||
"1. **Extract entities once**, reuse for relations and triples\n",
|
||||
"1. **Extract entities once**, reuse for relations and triplets\n",
|
||||
"2. **Batch process** multiple documents together\n",
|
||||
"3. **Cache extractors** instead of recreating\n",
|
||||
"4. **Filter early** with confidence thresholds\n",
|
||||
"5. **Validate incrementally** rather than all at once"
|
||||
"4. **Filter early** with confidence thresholds"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -638,25 +575,22 @@
|
||||
" **Extract relationships** using `RelationExtractor` \n",
|
||||
" **Compare extraction methods** (pattern, dependency, co-occurrence, HuggingFace, LLM) \n",
|
||||
" **Configure extraction parameters** for optimal results \n",
|
||||
" **Extract RDF triples** with `TripleExtractor` \n",
|
||||
" **Validate triples** using `TripleValidator` \n",
|
||||
" **Extract RDF triplets** with `TripletExtractor` \n",
|
||||
" **Serialize to RDF formats** with `RDFSerializer` \n",
|
||||
" **Assess quality** with `TripleQualityChecker` \n",
|
||||
" **Build complete pipelines** from entities to triples \n",
|
||||
" **Build complete pipelines** from entities to triplets \n",
|
||||
"\n",
|
||||
"### Key Takeaways\n",
|
||||
"\n",
|
||||
"1. **Relations connect entities**: They form the backbone of knowledge graphs\n",
|
||||
"2. **Multiple methods available**: Choose based on accuracy vs speed needs\n",
|
||||
"3. **Configuration is powerful**: Tune parameters for your domain\n",
|
||||
"4. **Triples are standardized**: Use RDF for interoperability\n",
|
||||
"5. **Validation is essential**: Ensure quality before using triples\n",
|
||||
"6. **Pipelines are efficient**: Extract entities → relations → triples in sequence\n",
|
||||
"4. **Triplets are standardized**: Use RDF for interoperability\n",
|
||||
"5. **Pipelines are efficient**: Extract entities → relations → triplets in sequence\n",
|
||||
"\n",
|
||||
"### Next Steps\n",
|
||||
"\n",
|
||||
" **Next Notebook**: [07_Building_Knowledge_Graphs.ipynb](./07_Building_Knowledge_Graphs.ipynb) \n",
|
||||
"Learn how to build complete knowledge graphs from your extracted triples!\n",
|
||||
"Learn how to build complete knowledge graphs from your extracted triplets!\n",
|
||||
"\n",
|
||||
" **Further Reading**:\n",
|
||||
"- [Semantic Extract API Reference](https://semantica.readthedocs.io/reference/semantic_extract/)\n",
|
||||
@@ -690,4 +624,4 @@
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates how to build knowledge graphs from entities and relationships using Semantica's graph building modules. You'll learn to use `GraphBuilder`, `EntityResolver`, and `GraphValidator`.\n",
|
||||
"This notebook demonstrates how to build knowledge graphs from entities and relationships using Semantica's graph building modules. You'll learn to use `GraphBuilder` and `EntityResolver`.\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/kg/)\n",
|
||||
"\n",
|
||||
@@ -18,7 +18,6 @@
|
||||
"\n",
|
||||
"- Use `GraphBuilder` to construct knowledge graphs\n",
|
||||
"- Use `EntityResolver` to resolve entity conflicts\n",
|
||||
"- Use `GraphValidator` to validate graph structure\n",
|
||||
"**Note**: For deduplication, use the `semantica.deduplication` module.\n",
|
||||
"\n",
|
||||
"## Installation\n",
|
||||
@@ -38,6 +37,15 @@
|
||||
"Construct a knowledge graph from entities and relationships.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -60,8 +68,8 @@
|
||||
"for i, entity in enumerate(entities_list[:5], 1):\n",
|
||||
" entities.append({\n",
|
||||
" \"id\": f\"e{i}\",\n",
|
||||
" \"type\": entity.get(\"type\", \"Entity\"),\n",
|
||||
" \"name\": entity.get(\"text\", entity.get(\"entity\", \"\")),\n",
|
||||
" \"type\": entity.label,\n",
|
||||
" \"name\": entity.text,\n",
|
||||
" \"properties\": {}\n",
|
||||
" })\n",
|
||||
"\n",
|
||||
@@ -70,14 +78,14 @@
|
||||
" relationships.append({\n",
|
||||
" \"source\": f\"e{1}\",\n",
|
||||
" \"target\": f\"e{i+1}\",\n",
|
||||
" \"type\": rel.get(\"type\", \"related_to\"),\n",
|
||||
" \"type\": rel.predicate,\n",
|
||||
" \"properties\": {}\n",
|
||||
" })\n",
|
||||
"\n",
|
||||
"knowledge_graph = builder.build(entities, relationships)\n",
|
||||
"\n",
|
||||
"print(f\"Built knowledge graph with {len(knowledge_graph.get('entities', []))} entities\")\n",
|
||||
"print(f\"Relationships: {len(knowledge_graph.get('relationships', []))}\")\n"
|
||||
"print(f\"Relationships: {len(knowledge_graph.get('relationships', []))}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -99,42 +107,17 @@
|
||||
"\n",
|
||||
"entity_resolver = EntityResolver()\n",
|
||||
"\n",
|
||||
"resolved_entities = entity_resolver.resolve(entities)\n",
|
||||
"resolved_entities = entity_resolver.resolve_entities(entities)\n",
|
||||
"\n",
|
||||
"print(f\"Original entities: {len(entities)}\")\n",
|
||||
"print(f\"Resolved entities: {len(resolved_entities)}\")\n"
|
||||
"print(f\"Resolved entities: {len(resolved_entities)}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Graph Validation\n",
|
||||
"\n",
|
||||
"Validate the knowledge graph structure.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.kg import GraphValidator\n",
|
||||
"\n",
|
||||
"graph_validator = GraphValidator()\n",
|
||||
"\n",
|
||||
"validation_result = graph_validator.validate(knowledge_graph)\n",
|
||||
"\n",
|
||||
"print(f\"Graph validation: {validation_result.get('valid', False)}\")\n",
|
||||
"print(f\"Issues: {len(validation_result.get('issues', []))}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Deduplication\n",
|
||||
"## Step 3: Deduplication\n",
|
||||
"\n",
|
||||
"Remove duplicate entities from the graph.\n"
|
||||
]
|
||||
@@ -174,7 +157,6 @@
|
||||
"\n",
|
||||
"- **GraphBuilder**: Construct knowledge graphs from entities and relationships\n",
|
||||
"- **EntityResolver**: Resolve entity conflicts and duplicates\n",
|
||||
"- **GraphValidator**: Validate graph structure and quality\n",
|
||||
"- **Deduplication**: Use `semantica.deduplication` module for removing duplicate entities\n",
|
||||
"\n",
|
||||
"Next: Learn how to analyze graphs in the Graph_Analytics notebook.\n"
|
||||
@@ -182,8 +164,22 @@
|
||||
}
|
||||
],
|
||||
"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.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -1,289 +1,319 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/introduction/09_Your_First_Knowledge_Graph.ipynb)\n",
|
||||
"\n",
|
||||
"# 🚀 Your First Knowledge Graph\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook walks you through creating your first knowledge graph from a simple document. You'll learn the complete end-to-end workflow from ingesting a file to visualizing the resulting knowledge graph.\n",
|
||||
"\n",
|
||||
"> [!TIP]\n",
|
||||
"> This is the perfect starting point if you are new to Semantica. No prior knowledge of knowledge graphs is required!\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/kg/)\n",
|
||||
"\n",
|
||||
"### 🎯 Learning Objectives\n",
|
||||
"\n",
|
||||
"- **Understand the Workflow**: Learn the `File → Parse → Extract → Graph` pipeline\n",
|
||||
"- **Ingest Data**: Load documents using `FileIngestor`\n",
|
||||
"- **Parse Content**: Extract text using `DocumentParser`\n",
|
||||
"- **Extract Knowledge**: Identify entities using `NERExtractor`\n",
|
||||
"- **Build Graph**: Construct a graph using `GraphBuilder`\n",
|
||||
"- **Visualize**: See your graph come to life with `KGVisualizer`\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",
|
||||
"## 🔄 Simple End-to-End Workflow\n",
|
||||
"\n",
|
||||
"The complete workflow consists of four main steps:\n",
|
||||
"\n",
|
||||
"1. **📥 Ingest** - Load data from files or other sources\n",
|
||||
"2. **📄 Parse** - Extract and structure content from documents\n",
|
||||
"3. **⛏️ Extract** - Identify entities and relationships\n",
|
||||
"4. **🕸️ Build Graph** - Construct the knowledge graph\n",
|
||||
"\n",
|
||||
"Each step is demonstrated in the code cells below.\n",
|
||||
"\n",
|
||||
"> [!TIP]\n",
|
||||
"> **Alternative: Using Semantica Framework**\n",
|
||||
"> \n",
|
||||
"> For a simpler, high-level approach, you can use the `Semantica` framework class which orchestrates all these steps:\n",
|
||||
"> \n",
|
||||
"> ```python\n",
|
||||
"> from semantica.core import Semantica\n",
|
||||
"> \n",
|
||||
"> framework = Semantica()\n",
|
||||
"> framework.initialize()\n",
|
||||
"> \n",
|
||||
"> result = framework.build_knowledge_base(\n",
|
||||
"> sources=[\"sample_document.txt\"],\n",
|
||||
"> embeddings=True,\n",
|
||||
"> graph=True\n",
|
||||
"> )\n",
|
||||
"> \n",
|
||||
"> framework.shutdown()\n",
|
||||
"> ```\n",
|
||||
"> \n",
|
||||
"> This notebook shows the step-by-step approach for learning. See [Core Module Usage Guide](../../../semantica/core/core_usage.md) for more details.\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## 📂 Step 1: Ingest a File\n",
|
||||
"\n",
|
||||
"In this step, we'll use `FileIngestor` to load a document. The ingestor supports various file formats including PDF, DOCX, TXT, and more.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import FileIngestor\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"# Initialize the ingestor\n",
|
||||
"ingestor = FileIngestor()\n",
|
||||
"\n",
|
||||
"# Create a sample document for demonstration\n",
|
||||
"sample_text = \"\"\"\n",
|
||||
"Apple Inc. is a technology company founded by Steve Jobs, Steve Wozniak, and Ronald Wayne in 1976.\n",
|
||||
"The company is headquartered in Cupertino, California.\n",
|
||||
"Tim Cook is the current CEO of Apple Inc.\n",
|
||||
"Apple designs and manufactures consumer electronics, software, and online services.\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"sample_file = Path(\"sample_document.txt\")\n",
|
||||
"sample_file.write_text(sample_text)\n",
|
||||
"\n",
|
||||
"print(f\"File: {sample_file}\")\n",
|
||||
"print(f\"Content length: {len(sample_text)} characters\")\n",
|
||||
"\n",
|
||||
"# Ingest the file\n",
|
||||
"file_object = ingestor.ingest_file(sample_file, read_content=True)\n",
|
||||
"print(f\" File name: {file_object.name}\")\n",
|
||||
"print(f\" File type: {file_object.file_type}\")\n",
|
||||
"print(f\" Content available: {file_object.content is not None}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 📄 Step 2: Parse the Document\n",
|
||||
"\n",
|
||||
"After ingesting the file, we need to parse it to extract the text content. The `DocumentParser` handles various file formats and extracts structured content.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.parse import DocumentParser\n",
|
||||
"\n",
|
||||
"parser = DocumentParser()\n",
|
||||
"\n",
|
||||
"# Parse the document to extract text\n",
|
||||
"parsed_content = parser.parse_document(str(sample_file))\n",
|
||||
"print(f\" Parsed content length: {len(parsed_content) if parsed_content else 0} characters\")\n",
|
||||
"print(f\" Preview: {parsed_content[:200] if parsed_content else 'N/A'}...\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## ⛏️ Step 3: Extract Entities\n",
|
||||
"\n",
|
||||
"Now we'll extract entities from the parsed text using Named Entity Recognition (NER). This identifies people, organizations, locations, dates, and other entities in the text.\n",
|
||||
"\n",
|
||||
"> [!NOTE]\n",
|
||||
"> In a real scenario, you would use `NERExtractor` with an LLM or model backend. Here we simulate the output for demonstration purposes.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.semantic_extract import NamedEntityRecognizer, NERExtractor\n",
|
||||
"\n",
|
||||
"ner = NamedEntityRecognizer()\n",
|
||||
"extractor = NERExtractor()\n",
|
||||
"\n",
|
||||
"print(f\"\\nText: {parsed_content[:100]}...\")\n",
|
||||
"\n",
|
||||
"# Simulated extraction results\n",
|
||||
"expected_entities = [\n",
|
||||
" {\"text\": \"Apple Inc.\", \"type\": \"Organization\", \"start\": 0, \"end\": 10},\n",
|
||||
" {\"text\": \"Steve Jobs\", \"type\": \"Person\", \"start\": 50, \"end\": 60},\n",
|
||||
" {\"text\": \"Steve Wozniak\", \"type\": \"Person\", \"start\": 62, \"end\": 75},\n",
|
||||
" {\"text\": \"Ronald Wayne\", \"type\": \"Person\", \"start\": 81, \"end\": 93},\n",
|
||||
" {\"text\": \"1976\", \"type\": \"Date\", \"start\": 97, \"end\": 101},\n",
|
||||
" {\"text\": \"Cupertino, California\", \"type\": \"Location\", \"start\": 130, \"end\": 151},\n",
|
||||
" {\"text\": \"Tim Cook\", \"type\": \"Person\", \"start\": 153, \"end\": 161},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"for entity in expected_entities:\n",
|
||||
" print(f\" - {entity['text']} ({entity['type']})\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 🕸️ Step 4: Build the Knowledge Graph\n",
|
||||
"\n",
|
||||
"Using the extracted entities and relationships, we'll construct a knowledge graph. The graph represents entities as nodes and relationships as edges.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.kg import GraphBuilder\n",
|
||||
"import networkx as nx\n",
|
||||
"\n",
|
||||
"builder = GraphBuilder()\n",
|
||||
"\n",
|
||||
"# Prepare data for graph construction\n",
|
||||
"entities_data = [\n",
|
||||
" {\"id\": f\"entity_{i}\", \"name\": entity[\"text\"], \"type\": entity[\"type\"]}\n",
|
||||
" for i, entity in enumerate(expected_entities)\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"relationships_data = [\n",
|
||||
" {\"source\": \"entity_0\", \"target\": \"entity_1\", \"type\": \"founded_by\"},\n",
|
||||
" {\"source\": \"entity_0\", \"target\": \"entity_2\", \"type\": \"founded_by\"},\n",
|
||||
" {\"source\": \"entity_0\", \"target\": \"entity_3\", \"type\": \"founded_by\"},\n",
|
||||
" {\"source\": \"entity_0\", \"target\": \"entity_4\", \"type\": \"founded_in\"},\n",
|
||||
" {\"source\": \"entity_0\", \"target\": \"entity_5\", \"type\": \"located_in\"},\n",
|
||||
" {\"source\": \"entity_6\", \"target\": \"entity_0\", \"type\": \"ceo_of\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Build the graph using NetworkX\n",
|
||||
"kg = nx.DiGraph()\n",
|
||||
"\n",
|
||||
"for entity in entities_data:\n",
|
||||
" kg.add_node(entity[\"id\"], name=entity[\"name\"], type=entity[\"type\"])\n",
|
||||
"\n",
|
||||
"for rel in relationships_data:\n",
|
||||
" source_name = entities_data[int(rel[\"source\"].split(\"_\")[1])][\"name\"]\n",
|
||||
" target_name = entities_data[int(rel[\"target\"].split(\"_\")[1])][\"name\"]\n",
|
||||
" kg.add_edge(rel[\"source\"], rel[\"target\"], type=rel[\"type\"])\n",
|
||||
"\n",
|
||||
"print(f\" Nodes (entities): {len(kg.nodes)}\")\n",
|
||||
"print(f\" Edges (relationships): {len(kg.edges)}\")\n",
|
||||
"\n",
|
||||
"for node_id in kg.nodes():\n",
|
||||
" node_data = kg.nodes[node_id]\n",
|
||||
" print(f\" Node: {node_data['name']} ({node_data['type']})\")\n",
|
||||
"\n",
|
||||
"for source, target, data in kg.edges(data=True):\n",
|
||||
" source_name = kg.nodes[source]['name']\n",
|
||||
" target_name = kg.nodes[target]['name']\n",
|
||||
" print(f\" {source_name} --[{data['type']}]--> {target_name}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 📊 Step 5: Visualize and Analyze\n",
|
||||
"\n",
|
||||
"Finally, we'll visualize the knowledge graph and analyze its structure. This helps you understand the relationships and entities in your data.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.visualization import KGVisualizer\n",
|
||||
"\n",
|
||||
"visualizer = KGVisualizer()\n",
|
||||
"\n",
|
||||
"print(f\" Total entities: {len(kg.nodes)}\")\n",
|
||||
"print(f\" Total relationships: {len(kg.edges)}\")\n",
|
||||
"\n",
|
||||
"entity_types = {}\n",
|
||||
"for node_id in kg.nodes():\n",
|
||||
" entity_type = kg.nodes[node_id]['type']\n",
|
||||
" entity_types[entity_type] = entity_types.get(entity_type, 0) + 1\n",
|
||||
"\n",
|
||||
"for etype, count in entity_types.items():\n",
|
||||
" print(f\" - {etype}: {count}\")\n",
|
||||
"\n",
|
||||
"rel_types = {}\n",
|
||||
"for _, _, data in kg.edges(data=True):\n",
|
||||
" rel_type = data.get('type', 'unknown')\n",
|
||||
" rel_types[rel_type] = rel_types.get(rel_type, 0) + 1\n",
|
||||
"\n",
|
||||
"for rtype, count in rel_types.items():\n",
|
||||
" print(f\" - {rtype}: {count}\")\n",
|
||||
"\n",
|
||||
"# Cleanup\n",
|
||||
"if sample_file.exists():\n",
|
||||
" sample_file.unlink()\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/introduction/09_Your_First_Knowledge_Graph.ipynb)\n",
|
||||
"\n",
|
||||
"# 🚀 Your First Knowledge Graph\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook walks you through creating your first knowledge graph from a simple document. You'll learn the complete end-to-end workflow from ingesting a file to visualizing the resulting knowledge graph.\n",
|
||||
"\n",
|
||||
"> [!TIP]\n",
|
||||
"> This is the perfect starting point if you are new to Semantica. No prior knowledge of knowledge graphs is required!\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/kg/)\n",
|
||||
"\n",
|
||||
"### 🎯 Learning Objectives\n",
|
||||
"\n",
|
||||
"- **Understand the Workflow**: Learn the `File → Parse → Extract → Graph` pipeline\n",
|
||||
"- **Ingest Data**: Load documents using `FileIngestor`\n",
|
||||
"- **Parse Content**: Extract text using `DocumentParser`\n",
|
||||
"- **Extract Knowledge**: Identify entities using `NERExtractor`\n",
|
||||
"- **Build Graph**: Construct a graph using `GraphBuilder`\n",
|
||||
"- **Visualize**: See your graph come to life with `KGVisualizer`\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",
|
||||
"## 🔄 Simple End-to-End Workflow\n",
|
||||
"\n",
|
||||
"The complete workflow consists of four main steps:\n",
|
||||
"\n",
|
||||
"1. **📥 Ingest** - Load data from files or other sources\n",
|
||||
"2. **📄 Parse** - Extract and structure content from documents\n",
|
||||
"3. **⛏️ Extract** - Identify entities and relationships\n",
|
||||
"4. **🕸️ Build Graph** - Construct the knowledge graph\n",
|
||||
"\n",
|
||||
"Each step is demonstrated in the code cells below.\n",
|
||||
"\n",
|
||||
"> [!TIP]\n",
|
||||
"> **Alternative: Using Semantica Framework**\n",
|
||||
"> \n",
|
||||
"> For a simpler, high-level approach, you can use the `Semantica` framework class which orchestrates all these steps:\n",
|
||||
"> \n",
|
||||
"> ```python\n",
|
||||
"> from semantica.core import Semantica\n",
|
||||
"> \n",
|
||||
"> framework = Semantica()\n",
|
||||
"> framework.initialize()\n",
|
||||
"> \n",
|
||||
"> result = framework.build_knowledge_base(\n",
|
||||
"> sources=[\"sample_document.txt\"],\n",
|
||||
"> embeddings=True,\n",
|
||||
"> graph=True\n",
|
||||
"> )\n",
|
||||
"> \n",
|
||||
"> framework.shutdown()\n",
|
||||
"> ```\n",
|
||||
"> \n",
|
||||
"> This notebook shows the step-by-step approach for learning. See [Core Module Usage Guide](../../../semantica/core/core_usage.md) for more details.\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## 📂 Step 1: Ingest a File\n",
|
||||
"\n",
|
||||
"In this step, we'll use `FileIngestor` to load a document. The ingestor supports various file formats including PDF, DOCX, TXT, and more.\n"
|
||||
]
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.ingest import FileIngestor\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"# Initialize the ingestor\n",
|
||||
"ingestor = FileIngestor()\n",
|
||||
"\n",
|
||||
"# Create a sample document for demonstration\n",
|
||||
"sample_text = \"\"\"\n",
|
||||
"Apple Inc. is a technology company founded by Steve Jobs, Steve Wozniak, and Ronald Wayne in 1976.\n",
|
||||
"The company is headquartered in Cupertino, California.\n",
|
||||
"Tim Cook is the current CEO of Apple Inc.\n",
|
||||
"Apple designs and manufactures consumer electronics, software, and online services.\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"sample_file = Path(\"sample_document.txt\")\n",
|
||||
"sample_file.write_text(sample_text)\n",
|
||||
"\n",
|
||||
"print(f\"File: {sample_file}\")\n",
|
||||
"print(f\"Content length: {len(sample_text)} characters\")\n",
|
||||
"\n",
|
||||
"# Ingest the file\n",
|
||||
"file_object = ingestor.ingest_file(sample_file, read_content=True)\n",
|
||||
"print(f\" File name: {file_object.name}\")\n",
|
||||
"print(f\" File type: {file_object.file_type}\")\n",
|
||||
"print(f\" Content available: {file_object.content is not None}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 📄 Step 2: Parse the Document\n",
|
||||
"\n",
|
||||
"After ingesting the file, we need to parse it to extract the text content. The `DocumentParser` handles various file formats and extracts structured content.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.parse import DocumentParser\n",
|
||||
"\n",
|
||||
"parser = DocumentParser()\n",
|
||||
"# Parse the document to extract text\n",
|
||||
"parsed_document = parser.parse_document(str(sample_file))\n",
|
||||
"parsed_content = parsed_document.get(\"content\", \"\")\n",
|
||||
"print(f\" Parsed content length: {len(parsed_content) if parsed_content else 0} characters\")\n",
|
||||
"print(f\" Preview: {parsed_content[:200] if parsed_content else 'N/A'}...\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## ⛏️ Step 3: Extract Entities\n",
|
||||
"\n",
|
||||
"Now we'll extract entities from the parsed text using Named Entity Recognition (NER). This identifies people, organizations, locations, dates, and other entities in the text.\n",
|
||||
"\n",
|
||||
"> [!NOTE]\n",
|
||||
"> In a real scenario, you would use `NERExtractor` with an LLM or model backend. Here we simulate the output for demonstration purposes.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.semantic_extract import NamedEntityRecognizer, NERExtractor\n",
|
||||
"\n",
|
||||
"ner = NamedEntityRecognizer()\n",
|
||||
"extractor = NERExtractor()\n",
|
||||
"\n",
|
||||
"print(f\"\\nText: {parsed_content[:100]}...\")\n",
|
||||
"\n",
|
||||
"# Simulated extraction results\n",
|
||||
"expected_entities = [\n",
|
||||
" {\"text\": \"Apple Inc.\", \"type\": \"Organization\", \"start\": 0, \"end\": 10},\n",
|
||||
" {\"text\": \"Steve Jobs\", \"type\": \"Person\", \"start\": 50, \"end\": 60},\n",
|
||||
" {\"text\": \"Steve Wozniak\", \"type\": \"Person\", \"start\": 62, \"end\": 75},\n",
|
||||
" {\"text\": \"Ronald Wayne\", \"type\": \"Person\", \"start\": 81, \"end\": 93},\n",
|
||||
" {\"text\": \"1976\", \"type\": \"Date\", \"start\": 97, \"end\": 101},\n",
|
||||
" {\"text\": \"Cupertino, California\", \"type\": \"Location\", \"start\": 130, \"end\": 151},\n",
|
||||
" {\"text\": \"Tim Cook\", \"type\": \"Person\", \"start\": 153, \"end\": 161},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"for entity in expected_entities:\n",
|
||||
" print(f\" - {entity['text']} ({entity['type']})\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 🕸️ Step 4: Build the Knowledge Graph\n",
|
||||
"\n",
|
||||
"Using the extracted entities and relationships, we'll construct a knowledge graph. The graph represents entities as nodes and relationships as edges.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.kg import GraphBuilder\n",
|
||||
"import networkx as nx\n",
|
||||
"\n",
|
||||
"builder = GraphBuilder()\n",
|
||||
"\n",
|
||||
"# Prepare data for graph construction\n",
|
||||
"entities_data = [\n",
|
||||
" {\"id\": f\"entity_{i}\", \"name\": entity[\"text\"], \"type\": entity[\"type\"]}\n",
|
||||
" for i, entity in enumerate(expected_entities)\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"relationships_data = [\n",
|
||||
" {\"source\": \"entity_0\", \"target\": \"entity_1\", \"type\": \"founded_by\"},\n",
|
||||
" {\"source\": \"entity_0\", \"target\": \"entity_2\", \"type\": \"founded_by\"},\n",
|
||||
" {\"source\": \"entity_0\", \"target\": \"entity_3\", \"type\": \"founded_by\"},\n",
|
||||
" {\"source\": \"entity_0\", \"target\": \"entity_4\", \"type\": \"founded_in\"},\n",
|
||||
" {\"source\": \"entity_0\", \"target\": \"entity_5\", \"type\": \"located_in\"},\n",
|
||||
" {\"source\": \"entity_6\", \"target\": \"entity_0\", \"type\": \"ceo_of\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Build the graph using NetworkX\n",
|
||||
"kg = nx.DiGraph()\n",
|
||||
"\n",
|
||||
"for entity in entities_data:\n",
|
||||
" kg.add_node(entity[\"id\"], name=entity[\"name\"], type=entity[\"type\"])\n",
|
||||
"\n",
|
||||
"for rel in relationships_data:\n",
|
||||
" source_name = entities_data[int(rel[\"source\"].split(\"_\")[1])][\"name\"]\n",
|
||||
" target_name = entities_data[int(rel[\"target\"].split(\"_\")[1])][\"name\"]\n",
|
||||
" kg.add_edge(rel[\"source\"], rel[\"target\"], type=rel[\"type\"])\n",
|
||||
"\n",
|
||||
"print(f\" Nodes (entities): {len(kg.nodes)}\")\n",
|
||||
"print(f\" Edges (relationships): {len(kg.edges)}\")\n",
|
||||
"\n",
|
||||
"for node_id in kg.nodes():\n",
|
||||
" node_data = kg.nodes[node_id]\n",
|
||||
" print(f\" Node: {node_data['name']} ({node_data['type']})\")\n",
|
||||
"\n",
|
||||
"for source, target, data in kg.edges(data=True):\n",
|
||||
" source_name = kg.nodes[source]['name']\n",
|
||||
" target_name = kg.nodes[target]['name']\n",
|
||||
" print(f\" {source_name} --[{data['type']}]--> {target_name}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 📊 Step 5: Visualize and Analyze\n",
|
||||
"\n",
|
||||
"Finally, we'll visualize the knowledge graph and analyze its structure. This helps you understand the relationships and entities in your data.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.visualization import KGVisualizer\n",
|
||||
"\n",
|
||||
"visualizer = KGVisualizer()\n",
|
||||
"\n",
|
||||
"print(f\" Total entities: {len(kg.nodes)}\")\n",
|
||||
"print(f\" Total relationships: {len(kg.edges)}\")\n",
|
||||
"\n",
|
||||
"entity_types = {}\n",
|
||||
"for node_id in kg.nodes():\n",
|
||||
" entity_type = kg.nodes[node_id]['type']\n",
|
||||
" entity_types[entity_type] = entity_types.get(entity_type, 0) + 1\n",
|
||||
"\n",
|
||||
"for etype, count in entity_types.items():\n",
|
||||
" print(f\" - {etype}: {count}\")\n",
|
||||
"\n",
|
||||
"rel_types = {}\n",
|
||||
"for _, _, data in kg.edges(data=True):\n",
|
||||
" rel_type = data.get('type', 'unknown')\n",
|
||||
" rel_types[rel_type] = rel_types.get(rel_type, 0) + 1\n",
|
||||
"\n",
|
||||
"for rtype, count in rel_types.items():\n",
|
||||
" print(f\" - {rtype}: {count}\")\n",
|
||||
"\n",
|
||||
"# Cleanup\n",
|
||||
"if sample_file.exists():\n",
|
||||
" sample_file.unlink()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
"# For Neo4j (requires Neo4j server)\n",
|
||||
"pip install neo4j\n",
|
||||
"\n",
|
||||
|
||||
"# For FalkorDB (requires Redis/FalkorDB server)\n",
|
||||
"pip install falkordb\n",
|
||||
"```\n",
|
||||
@@ -81,6 +80,15 @@
|
||||
"**Recommendation**: Use **Neo4j** for enterprise production systems or **FalkorDB** for high-performance real-time applications.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
@@ -98,25 +106,18 @@
|
||||
"source": [
|
||||
"from semantica.graph_store import GraphStore\n",
|
||||
"\n",
|
||||
"# Option 1: Neo4j (requires Neo4j server running)\n",
|
||||
"# Neo4j AuraDB Connection Details\n",
|
||||
"# Replace these values with your actual AuraDB credentials\n",
|
||||
"store = GraphStore(\n",
|
||||
" backend=\"neo4j\",\n",
|
||||
" uri=\"bolt://localhost:7687\",\n",
|
||||
" uri=\"Your URI\", # Your AuraDB Instance URI\n",
|
||||
" user=\"neo4j\",\n",
|
||||
" password=\"password\"\n",
|
||||
" password=\"Your Password\" # Please enter your password here\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Option 2: FalkorDB (requires Redis/FalkorDB server)\n",
|
||||
"# store = GraphStore(\n",
|
||||
"# backend=\"falkordb\",\n",
|
||||
"# host=\"localhost\",\n",
|
||||
"# port=6379,\n",
|
||||
"# graph_name=\"demo_graph\"\n",
|
||||
"# )\n",
|
||||
"\n",
|
||||
"# Connect to the database\n",
|
||||
"store.connect()\n",
|
||||
"print(\"Connected to graph database successfully!\")\n"
|
||||
"print(\"Connected to graph database successfully!\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -592,8 +593,22 @@
|
||||
}
|
||||
],
|
||||
"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.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -39,6 +39,15 @@
|
||||
"Analyze graph structure and properties.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -118,11 +127,15 @@
|
||||
"\n",
|
||||
"community_detector = CommunityDetector()\n",
|
||||
"\n",
|
||||
"communities = community_detector.detect_communities(kg)\n",
|
||||
"# Get detection result\n",
|
||||
"result = community_detector.detect_communities(kg)\n",
|
||||
"\n",
|
||||
"# Extract communities list from result dictionary\n",
|
||||
"communities = result.get(\"communities\", [])\n",
|
||||
"\n",
|
||||
"print(f\"Detected {len(communities)} communities\")\n",
|
||||
"for i, community in enumerate(communities[:3], 1):\n",
|
||||
" print(f\" Community {i}: {len(community)} entities\")\n"
|
||||
" print(f\" Community {i}: {len(community)} entities\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -164,13 +177,27 @@
|
||||
"- **CommunityDetector**: Detect communities in graphs\n",
|
||||
"- **ConnectivityAnalyzer**: Analyze graph connectivity\n",
|
||||
"\n",
|
||||
"Next: Learn how to assess graph quality in the Graph_Quality notebook.\n"
|
||||
"Next: Learn how to deduplicate entities in the Deduplication notebook.\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.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,178 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"**Notice**: The `semantica.kg_qa` module is temporarily unavailable and will be reintroduced in a future release. The quality assessment examples in this notebook are disabled."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/introduction/12_Graph_Quality.ipynb)\n",
|
||||
"\n",
|
||||
"# Graph Quality\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates how to assess and improve knowledge graph quality using Semantica's quality assurance modules. You'll learn to use `KGQualityAssessor`, `ConsistencyChecker`, `CompletenessValidator`, and `QualityMetrics`.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/kg_qa/)\n",
|
||||
"\n",
|
||||
"### Learning Objectives\n",
|
||||
"\n",
|
||||
"- Use `KGQualityAssessor` for overall quality assessment\n",
|
||||
"- Use `ConsistencyChecker` to validate consistency\n",
|
||||
"- Use `CompletenessValidator` to check completeness\n",
|
||||
"- Use `QualityMetrics` to calculate quality metrics\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",
|
||||
"## Step 1: Quality Assessment\n",
|
||||
"\n",
|
||||
"Assess overall graph quality.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
||||
"from semantica.kg import GraphBuilder\n",
|
||||
"\n",
|
||||
"builder = GraphBuilder()\n",
|
||||
|
||||
"\n",
|
||||
"entities = [\n",
|
||||
" {\"id\": \"e1\", \"type\": \"Organization\", \"name\": \"Apple Inc.\", \"properties\": {}}\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"relationships = []\n",
|
||||
"\n",
|
||||
"kg = builder.build(entities, relationships)\n",
|
||||
"\n",
|
||||
"quality_score = assessor.assess_overall_quality(kg)\n",
|
||||
"\n",
|
||||
"print(f\"Overall quality score: {quality_score.get('overall_score', 0):.3f}\")\n",
|
||||
"print(f\"Completeness: {quality_score.get('completeness', 0):.3f}\")\n",
|
||||
"print(f\"Consistency: {quality_score.get('consistency', 0):.3f}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Consistency Checking\n",
|
||||
"\n",
|
||||
"Check graph consistency.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
||||
"\n",
|
||||
"consistency_checker = ConsistencyChecker()\n",
|
||||
"\n",
|
||||
"consistency_result = consistency_checker.check_consistency(kg)\n",
|
||||
"\n",
|
||||
"print(f\"Consistency check:\")\n",
|
||||
"print(f\" Is consistent: {consistency_result.get('is_consistent', False)}\")\n",
|
||||
"print(f\" Issues: {len(consistency_result.get('issues', []))}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Completeness Validation\n",
|
||||
"\n",
|
||||
"Validate graph completeness.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
||||
"\n",
|
||||
"completeness_validator = CompletenessValidator()\n",
|
||||
"\n",
|
||||
"completeness_result = completeness_validator.validate_completeness(kg)\n",
|
||||
"\n",
|
||||
"print(f\"Completeness validation:\")\n",
|
||||
"print(f\" Is complete: {completeness_result.get('is_complete', False)}\")\n",
|
||||
"print(f\" Missing properties: {len(completeness_result.get('missing_properties', []))}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Quality Metrics\n",
|
||||
"\n",
|
||||
"Calculate detailed quality metrics.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
|
||||
"\n",
|
||||
"quality_metrics = QualityMetrics()\n",
|
||||
"\n",
|
||||
"metrics = quality_metrics.calculate_metrics(kg)\n",
|
||||
"\n",
|
||||
"print(f\"Quality metrics:\")\n",
|
||||
"print(f\" Entity coverage: {metrics.get('entity_coverage', 0):.3f}\")\n",
|
||||
"print(f\" Relationship coverage: {metrics.get('relationship_coverage', 0):.3f}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"You've learned how to assess graph quality:\n",
|
||||
"\n",
|
||||
"- **KGQualityAssessor**: Overall quality assessment\n",
|
||||
"- **ConsistencyChecker**: Consistency validation\n",
|
||||
"- **CompletenessValidator**: Completeness validation\n",
|
||||
"- **QualityMetrics**: Detailed quality metrics\n",
|
||||
"\n",
|
||||
"Next: Learn how to deduplicate entities in the Deduplication notebook.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -39,6 +39,15 @@
|
||||
"Generate embeddings using EmbeddingGenerator.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -133,6 +142,11 @@
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -74,6 +74,15 @@
|
||||
"- `export_relationships()` - Export relationships to JSON\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install semantica"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -166,7 +175,7 @@
|
||||
"rdf_exporter = RDFExporter()\n",
|
||||
"\n",
|
||||
"# Export to RDF format (Turtle by default)\n",
|
||||
"rdf_exporter.export_knowledge_graph(kg, \"output.ttl\", format=\"turtle\")\n"
|
||||
"rdf_exporter.export(kg, \"output.ttl\", format=\"turtle\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -237,10 +246,14 @@
|
||||
"generator = OntologyGenerator()\n",
|
||||
"\n",
|
||||
"# Generate ontology from entities and relationships\n",
|
||||
"ontology = generator.generate(entities, relationships)\n",
|
||||
"# Note: Pass data as a dictionary to generate_ontology\n",
|
||||
"ontology = generator.generate_ontology({\n",
|
||||
" \"entities\": entities,\n",
|
||||
" \"relationships\": relationships\n",
|
||||
"})\n",
|
||||
"\n",
|
||||
"# Export ontology to OWL\n",
|
||||
"owl_exporter.export(ontology, \"output.owl\")\n"
|
||||
"owl_exporter.export(ontology, \"output.owl\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -295,24 +308,6 @@
|
||||
"- `json` - JSON report\n",
|
||||
"- `text` - Plain text report\n",
|
||||
"\n",
|
||||
"## Step 7: Method Registry\n",
|
||||
"\n",
|
||||
"Register and use custom export methods using the MethodRegistry system:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"from semantica.export import MethodRegistry, method_registry, JSONExporter\n",
|
||||
"\n",
|
||||
"# Register custom method\n",
|
||||
"def my_custom_export(data, file_path, **kwargs):\n",
|
||||
" # Custom export logic\n",
|
||||
" pass\n",
|
||||
"\n",
|
||||
"MethodRegistry.register(\"json\", \"custom\", my_custom_export)\n",
|
||||
"\n",
|
||||
"# List available methods\n",
|
||||
"methods = method_registry.list_all()\n",
|
||||
"print(methods)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
@@ -348,8 +343,22 @@
|
||||
}
|
||||
],
|
||||
"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.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -37,6 +37,15 @@
|
||||
"Visualize knowledge graphs.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -q semantica"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
@@ -82,11 +91,14 @@
|
||||
"from semantica.ontology import OntologyGenerator\n",
|
||||
"\n",
|
||||
"ontology_visualizer = OntologyVisualizer()\n",
|
||||
"generator = OntologyGenerator()\n",
|
||||
"# Initialize generator with min_occurrences=1 to allow single-instance classes\n",
|
||||
"generator = OntologyGenerator(min_occurrences=1)\n",
|
||||
"\n",
|
||||
"ontology = generator.generate(entities, relationships)\n",
|
||||
"# Generate ontology using the correct method signature (dictionary input)\n",
|
||||
"ontology = generator.generate_ontology({\"entities\": entities, \"relationships\": relationships})\n",
|
||||
"\n",
|
||||
"visualization = ontology_visualizer.visualize_hierarchy(ontology, output=\"interactive\")\n"
|
||||
"# Visualize the hierarchy\n",
|
||||
"visualization = ontology_visualizer.visualize_hierarchy(ontology, output=\"interactive\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -135,50 +147,26 @@
|
||||
"source": [
|
||||
"from semantica.visualization import SemanticNetworkVisualizer\n",
|
||||
"\n",
|
||||
"# Initialize (uses new defaults: Vibrant colors, Kamada-Kawai layout)\n",
|
||||
"viz = SemanticNetworkVisualizer()\n",
|
||||
"\n",
|
||||
"# Your semantic network data\n",
|
||||
"semantic_network = {\n",
|
||||
" \"nodes\": [\n",
|
||||
" {\"id\": \"n1\", \"label\": \"Node 1\", \"type\": \"Entity\"},\n",
|
||||
" {\"id\": \"n2\", \"label\": \"Node 2\", \"type\": \"Entity\"}\n",
|
||||
" {\"id\": \"n1\", \"label\": \"Python\", \"type\": \"Language\"},\n",
|
||||
" {\"id\": \"n2\", \"label\": \"Code\", \"type\": \"Concept\"}\n",
|
||||
" ],\n",
|
||||
" \"edges\": [\n",
|
||||
" {\"source\": \"n1\", \"target\": \"n2\", \"label\": \"related_to\"}\n",
|
||||
" {\"source\": \"n1\", \"target\": \"n2\", \"label\": \"writes\"}\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"sem_viz = SemanticNetworkVisualizer()\n",
|
||||
"sem_viz.visualize_network(semantic_network, output=\"interactive\")\n",
|
||||
"sem_viz.visualize_node_types(semantic_network, output=\"interactive\")\n",
|
||||
"sem_viz.visualize_edge_types(semantic_network, output=\"interactive\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Advanced Embedding Visualization\n",
|
||||
"\n",
|
||||
"Compare multi-modal embeddings and assess embedding quality."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"from semantica.visualization import EmbeddingVisualizer\n",
|
||||
"\n",
|
||||
"# Synthetic multi-modal embeddings (text, image, audio)\n",
|
||||
"text_emb = np.random.rand(50, 128)\n",
|
||||
"image_emb = np.random.rand(50, 128)\n",
|
||||
"audio_emb = np.random.rand(50, 128)\n",
|
||||
"\n",
|
||||
"emb_viz = EmbeddingVisualizer()\n",
|
||||
"emb_viz.visualize_multimodal_comparison(text_emb, image_emb, audio_emb, output=\"interactive\")\n",
|
||||
"\n",
|
||||
"# Embedding quality metrics\n",
|
||||
"quality_fig = emb_viz.visualize_quality_metrics(text_emb, output=\"interactive\")\n"
|
||||
"# This will now display the interactive graph in the notebook cell\n",
|
||||
"viz.visualize_network(\n",
|
||||
" semantic_network, \n",
|
||||
" output=\"html\", \n",
|
||||
" file_path=\"network_graph.html\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -191,7 +179,7 @@
|
||||
"\n",
|
||||
"- **KGVisualizer**: Visualize knowledge graphs\n",
|
||||
"- **OntologyVisualizer**: Visualize ontologies\n",
|
||||
"- **EmbeddingVisualizer**: Visualize embeddings, multi-modal and quality metrics\n",
|
||||
"- **EmbeddingVisualizer**: Visualize embeddings, multi-modal\n",
|
||||
"- **SemanticNetworkVisualizer**: Visualize semantic network structure and type distributions\n",
|
||||
"\n",
|
||||
"Next: Learn how to detect conflicts in the Conflict_Detection notebook.\n"
|
||||
@@ -199,8 +187,22 @@
|
||||
}
|
||||
],
|
||||
"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.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -1,604 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/introduction/18_Conflict_Detection.ipynb)\n",
|
||||
"\n",
|
||||
"# Conflict Detection\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook demonstrates how to detect and resolve conflicts in knowledge graphs using Semantica's conflict modules. You'll learn to use `ConflictDetector`, `SourceTracker`, and `ConflictResolver`.\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/conflicts/)\n",
|
||||
"\n",
|
||||
"### Learning Objectives\n",
|
||||
"\n",
|
||||
"- Use `ConflictDetector` to detect conflicts\n",
|
||||
"- Use `SourceTracker` to track data sources\n",
|
||||
"- Use `ConflictResolver` to resolve conflicts\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",
|
||||
"## Step 1: Conflict Detection\n",
|
||||
"\n",
|
||||
"Detect conflicts in entities.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import ConflictDetector\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"# Initialize detector with configuration\n",
|
||||
"detector = ConflictDetector(\n",
|
||||
" confidence_threshold=0.7,\n",
|
||||
" track_provenance=True,\n",
|
||||
" conflict_fields={\"Company\": [\"name\", \"founded\", \"revenue\"]}\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Sample entities from multiple sources\n",
|
||||
"entities = [\n",
|
||||
" {\"id\": \"e1\", \"name\": \"Apple Inc.\", \"founded\": 1976, \"type\": \"Company\", \n",
|
||||
" \"source\": \"wikipedia\", \"confidence\": 0.9},\n",
|
||||
" {\"id\": \"e1\", \"name\": \"Apple Incorporated\", \"founded\": 1976, \"type\": \"Company\",\n",
|
||||
" \"source\": \"official_site\", \"confidence\": 0.95},\n",
|
||||
" {\"id\": \"e1\", \"name\": \"Apple Inc.\", \"founded\": 1977, \"type\": \"Company\",\n",
|
||||
" \"source\": \"news\", \"confidence\": 0.7},\n",
|
||||
" {\"id\": \"e2\", \"name\": \"Microsoft\", \"type\": \"Company\", \"founded\": 1975, \"source\": \"source1\"},\n",
|
||||
" {\"id\": \"e2\", \"name\": \"Microsoft Corporation\", \"type\": \"Organization\", \n",
|
||||
" \"founded\": 1975, \"source\": \"source2\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# 1.1 Value Conflict Detection\n",
|
||||
"value_conflicts = detector.detect_value_conflicts(entities, \"name\")\n",
|
||||
"\n",
|
||||
"# 1.2 Type Conflict Detection\n",
|
||||
"type_conflicts = detector.detect_type_conflicts(entities)\n",
|
||||
"\n",
|
||||
"# 1.3 Temporal Conflict Detection\n",
|
||||
"temporal_conflicts = detector.detect_temporal_conflicts(entities)\n",
|
||||
"\n",
|
||||
"# 1.4 Logical Conflict Detection\n",
|
||||
"logical_entities = [\n",
|
||||
" {\"id\": \"e3\", \"type\": \"Person\", \"name\": \"John Doe\", \"source\": \"source1\"},\n",
|
||||
" {\"id\": \"e3\", \"type\": \"Organization\", \"name\": \"John Doe\", \"source\": \"source2\"},\n",
|
||||
"]\n",
|
||||
"logical_conflicts = detector.detect_logical_conflicts(logical_entities)\n",
|
||||
"\n",
|
||||
"# 1.5 Relationship Conflict Detection\n",
|
||||
"relationships = [\n",
|
||||
" {\"id\": \"rel1\", \"source_id\": \"e1\", \"target_id\": \"e2\", \"type\": \"competes_with\", \"source\": \"source1\"},\n",
|
||||
" {\"id\": \"rel1\", \"source_id\": \"e1\", \"target_id\": \"e2\", \"type\": \"partners_with\", \"source\": \"source2\"},\n",
|
||||
"]\n",
|
||||
"rel_conflicts = detector.detect_relationship_conflicts(relationships)\n",
|
||||
"\n",
|
||||
"# 1.6 General Conflict Detection (all types)\n",
|
||||
"all_conflicts = detector.detect_conflicts(entities)\n",
|
||||
"\n",
|
||||
"# Get conflict report\n",
|
||||
"report = detector.get_conflict_report()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Source Tracking\n",
|
||||
"\n",
|
||||
"Track data sources.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import SourceTracker, SourceReference\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"# Initialize source tracker\n",
|
||||
"tracker = SourceTracker()\n",
|
||||
"\n",
|
||||
"# Create source references with metadata\n",
|
||||
"source1 = SourceReference(\n",
|
||||
" document=\"wikipedia\",\n",
|
||||
" page=1,\n",
|
||||
" section=\"Company Information\",\n",
|
||||
" timestamp=datetime(2023, 1, 15),\n",
|
||||
" confidence=0.9\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"source2 = SourceReference(\n",
|
||||
" document=\"official_site\",\n",
|
||||
" section=\"About Us\",\n",
|
||||
" timestamp=datetime(2023, 3, 20),\n",
|
||||
" confidence=0.95\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Track property sources\n",
|
||||
"tracker.track_property_source(\"e1\", \"name\", \"Apple Inc.\", source1)\n",
|
||||
"tracker.track_property_source(\"e1\", \"name\", \"Apple Incorporated\", source2)\n",
|
||||
"tracker.track_property_source(\"e1\", \"founded\", 1976, source1)\n",
|
||||
"\n",
|
||||
"# Track entity sources\n",
|
||||
"tracker.track_entity_source(\"e1\", source1)\n",
|
||||
"\n",
|
||||
"# Set source credibility scores\n",
|
||||
"tracker.set_source_credibility(\"wikipedia\", 0.85)\n",
|
||||
"tracker.set_source_credibility(\"official_site\", 0.95)\n",
|
||||
"\n",
|
||||
"# Retrieve property sources\n",
|
||||
"prop_source = tracker.get_property_sources(\"e1\", \"name\")\n",
|
||||
"\n",
|
||||
"# Get entity sources\n",
|
||||
"entity_sources = tracker.get_entity_sources(\"e1\")\n",
|
||||
"\n",
|
||||
"# Get all source credibilities\n",
|
||||
"all_credibilities = tracker.get_all_source_credibilities()\n",
|
||||
"\n",
|
||||
"# Generate traceability chain\n",
|
||||
"chain = tracker.generate_traceability_chain(\"e1\", \"name\")\n",
|
||||
"\n",
|
||||
"# Generate source report\n",
|
||||
"report = tracker.generate_source_report(\"e1\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Conflict Resolution\n",
|
||||
"\n",
|
||||
"Resolve conflicts using ConflictResolver.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import ConflictResolver\n",
|
||||
"\n",
|
||||
"# Initialize resolver with source tracker\n",
|
||||
"resolver = ConflictResolver(\n",
|
||||
" default_strategy=\"voting\",\n",
|
||||
" source_tracker=tracker\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Resolve conflicts using different strategies\n",
|
||||
"if value_conflicts:\n",
|
||||
" # Voting strategy\n",
|
||||
" voting_results = resolver.resolve_conflicts(value_conflicts, strategy=\"voting\")\n",
|
||||
" \n",
|
||||
" # Credibility-weighted strategy\n",
|
||||
" credibility_results = resolver.resolve_conflicts(value_conflicts, strategy=\"credibility_weighted\")\n",
|
||||
" \n",
|
||||
" # Most recent strategy\n",
|
||||
" recent_results = resolver.resolve_conflicts(value_conflicts, strategy=\"most_recent\")\n",
|
||||
" \n",
|
||||
" # Highest confidence strategy\n",
|
||||
" confidence_results = resolver.resolve_conflicts(value_conflicts, strategy=\"highest_confidence\")\n",
|
||||
" \n",
|
||||
" # First seen strategy\n",
|
||||
" first_seen_results = resolver.resolve_conflicts(value_conflicts, strategy=\"first_seen\")\n",
|
||||
" \n",
|
||||
" # Manual review strategy\n",
|
||||
" manual_results = resolver.resolve_conflicts(value_conflicts, strategy=\"manual_review\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"You've learned how to detect and resolve conflicts:\n",
|
||||
"\n",
|
||||
"- **ConflictDetector**: Detect conflicts in entities\n",
|
||||
"- **SourceTracker**: Track data sources\n",
|
||||
"- **ConflictResolver**: Resolve conflicts using various strategies\n",
|
||||
"\n",
|
||||
"Next: Learn about configuration in the Configuration notebook.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import ConflictAnalyzer\n",
|
||||
"\n",
|
||||
"# Initialize analyzer\n",
|
||||
"analyzer = ConflictAnalyzer()\n",
|
||||
"\n",
|
||||
"# Comprehensive analysis\n",
|
||||
"analysis = analyzer.analyze_conflicts(all_conflicts)\n",
|
||||
"\n",
|
||||
"# Analysis by type, severity, and source\n",
|
||||
"by_type = analysis['by_type']['counts']\n",
|
||||
"by_severity = analysis['by_severity']['counts']\n",
|
||||
"by_source = analysis['by_source']['counts']\n",
|
||||
"\n",
|
||||
"# Top entities and properties\n",
|
||||
"top_entities = analysis['by_entity']['top_entities']\n",
|
||||
"top_properties = analysis['by_property']['top_properties']\n",
|
||||
"\n",
|
||||
"# Patterns and recommendations\n",
|
||||
"patterns = analysis['patterns']\n",
|
||||
"recommendations = analysis['recommendations']\n",
|
||||
"\n",
|
||||
"# Trend analysis\n",
|
||||
"trends = analyzer.analyze_trends(all_conflicts)\n",
|
||||
"\n",
|
||||
"# Generate insights report\n",
|
||||
"insights = analyzer.generate_insights_report(all_conflicts)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 5: Investigation Guides\n",
|
||||
"\n",
|
||||
"`InvestigationGuideGenerator` creates guides for manual review.\n",
|
||||
"\n",
|
||||
"**Guide Components:**\n",
|
||||
"- Conflict summary, investigation steps, recommended actions\n",
|
||||
"- Source information, context, severity assessment\n",
|
||||
"\n",
|
||||
"**Use Cases:** High-severity conflicts, ambiguous cases, compliance, QA workflows\n",
|
||||
"\n",
|
||||
"**Export Formats:** Markdown checklists, detailed reports, structured context\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import InvestigationGuideGenerator\n",
|
||||
"\n",
|
||||
"# Initialize guide generator\n",
|
||||
"guide_generator = InvestigationGuideGenerator(source_tracker=tracker)\n",
|
||||
"\n",
|
||||
"# Generate guide for a conflict\n",
|
||||
"if value_conflicts:\n",
|
||||
" guide = guide_generator.generate_guide(value_conflicts[0])\n",
|
||||
"\n",
|
||||
"# Generate guides for multiple conflicts\n",
|
||||
"guides = guide_generator.generate_guides(value_conflicts[:3])\n",
|
||||
"\n",
|
||||
"# Export checklist\n",
|
||||
"checklist = guide_generator.export_investigation_checklist(guide, format=\"markdown\")\n",
|
||||
"\n",
|
||||
"# Generate conflict report\n",
|
||||
"conflict_report = guide_generator.generate_conflict_report(value_conflicts, format=\"detailed\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 6: Methods Module\n",
|
||||
"\n",
|
||||
"`semantica.conflicts.methods` provides convenience functions for functional-style access.\n",
|
||||
"\n",
|
||||
"**Functions:**\n",
|
||||
"- `detect_conflicts()`: Methods: `value`, `type`, `temporal`, `logical`, `relationship`\n",
|
||||
"- `resolve_conflicts()`: Methods: `voting`, `credibility_weighted`, `most_recent`, `highest_confidence`, `first_seen`, `manual_review`\n",
|
||||
"- `analyze_conflicts()`: Methods: `pattern`, `type`, `severity`, `source`, `trend`\n",
|
||||
"- `track_sources()`: Methods: `property`, `entity`, `relationship`\n",
|
||||
"- `generate_investigation_guide()`: Methods: `guide`, `checklist`, `context`\n",
|
||||
"- `list_available_methods()`: List all methods by task type\n",
|
||||
"- `get_conflict_method()`: Retrieve specific method function\n",
|
||||
"\n",
|
||||
"**Benefits:** Simpler API, method discovery, consistent interface, extensible\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts.methods import (\n",
|
||||
" detect_conflicts,\n",
|
||||
" resolve_conflicts,\n",
|
||||
" analyze_conflicts,\n",
|
||||
" track_sources,\n",
|
||||
" generate_investigation_guide,\n",
|
||||
" list_available_methods,\n",
|
||||
" get_conflict_method\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Detection methods\n",
|
||||
"value_conflicts_method = detect_conflicts(entities, method=\"value\", property_name=\"name\")\n",
|
||||
"type_conflicts_method = detect_conflicts(entities, method=\"type\")\n",
|
||||
"temporal_conflicts_method = detect_conflicts(entities, method=\"temporal\")\n",
|
||||
"logical_conflicts_method = detect_conflicts(logical_entities, method=\"logical\")\n",
|
||||
"\n",
|
||||
"# Resolution methods\n",
|
||||
"if value_conflicts_method:\n",
|
||||
" voting_results = resolve_conflicts(value_conflicts_method, method=\"voting\")\n",
|
||||
" credibility_results = resolve_conflicts(value_conflicts_method, method=\"credibility_weighted\")\n",
|
||||
"\n",
|
||||
"# Analysis methods\n",
|
||||
"pattern_analysis = analyze_conflicts(all_conflicts, method=\"pattern\")\n",
|
||||
"type_analysis = analyze_conflicts(all_conflicts, method=\"type\")\n",
|
||||
"severity_analysis = analyze_conflicts(all_conflicts, method=\"severity\")\n",
|
||||
"source_analysis = analyze_conflicts(all_conflicts, method=\"source\")\n",
|
||||
"trend_analysis = analyze_conflicts(all_conflicts, method=\"trend\")\n",
|
||||
"\n",
|
||||
"# Source tracking methods\n",
|
||||
"source_ref = SourceReference(document=\"test_source\", confidence=0.9)\n",
|
||||
"track_sources(\"e1\", method=\"property\", property_name=\"name\", value=\"Test\", source=source_ref)\n",
|
||||
"track_sources(\"e1\", method=\"entity\", source=source_ref)\n",
|
||||
"\n",
|
||||
"# Investigation guide methods\n",
|
||||
"if value_conflicts_method:\n",
|
||||
" guide_method = generate_investigation_guide(value_conflicts_method[0], method=\"guide\")\n",
|
||||
" checklist_method = generate_investigation_guide(value_conflicts_method[0], method=\"checklist\")\n",
|
||||
" context_method = generate_investigation_guide(value_conflicts_method[0], method=\"context\")\n",
|
||||
"\n",
|
||||
"# List available methods\n",
|
||||
"all_methods = list_available_methods()\n",
|
||||
"\n",
|
||||
"# Get specific method\n",
|
||||
"voting_method = get_conflict_method(\"resolution\", \"voting\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 7: Method Registry\n",
|
||||
"\n",
|
||||
"`method_registry` provides a plugin system for custom methods.\n",
|
||||
"\n",
|
||||
"**Registration:** Task type (`detection`, `resolution`, `analysis`, `tracking`, `investigation`), method name, function\n",
|
||||
"\n",
|
||||
"**Use Cases:**\n",
|
||||
"- Domain-specific resolution logic\n",
|
||||
"- External system integration\n",
|
||||
"- A/B testing strategies\n",
|
||||
"- ML model integration\n",
|
||||
"- Hybrid resolution approaches\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import method_registry, ResolutionResult\n",
|
||||
"\n",
|
||||
"# Register custom resolution method\n",
|
||||
"def custom_resolution(conflicts, **kwargs):\n",
|
||||
" \"\"\"Custom resolution that always picks the first value.\"\"\"\n",
|
||||
" results = []\n",
|
||||
" for conflict in conflicts:\n",
|
||||
" if conflict.conflicting_values:\n",
|
||||
" result = ResolutionResult(\n",
|
||||
" conflict_id=conflict.conflict_id,\n",
|
||||
" resolved=True,\n",
|
||||
" resolved_value=conflict.conflicting_values[0],\n",
|
||||
" resolution_strategy=\"custom_first\",\n",
|
||||
" confidence=0.8,\n",
|
||||
" resolution_notes=\"Custom: Always use first value\"\n",
|
||||
" )\n",
|
||||
" results.append(result)\n",
|
||||
" return results\n",
|
||||
"\n",
|
||||
"# Register the custom method\n",
|
||||
"method_registry.register(\"resolution\", \"custom_first\", custom_resolution)\n",
|
||||
"\n",
|
||||
"# List registered methods\n",
|
||||
"registered = method_registry.list_all(\"resolution\")\n",
|
||||
"\n",
|
||||
"# Use custom method\n",
|
||||
"if value_conflicts:\n",
|
||||
" custom_results = resolve_conflicts(value_conflicts, method=\"custom_first\")\n",
|
||||
"\n",
|
||||
"# Unregister method\n",
|
||||
"method_registry.unregister(\"resolution\", \"custom_first\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 8: Configuration\n",
|
||||
"\n",
|
||||
"`ConflictsConfig` manages settings programmatically, via environment variables, or method-specific.\n",
|
||||
"\n",
|
||||
"**Global Settings:**\n",
|
||||
"- `confidence_threshold`, `default_strategy`, `auto_resolve`, `track_provenance`\n",
|
||||
"\n",
|
||||
"**Method-Specific:** Voting (`min_sources`, `tie_breaker`), credibility-weighted (`min_credibility`), most_recent (`time_field`), etc.\n",
|
||||
"\n",
|
||||
"**Priority:** Method-specific → Global → Environment variables → Defaults\n",
|
||||
"\n",
|
||||
"**Best Practices:** Set source credibility early, configure conflict fields, use method-specific configs\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import ConflictsConfig, conflicts_config\n",
|
||||
"\n",
|
||||
"# Using global config instance\n",
|
||||
"conflicts_config.set(\"confidence_threshold\", 0.8)\n",
|
||||
"conflicts_config.set(\"default_strategy\", \"credibility_weighted\")\n",
|
||||
"threshold = conflicts_config.get(\"confidence_threshold\", default=0.7)\n",
|
||||
"\n",
|
||||
"# Method-specific configuration\n",
|
||||
"conflicts_config.set_method_config(\"voting\", min_sources=2, tie_breaker=\"confidence\")\n",
|
||||
"conflicts_config.set_method_config(\"credibility_weighted\", min_credibility=0.5)\n",
|
||||
"voting_config = conflicts_config.get_method_config(\"voting\")\n",
|
||||
"\n",
|
||||
"# Create custom config instance\n",
|
||||
"custom_config = ConflictsConfig()\n",
|
||||
"custom_config.set(\"confidence_threshold\", 0.9)\n",
|
||||
"custom_config.set(\"auto_resolve\", True)\n",
|
||||
"all_config = custom_config.get_all()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Part 9: Complete Workflow\n",
|
||||
"\n",
|
||||
"End-to-end example: integrating company data from multiple sources.\n",
|
||||
"\n",
|
||||
"**Workflow:** Initialize → Track Sources → Detect → Resolve → Analyze → Generate Guides → Build Final Entity\n",
|
||||
"\n",
|
||||
"**Scenario:** Three sources (Wikipedia, Official Site, Financial DB) with conflicts in name, founding year, and type classifications.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Complete workflow: Company data integration from multiple sources\n",
|
||||
"from semantica.conflicts import (\n",
|
||||
" ConflictDetector, ConflictResolver, ConflictAnalyzer,\n",
|
||||
" SourceTracker, InvestigationGuideGenerator, SourceReference\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Sample company data from multiple sources\n",
|
||||
"company_data = [\n",
|
||||
" {\"id\": \"company_1\", \"name\": \"Apple Inc.\", \"founded\": 1976, \"revenue\": 394328000000,\n",
|
||||
" \"headquarters\": \"Cupertino, California\", \"type\": \"Company\",\n",
|
||||
" \"source\": \"wikipedia\", \"confidence\": 0.85, \"timestamp\": datetime(2023, 1, 15)},\n",
|
||||
" {\"id\": \"company_1\", \"name\": \"Apple Inc.\", \"founded\": 1976, \"revenue\": 394328000000,\n",
|
||||
" \"headquarters\": \"Cupertino, CA\", \"type\": \"Company\",\n",
|
||||
" \"source\": \"official_site\", \"confidence\": 0.95, \"timestamp\": datetime(2023, 3, 20)},\n",
|
||||
" {\"id\": \"company_1\", \"name\": \"Apple Incorporated\", \"founded\": 1977, \"revenue\": 394328000000,\n",
|
||||
" \"headquarters\": \"Cupertino\", \"type\": \"Organization\",\n",
|
||||
" \"source\": \"financial_db\", \"confidence\": 0.80, \"timestamp\": datetime(2023, 2, 10)},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Initialize all components\n",
|
||||
"detector = ConflictDetector(\n",
|
||||
" confidence_threshold=0.7,\n",
|
||||
" track_provenance=True,\n",
|
||||
" conflict_fields={\"Company\": [\"name\", \"founded\", \"revenue\", \"headquarters\"]}\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"tracker = SourceTracker()\n",
|
||||
"tracker.set_source_credibility(\"wikipedia\", 0.85)\n",
|
||||
"tracker.set_source_credibility(\"official_site\", 0.95)\n",
|
||||
"tracker.set_source_credibility(\"financial_db\", 0.80)\n",
|
||||
"\n",
|
||||
"resolver = ConflictResolver(default_strategy=\"credibility_weighted\", source_tracker=tracker)\n",
|
||||
"analyzer = ConflictAnalyzer()\n",
|
||||
"guide_generator = InvestigationGuideGenerator(source_tracker=tracker)\n",
|
||||
"\n",
|
||||
"# Step 1: Track sources\n",
|
||||
"for entity in company_data:\n",
|
||||
" source_ref = SourceReference(\n",
|
||||
" document=entity[\"source\"],\n",
|
||||
" confidence=entity[\"confidence\"],\n",
|
||||
" timestamp=entity[\"timestamp\"]\n",
|
||||
" )\n",
|
||||
" tracker.track_property_source(entity[\"id\"], \"name\", entity[\"name\"], source_ref)\n",
|
||||
" tracker.track_property_source(entity[\"id\"], \"founded\", entity[\"founded\"], source_ref)\n",
|
||||
"\n",
|
||||
"# Step 2: Detect conflicts\n",
|
||||
"detected_conflicts = detector.detect_entity_conflicts(company_data, entity_type=\"Company\")\n",
|
||||
"\n",
|
||||
"# Step 3: Resolve conflicts\n",
|
||||
"resolved_data = {}\n",
|
||||
"for conflict in detected_conflicts:\n",
|
||||
" results = resolver.resolve_conflicts([conflict], strategy=\"credibility_weighted\")\n",
|
||||
" if results[0].resolved:\n",
|
||||
" resolved_data[conflict.property_name] = results[0].resolved_value\n",
|
||||
"\n",
|
||||
"# Step 4: Analyze\n",
|
||||
"analysis = analyzer.analyze_conflicts(detected_conflicts)\n",
|
||||
"\n",
|
||||
"# Step 5: Generate guides for unresolved conflicts\n",
|
||||
"unresolved = [c for c in detected_conflicts if c.property_name not in resolved_data]\n",
|
||||
"if unresolved:\n",
|
||||
" guides = guide_generator.generate_guides(unresolved)\n",
|
||||
"\n",
|
||||
"# Final resolved entity\n",
|
||||
"final_entity = {\"id\": \"company_1\", \"type\": \"Company\", **resolved_data}\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"### Key Features\n",
|
||||
"\n",
|
||||
"✅ **Detection**: Value, type, temporal, logical, relationship conflicts \n",
|
||||
"✅ **Resolution**: 6 strategies (voting, credibility-weighted, most_recent, first_seen, highest_confidence, manual_review) \n",
|
||||
"✅ **Source Tracking**: Provenance, credibility, traceability chains \n",
|
||||
"✅ **Analysis**: Patterns, trends, recommendations \n",
|
||||
"✅ **Investigation Guides**: Automated guides and checklists \n",
|
||||
"✅ **Methods Module**: Convenience functions for all operations \n",
|
||||
"✅ **Method Registry**: Custom method registration \n",
|
||||
"✅ **Configuration**: Global and method-specific settings\n",
|
||||
"\n",
|
||||
"### Best Practices\n",
|
||||
"\n",
|
||||
"1. Set source credibility before detection\n",
|
||||
"2. Choose strategies based on data characteristics\n",
|
||||
"3. Enable provenance tracking for audits\n",
|
||||
"4. Analyze patterns before resolving\n",
|
||||
"5. Use guides for high-severity conflicts\n",
|
||||
"6. Configure conflict fields to focus on critical properties\n",
|
||||
"\n",
|
||||
"### Common Patterns\n",
|
||||
"\n",
|
||||
"- **Integration**: Track → Detect → Resolve → Analyze\n",
|
||||
"- **QA**: Detect → Analyze → Generate guides → Review\n",
|
||||
"- **Auto**: Detect → Resolve → Analyze\n",
|
||||
"- **Assessment**: Track → Analyze → Adjust credibility\n",
|
||||
"\n",
|
||||
"### Next Steps\n",
|
||||
"\n",
|
||||
"- `04_Conflict_Resolution_Strategies.ipynb` - Advanced strategies\n",
|
||||
"- `06_Multi_Source_Data_Integration.ipynb` - Integration workflows\n",
|
||||
"- [API Reference](https://semantica.readthedocs.io/reference/conflicts/)\n",
|
||||
"- [Usage Guide](../semantica/conflicts/conflicts_usage.md)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,439 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Conflict Detection and Resolution\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"In modern data pipelines, especially those building Knowledge Graphs, data is often ingested from multiple heterogeneous sources (e.g., internal databases, third-party APIs, web scrapes). Discrepancies are inevitable. \n",
|
||||
"\n",
|
||||
"The **Semantica Conflict Resolution Module** (`semantica.conflicts`) provides a robust framework for managing these data inconsistencies. It is designed to ensure that your downstream applications consume only high-quality, reconciled data.\n",
|
||||
"\n",
|
||||
"### What counts as a \"conflict\"?\n",
|
||||
"\n",
|
||||
"- A conflict happens when **multiple records for the same entity** disagree on a field.\n",
|
||||
"- Semantica typically assumes each record is a dictionary with:\n",
|
||||
" - `id` (or `entity_id`): stable identifier for the entity being described\n",
|
||||
" - one or more attributes (e.g., `name`, `birth_date`, `department`)\n",
|
||||
" - `source`: where the value came from (db, scrape, api, file)\n",
|
||||
" - optional `timestamp`: when the value was observed\n",
|
||||
"- The module is source-aware: it can record **which sources contributed which values**, then resolve using strategies like voting or credibility.\n",
|
||||
"\n",
|
||||
"### Practical API notes (to avoid common mismatches)\n",
|
||||
"\n",
|
||||
"- Use `ConflictDetector.detect_value_conflicts(entities, property_name=...)` when you want to check one field.\n",
|
||||
"- Use `ConflictDetector.detect_conflicts(entities)` when you want a broader scan (value/type/temporal/etc.).\n",
|
||||
"- If you're starting from a Knowledge Graph dictionary (built via `GraphBuilder`), pull entities via `kg.get(\"entities\", [])`.\n",
|
||||
"\n",
|
||||
"### Key Capabilities\n",
|
||||
"\n",
|
||||
"1. **Multi-Dimensional Conflict Detection**\n",
|
||||
" * **Value Conflicts**: Different values for the same property (e.g., `\"Google\"` vs `\"Google Inc.\"`).\n",
|
||||
" * **Type Conflicts**: Data type mismatches (e.g., string vs integer).\n",
|
||||
" * **Temporal Conflicts**: Chronological inconsistencies (e.g., a `start_date` after an `end_date`).\n",
|
||||
"\n",
|
||||
"2. **Provenance & Source Tracking**\n",
|
||||
" * **Granular Tracking**: Trace every property value back to its specific source document, page, or API call.\n",
|
||||
" * **Credibility Scoring**: Assign trust scores to sources (e.g., `0.95` for internal HR DB vs `0.60` for web scrapes).\n",
|
||||
"\n",
|
||||
"3. **Automated Resolution Strategies**\n",
|
||||
" * **Voting**: Majority rules (useful for multiple equal-weight sources).\n",
|
||||
" * **Credibility Weighted**: Values from higher-trust sources override others.\n",
|
||||
" * **Recency**: The most recent data point wins.\n",
|
||||
" * **Expert Review**: Flag complex conflicts for human intervention.\n",
|
||||
"\n",
|
||||
"4. **Investigation & Auditing**\n",
|
||||
" * **Investigation Guides**: Auto-generate step-by-step guides for human analysts to resolve sticky conflicts.\n",
|
||||
" * **Audit Trails**: Keep a record of how every conflict was resolved for compliance.\n",
|
||||
"\n",
|
||||
"## Installation\n",
|
||||
"\n",
|
||||
"Ensure Semantica is installed in your environment:\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"pip install semantica\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"- If you're running this notebook inside the Semantica repo, prefer an editable install (so changes in code are reflected immediately):\n",
|
||||
" - `pip install -e .`\n",
|
||||
"- If you're using a hosted notebook environment, `%pip install semantica` is often more reliable than `!pip install ...` because it installs into the active kernel."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install -q semantica "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"from datetime import datetime"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 1: Simulating Multi-Source Data\n",
|
||||
"\n",
|
||||
"To demonstrate the framework, we will simulate a realistic scenario involving employee data.\n",
|
||||
"\n",
|
||||
"**The Scenario:**\n",
|
||||
"We have received records for **Employee 001** from three distinct sources:\n",
|
||||
"\n",
|
||||
"- **HR Database**: Highly trusted internal source.\n",
|
||||
"- **LinkedIn Scrape**: Less reliable external source.\n",
|
||||
"- **Public Directory**: Outdated public API.\n",
|
||||
"\n",
|
||||
"**The record shape (what Semantica expects):**\n",
|
||||
"\n",
|
||||
"- Each record is a dictionary describing the same entity (`id`: `emp_001`).\n",
|
||||
"- Each record includes a `source` key so conflicts can be attributed.\n",
|
||||
"- A `timestamp` lets you apply time-based resolution strategies (e.g., most recent wins).\n",
|
||||
"\n",
|
||||
"**The Conflicts:**\n",
|
||||
"* **`birth_date`**: The Public Directory lists a different year.\n",
|
||||
"* **`department`**: LinkedIn uses a more specific name (\"Software Engineering\") vs the generic \"Engineering\" in the HR DB."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# 1. Define source metadata\n",
|
||||
"sources_metadata = {\n",
|
||||
" \"hr_db\": {\"credibility\": 0.95, \"type\": \"internal_database\"},\n",
|
||||
" \"linkedin_scrape\": {\"credibility\": 0.60, \"type\": \"web_scrape\"},\n",
|
||||
" \"public_dir\": {\"credibility\": 0.40, \"type\": \"public_api\"}\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# 2. Define entity records from these sources\n",
|
||||
"entity_records = [\n",
|
||||
" {\n",
|
||||
" \"id\": \"emp_001\",\n",
|
||||
" \"name\": \"John Doe\",\n",
|
||||
" \"birth_date\": \"1980-05-15\",\n",
|
||||
" \"department\": \"Engineering\",\n",
|
||||
" \"source\": \"hr_db\",\n",
|
||||
" \"timestamp\": \"2023-01-01T10:00:00\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"emp_001\",\n",
|
||||
" \"name\": \"Jonathan Doe\",\n",
|
||||
" \"birth_date\": \"1980-05-15\",\n",
|
||||
" \"department\": \"Software Engineering\",\n",
|
||||
" \"source\": \"linkedin_scrape\",\n",
|
||||
" \"timestamp\": \"2023-06-15T14:30:00\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"emp_001\",\n",
|
||||
" \"name\": \"John Doe\",\n",
|
||||
" \"birth_date\": \"1982-05-15\", # Conflict: Different year\n",
|
||||
" \"department\": \"Engineering\",\n",
|
||||
" \"source\": \"public_dir\",\n",
|
||||
" \"timestamp\": \"2022-12-01T09:00:00\"\n",
|
||||
" }\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"print(f\"Loaded {len(entity_records)} records for Employee 001\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Registering and Tracking Sources\n",
|
||||
"\n",
|
||||
"Before we can effectively resolve conflicts based on trust, we must register our sources with the `SourceTracker`.\n",
|
||||
"\n",
|
||||
"The `SourceTracker` acts as a central registry for:\n",
|
||||
"\n",
|
||||
"- **Credibility Scores**: How much you trust the source.\n",
|
||||
"- **Metadata**: Helpful context (e.g., source type, system of record vs scrape).\n",
|
||||
"\n",
|
||||
"**How to think about credibility scores:**\n",
|
||||
"\n",
|
||||
"- Use scores as a *relative ordering* (the exact decimals matter less than the ranking).\n",
|
||||
"- Start simple: `internal_db > vendor_api > web_scrape`.\n",
|
||||
"- Revisit scores later using analytics (e.g., \"which sources are frequently wrong?\").\n",
|
||||
"\n",
|
||||
"We iterate through our simulated sources and register them."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import SourceTracker\n",
|
||||
"\n",
|
||||
"source_tracker = SourceTracker()\n",
|
||||
"\n",
|
||||
"print(\"Registering sources...\")\n",
|
||||
"for source_id, metadata in sources_metadata.items():\n",
|
||||
" source_tracker.register_source(\n",
|
||||
" source_id=source_id,\n",
|
||||
" source_type=metadata[\"type\"],\n",
|
||||
" credibility_score=metadata[\"credibility\"]\n",
|
||||
" )\n",
|
||||
" print(f\" - Registered '{source_id}' with credibility {metadata['credibility']}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Detecting Conflicts\n",
|
||||
"\n",
|
||||
"We use the `ConflictDetector` to scan our records for discrepancies. \n",
|
||||
"\n",
|
||||
"The detector is flexible and can be configured to check:\n",
|
||||
"\n",
|
||||
"- **Specific properties**: Check only critical fields like `birth_date`.\n",
|
||||
"- **Entity-wide scans**: Scan many properties (or all) for an entity.\n",
|
||||
"\n",
|
||||
"**What you get back:**\n",
|
||||
"\n",
|
||||
"- A list of `Conflict` objects.\n",
|
||||
"- Useful fields you’ll typically inspect:\n",
|
||||
" - `conflict_type` (e.g., `value_conflict`)\n",
|
||||
" - `entity_id`, `property_name`\n",
|
||||
" - `conflicting_values` and `sources`\n",
|
||||
" - `severity` and `confidence`\n",
|
||||
"\n",
|
||||
"Here, we explicitly check `birth_date` and `department`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import ConflictDetector\n",
|
||||
"\n",
|
||||
"# Initialize detector with our populated source tracker\n",
|
||||
"detector = ConflictDetector(source_tracker=source_tracker)\n",
|
||||
"\n",
|
||||
"conflicts = []\n",
|
||||
"\n",
|
||||
"# 1. Check birth_date\n",
|
||||
"dob_conflicts = detector.detect_value_conflicts(entity_records, \"birth_date\")\n",
|
||||
"conflicts.extend(dob_conflicts)\n",
|
||||
"\n",
|
||||
"# 2. Check department\n",
|
||||
"dept_conflicts = detector.detect_value_conflicts(entity_records, \"department\")\n",
|
||||
"conflicts.extend(dept_conflicts)\n",
|
||||
"\n",
|
||||
"print(f\"Detected {len(conflicts)} conflicts:\")\n",
|
||||
"for conflict in conflicts:\n",
|
||||
" print(f\"- {conflict.conflict_type.value}: {conflict.property_name} for {conflict.entity_id}\")\n",
|
||||
" print(f\" Values: {conflict.conflicting_values}\")\n",
|
||||
" print(f\" Severity: {conflict.severity}\")\n",
|
||||
" print(\"--- \")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Analyzing Conflict Patterns\n",
|
||||
"\n",
|
||||
"When dealing with large datasets, individual conflicts are less important than systemic patterns. The `ConflictAnalyzer` helps answer questions like:\n",
|
||||
"\n",
|
||||
"- \"Is one specific source responsible for most conflicts?\"\n",
|
||||
"- \"Are conflicts concentrated in a specific entity type or property?\"\n",
|
||||
"- \"What is the distribution of conflict severity and conflict types?\"\n",
|
||||
"\n",
|
||||
"**How to use this in a pipeline:**\n",
|
||||
"\n",
|
||||
"- Run analysis to identify noisy sources.\n",
|
||||
"- Use results to adjust credibility scores (Step 2) or refine ingestion/cleaning rules.\n",
|
||||
"- Track trends over time to catch regressions in upstream systems."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import ConflictAnalyzer\n",
|
||||
"\n",
|
||||
"analyzer = ConflictAnalyzer()\n",
|
||||
"analysis = analyzer.analyze_conflicts(conflicts)\n",
|
||||
"\n",
|
||||
"print(\"Conflict Analysis Summary:\")\n",
|
||||
"print(f\"Total Conflicts: {analysis['total_conflicts']}\")\n",
|
||||
"print(f\"By Type: {analysis.get('by_type', {}).get('counts')}\")\n",
|
||||
"print(f\"By Severity: {analysis.get('by_severity', {}).get('counts')}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Resolving Conflicts\n",
|
||||
"\n",
|
||||
"This is the critical step where we decide which value to trust. Semantica offers flexible resolution strategies.\n",
|
||||
"\n",
|
||||
"### Strategy A: Voting (Majority Rules)\n",
|
||||
"This strategy selects the value that appears most frequently. It is simple but treats all sources as equal.\n",
|
||||
"\n",
|
||||
"- Best when you have many independent sources of similar quality.\n",
|
||||
"- Less suitable if you have a single system-of-record that should always dominate.\n",
|
||||
"\n",
|
||||
"### Strategy B: Credibility Weighted\n",
|
||||
"This strategy calculates a weighted score for each value based on the `credibility` of its source. \n",
|
||||
"\n",
|
||||
"**Example:**\n",
|
||||
"* `hr_db` (0.95) says \"1980-05-15\"\n",
|
||||
"* `public_dir` (0.40) says \"1982-05-15\"\n",
|
||||
"\n",
|
||||
"Even if multiple low-quality sources agreed on the wrong date, the high-credibility source would likely win.\n",
|
||||
"\n",
|
||||
"**What the resolver returns:**\n",
|
||||
"\n",
|
||||
"- A list of resolution results where each item typically includes:\n",
|
||||
" - whether it was resolved\n",
|
||||
" - the chosen value (`resolved_value`)\n",
|
||||
" - a confidence score\n",
|
||||
" - metadata (like the property name) to support audit trails\n",
|
||||
"\n",
|
||||
"Run the next cell to compare voting vs credibility-weighted outcomes."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import ConflictResolver\n",
|
||||
"\n",
|
||||
"resolver = ConflictResolver()\n",
|
||||
"\n",
|
||||
"# CRITICAL: Link the source tracker to the resolver.\n",
|
||||
"# This allows the resolver to look up the credibility scores we registered in Step 2.\n",
|
||||
"resolver.set_source_tracker(source_tracker)\n",
|
||||
"\n",
|
||||
"print(\"--- Resolution: Voting ---\")\n",
|
||||
"voting_results = resolver.resolve_conflicts(conflicts, strategy=\"voting\")\n",
|
||||
"for res in voting_results:\n",
|
||||
" print(f\"Property: {res.metadata.get('property_name'):<15} | Resolved Value: {res.resolved_value}\")\n",
|
||||
"\n",
|
||||
"print(\"\\n--- Resolution: Credibility Weighted ---\")\n",
|
||||
"# Notice how the HR DB's value is preferred due to higher credibility\n",
|
||||
"credibility_results = resolver.resolve_conflicts(conflicts, strategy=\"credibility_weighted\")\n",
|
||||
"for res in credibility_results:\n",
|
||||
" print(f\"Property: {res.metadata.get('property_name'):<15} | Resolved Value: {res.resolved_value} (Confidence: {res.confidence:.2f})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 6: Generating Investigation Guides\n",
|
||||
"\n",
|
||||
"Not all conflicts can be resolved automatically. High-stakes or low-confidence resolutions require human review.\n",
|
||||
"\n",
|
||||
"The `InvestigationGuideGenerator` produces a structured \"flight plan\" for an analyst, detailing:\n",
|
||||
"\n",
|
||||
"- **What** is in conflict (entity + field + competing values).\n",
|
||||
"- **Who** is involved (which sources produced which values).\n",
|
||||
"- **How** to verify the correct data (actionable steps an analyst can follow).\n",
|
||||
"\n",
|
||||
"**When to generate guides:**\n",
|
||||
"\n",
|
||||
"- Low-confidence resolutions.\n",
|
||||
"- Conflicts on critical fields (identity, legal names, compliance attributes).\n",
|
||||
"- Any time you want a human-in-the-loop checkpoint before writing back to the graph."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.conflicts import InvestigationGuideGenerator\n",
|
||||
"\n",
|
||||
"guide_generator = InvestigationGuideGenerator()\n",
|
||||
"\n",
|
||||
"# Generate a guide for the first conflict (birth_date)\n",
|
||||
"guide = guide_generator.generate_guide(conflicts[0])\n",
|
||||
"\n",
|
||||
"print(f\"=== {guide.title} ===\")\n",
|
||||
"print(f\"Summary: {guide.conflict_summary}\\n\")\n",
|
||||
"\n",
|
||||
"print(\"Investigation Steps:\")\n",
|
||||
"for i, step in enumerate(guide.investigation_steps, 1):\n",
|
||||
" print(f\"{i}. {step.description}\")\n",
|
||||
" print(f\" Action: {step.action}\")\n",
|
||||
"\n",
|
||||
"print(\"\\nRecommended Actions:\")\n",
|
||||
"for action in guide.recommended_actions:\n",
|
||||
" print(f\"[ ] {action}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Conclusion\n",
|
||||
"\n",
|
||||
"You have successfully built a conflict resolution pipeline using Semantica! \n",
|
||||
"\n",
|
||||
"**Recap of what we achieved:**\n",
|
||||
"\n",
|
||||
"- **Simulated** multi-source entity records with realistic disagreements.\n",
|
||||
"- **Registered** sources with credibility scores to create a trust hierarchy.\n",
|
||||
"- **Detected** value conflicts for specific properties.\n",
|
||||
"- **Analyzed** conflicts to understand distribution by type and severity.\n",
|
||||
"- **Resolved** conflicts using voting and credibility-weighted strategies.\n",
|
||||
"- **Generated** an investigation guide to support human review.\n",
|
||||
"\n",
|
||||
"**Suggested next steps in a real project:**\n",
|
||||
"\n",
|
||||
"- Integrate with your ingestion layer so each extracted value includes a `source` and (ideally) a `timestamp`.\n",
|
||||
"- Expand detection beyond value conflicts using `ConflictDetector.detect_conflicts(...)`.\n",
|
||||
"- Store resolutions and guide outputs to build an audit trail for downstream consumers."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -6,134 +6,17 @@
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/introduction/18_Deduplication.ipynb)\n",
|
||||
"\n",
|
||||
"# Deduplication Module\n",
|
||||
"# Deduplication in Semantica\n",
|
||||
"\n",
|
||||
"## What is the Deduplication Module?\n",
|
||||
"Welcome to the **Deduplication** walkthrough! In any Knowledge Graph, data often comes from multiple sources, leading to duplicate entities (e.g., \"Apple Inc.\" vs. \"Apple Inc\"). \n",
|
||||
"\n",
|
||||
"The Deduplication Module is a comprehensive system for identifying and merging duplicate entities in knowledge graphs. It helps maintain data quality by detecting semantically similar entities, calculating similarity scores, and merging duplicates into canonical representations while preserving provenance and handling conflicts.\n",
|
||||
"Semantica provides a robust **Deduplication Module** to help you:\n",
|
||||
"1. **Calculate Similarity**: Compare entities using strings, properties, and embeddings.\n",
|
||||
"2. **Detect Duplicates**: Find pairs or groups of entities that represent the same real-world object.\n",
|
||||
"3. **Cluster Entities**: Group similar entities together.\n",
|
||||
"4. **Merge Entities**: Combine duplicates into a single, canonical entity while resolving conflicts.\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/deduplication/)\n",
|
||||
"\n",
|
||||
"## Module Capabilities\n",
|
||||
"\n",
|
||||
"### Core Functionality\n",
|
||||
"\n",
|
||||
"1. **Similarity Calculation**\n",
|
||||
" - Multiple algorithms: Exact matching, Levenshtein distance, Jaro-Winkler, Cosine similarity, Jaccard similarity\n",
|
||||
" - Multi-factor aggregation: Combines string, property, relationship, and embedding similarity\n",
|
||||
" - Configurable weights for different similarity components\n",
|
||||
" - Batch processing for efficient pairwise comparisons\n",
|
||||
"\n",
|
||||
"2. **Duplicate Detection**\n",
|
||||
" - Pairwise comparison: Compare all entity pairs for duplicates\n",
|
||||
" - Group detection: Find clusters of duplicates using Union-Find algorithm\n",
|
||||
" - Incremental detection: Efficiently detect duplicates between new and existing entities\n",
|
||||
" - Confidence scoring: Multi-factor confidence calculation (similarity + name match + property matches)\n",
|
||||
" - Relationship duplicate detection: Identify duplicate relationships\n",
|
||||
"\n",
|
||||
"3. **Entity Merging**\n",
|
||||
" - Multiple merge strategies: Keep first, last, most complete, highest confidence, or merge all\n",
|
||||
" - Automatic duplicate detection before merging\n",
|
||||
" - Conflict resolution: Handle property and relationship conflicts\n",
|
||||
" - Provenance preservation: Track which entities were merged\n",
|
||||
" - Merge history: Maintain record of all merge operations\n",
|
||||
" - Quality validation: Validate merged entities for completeness\n",
|
||||
"\n",
|
||||
"4. **Clustering**\n",
|
||||
" - Graph-based clustering: Union-Find algorithm for connected components\n",
|
||||
" - Hierarchical clustering: Agglomerative clustering for large datasets\n",
|
||||
" - Cluster quality metrics: Cohesion and separation measures\n",
|
||||
" - Incremental updates: Update clusters with new entities\n",
|
||||
"\n",
|
||||
"5. **Advanced Features**\n",
|
||||
" - Property-specific merge rules: Different strategies for different properties\n",
|
||||
" - Custom conflict resolution: Define custom functions for resolving conflicts\n",
|
||||
" - Method registry: Register and use custom deduplication methods\n",
|
||||
" - Configuration management: Centralized configuration from multiple sources\n",
|
||||
" - Extensibility: Add custom similarity, detection, merge, and clustering methods\n",
|
||||
"\n",
|
||||
"## Module Architecture\n",
|
||||
"\n",
|
||||
"### Main Components\n",
|
||||
"\n",
|
||||
"**Core Classes:**\n",
|
||||
"- `DuplicateDetector`: Detects duplicate entities and relationships\n",
|
||||
"- `EntityMerger`: Merges duplicate entities with configurable strategies\n",
|
||||
"- `SimilarityCalculator`: Calculates multi-factor similarity between entities\n",
|
||||
"- `ClusterBuilder`: Builds clusters for efficient batch deduplication\n",
|
||||
"- `MergeStrategyManager`: Manages merge strategies and conflict resolution\n",
|
||||
"- `MethodRegistry`: Registry for custom deduplication methods\n",
|
||||
"- `DeduplicationConfig`: Centralized configuration management\n",
|
||||
"\n",
|
||||
"**Data Structures:**\n",
|
||||
"- `DuplicateCandidate`: Duplicate pair with confidence scores\n",
|
||||
"- `DuplicateGroup`: Group of duplicate entities\n",
|
||||
"- `MergeOperation`: Merge operation record with metadata\n",
|
||||
"- `SimilarityResult`: Similarity calculation result with components\n",
|
||||
"- `Cluster`: Entity cluster representation\n",
|
||||
"- `ClusterResult`: Cluster building result with quality metrics\n",
|
||||
"- `MergeResult`: Merge operation result with conflicts\n",
|
||||
"- `MergeStrategy`: Enumeration of merge strategies\n",
|
||||
"\n",
|
||||
"**Convenience Functions:**\n",
|
||||
"- `detect_duplicates()`: Duplicate detection wrapper\n",
|
||||
"- `merge_entities()`: Entity merging wrapper\n",
|
||||
"- `calculate_similarity()`: Similarity calculation wrapper\n",
|
||||
"- `build_clusters()`: Cluster building wrapper\n",
|
||||
"- `get_deduplication_method()`: Get method by name\n",
|
||||
"- `list_available_methods()`: List all available methods\n",
|
||||
"\n",
|
||||
"## Algorithms Used\n",
|
||||
"\n",
|
||||
"**Similarity Calculation:**\n",
|
||||
"- Levenshtein Distance: Dynamic programming for edit distance\n",
|
||||
"- Jaro Similarity: Character-based similarity with match window\n",
|
||||
"- Jaro-Winkler: Jaro with prefix bonus (up to 4 characters)\n",
|
||||
"- Cosine Similarity: Vector dot product for embeddings\n",
|
||||
"- Jaccard Similarity: Intersection over union for sets\n",
|
||||
"- Multi-factor Aggregation: Weighted sum of similarity components\n",
|
||||
"\n",
|
||||
"**Duplicate Detection:**\n",
|
||||
"- Pairwise Comparison: O(n²) all-pairs similarity calculation\n",
|
||||
"- Union-Find Algorithm: Disjoint set union for group formation\n",
|
||||
"- Confidence Scoring: Multi-factor confidence calculation\n",
|
||||
"- Incremental Processing: O(n×m) efficient new vs existing comparison\n",
|
||||
"\n",
|
||||
"**Clustering:**\n",
|
||||
"- Union-Find (DSU): Connected component detection\n",
|
||||
"- Hierarchical Clustering: Agglomerative bottom-up clustering\n",
|
||||
"- Similarity Graph: Graph construction from similarity scores\n",
|
||||
"\n",
|
||||
"**Entity Merging:**\n",
|
||||
"- Strategy Pattern: Multiple merge strategies\n",
|
||||
"- Conflict Resolution: Voting, credibility-weighted, temporal, confidence-based\n",
|
||||
"- Property Merging: Rule-based property combination\n",
|
||||
"- Provenance Tracking: Metadata preservation during merges\n",
|
||||
"\n",
|
||||
"## Installation\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"pip install semantica\n",
|
||||
"# Or with all optional dependencies:\n",
|
||||
"pip install semantica[all]\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"## Table of Contents\n",
|
||||
"\n",
|
||||
"1. [Module Overview](#module-overview)\n",
|
||||
"2. [Setup and Sample Data](#setup)\n",
|
||||
"3. [Similarity Calculation](#similarity)\n",
|
||||
"4. [Duplicate Detection](#detection)\n",
|
||||
"5. [Entity Merging](#merging)\n",
|
||||
"6. [Clustering](#clustering)\n",
|
||||
"7. [Advanced Features](#advanced)\n",
|
||||
"8. [Complete Workflow](#workflow)\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Module Overview {#module-overview}\n",
|
||||
"\n",
|
||||
"The deduplication module provides a complete solution for maintaining clean knowledge graphs by identifying and merging duplicate entities. It supports multiple similarity algorithms, detection methods, merge strategies, and clustering approaches, making it suitable for various use cases from simple exact matching to advanced semantic deduplication.\n"
|
||||
"This notebook will guide you through each step with clear examples."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -142,101 +25,93 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Import all deduplication classes\n",
|
||||
"from semantica.deduplication import (\n",
|
||||
" # Main Classes\n",
|
||||
" DuplicateDetector,\n",
|
||||
" EntityMerger,\n",
|
||||
" SimilarityCalculator,\n",
|
||||
" ClusterBuilder,\n",
|
||||
" MergeStrategyManager,\n",
|
||||
" MethodRegistry,\n",
|
||||
" DeduplicationConfig,\n",
|
||||
" # Data Classes\n",
|
||||
" DuplicateCandidate,\n",
|
||||
" DuplicateGroup,\n",
|
||||
" MergeOperation,\n",
|
||||
" SimilarityResult,\n",
|
||||
" Cluster,\n",
|
||||
" ClusterResult,\n",
|
||||
" MergeResult,\n",
|
||||
" MergeStrategy,\n",
|
||||
" # Global Instances\n",
|
||||
" method_registry,\n",
|
||||
" dedup_config,\n",
|
||||
")\n",
|
||||
"# Install Semantica\n",
|
||||
"!pip install -q semantica"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. Preparing Sample Data\n",
|
||||
"\n",
|
||||
"# Create sample entities with potential duplicates\n",
|
||||
"Let's create a dataset with some intentional duplicates. We'll simulate data coming from different sources (e.g., a CRM and a public database).\n",
|
||||
"\n",
|
||||
"**Our Entities:**\n",
|
||||
"- **Apple**: Variations like \"Apple Inc.\", \"Apple Inc\", and just \"Apple\".\n",
|
||||
"- **Microsoft**: Variations like \"Microsoft Corp\" and \"Microsoft\".\n",
|
||||
"- **Google**: A unique entity for control."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"entities = [\n",
|
||||
" # Apple Variations\n",
|
||||
" {\n",
|
||||
" \"id\": \"e1\",\n",
|
||||
" \"name\": \"Apple Inc.\",\n",
|
||||
" \"type\": \"Company\",\n",
|
||||
" \"founded\": 1976,\n",
|
||||
" \"properties\": {\"industry\": \"Technology\", \"headquarters\": \"Cupertino\"},\n",
|
||||
" \"relationships\": [{\"subject\": \"e1\", \"predicate\": \"founded_by\", \"object\": \"Steve Jobs\"}],\n",
|
||||
" \"properties\": {\"industry\": \"Technology\", \"hq\": \"Cupertino\", \"founded\": 1976},\n",
|
||||
" \"relationships\": [{\"predicate\": \"founded_by\", \"object\": \"Steve Jobs\"}]\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"e2\",\n",
|
||||
" \"name\": \"Apple Inc\",\n",
|
||||
" \"type\": \"Company\",\n",
|
||||
" \"founded\": 1976,\n",
|
||||
" \"properties\": {\"industry\": \"Tech\", \"headquarters\": \"Cupertino, CA\"},\n",
|
||||
" \"relationships\": [{\"subject\": \"e2\", \"predicate\": \"founded_by\", \"object\": \"Steve Jobs\"}],\n",
|
||||
" \"properties\": {\"industry\": \"Tech\", \"hq\": \"Cupertino, CA\"}, # Slightly different properties\n",
|
||||
" \"relationships\": []\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"e3\",\n",
|
||||
" \"name\": \"Microsoft Corporation\",\n",
|
||||
" \"name\": \"Apple\",\n",
|
||||
" \"type\": \"Company\",\n",
|
||||
" \"founded\": 1975,\n",
|
||||
" \"properties\": {\"industry\": \"Technology\", \"headquarters\": \"Redmond\"},\n",
|
||||
" \"properties\": {\"industry\": \"Consumer Electronics\"}, \n",
|
||||
" \"relationships\": [{\"predicate\": \"ceo\", \"object\": \"Tim Cook\"}]\n",
|
||||
" },\n",
|
||||
" \n",
|
||||
" # Microsoft Variations\n",
|
||||
" {\n",
|
||||
" \"id\": \"e4\",\n",
|
||||
" \"name\": \"Microsoft\",\n",
|
||||
" \"name\": \"Microsoft Corp\",\n",
|
||||
" \"type\": \"Company\",\n",
|
||||
" \"founded\": 1975,\n",
|
||||
" \"properties\": {\"industry\": \"Tech\", \"headquarters\": \"Redmond, WA\"},\n",
|
||||
" \"properties\": {\"industry\": \"Software\", \"hq\": \"Redmond\"}\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"e5\",\n",
|
||||
" \"name\": \"Microsoft\",\n",
|
||||
" \"type\": \"Company\",\n",
|
||||
" \"properties\": {\"industry\": \"Tech\", \"hq\": \"Redmond, WA\"}\n",
|
||||
" },\n",
|
||||
" \n",
|
||||
" # Unique Entity\n",
|
||||
" {\n",
|
||||
" \"id\": \"e6\",\n",
|
||||
" \"name\": \"Google LLC\",\n",
|
||||
" \"type\": \"Company\",\n",
|
||||
" \"founded\": 1998,\n",
|
||||
" \"properties\": {\"industry\": \"Technology\"},\n",
|
||||
" },\n",
|
||||
" \"properties\": {\"industry\": \"Internet\"}\n",
|
||||
" }\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"print(f\"Created {len(entities)} sample entities\")\n",
|
||||
"print(\"\\nEntity names:\")\n",
|
||||
"for e in entities:\n",
|
||||
" print(f\" - {e['name']} (ID: {e['id']})\")\n"
|
||||
"print(f\"Created {len(entities)} sample entities.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"## 2. Similarity Calculation\n",
|
||||
"\n",
|
||||
"## Similarity Calculation {#similarity}\n",
|
||||
"The `SimilarityCalculator` is the core engine. It compares two entities and returns a score between 0 and 1. It looks at:\n",
|
||||
"- **String Similarity**: Names and text fields.\n",
|
||||
"- **Property Similarity**: Overlap in key-value pairs.\n",
|
||||
"- **Relationship Similarity**: Connections to other entities.\n",
|
||||
"- **Embeddings**: Semantic vector similarity (if available).\n",
|
||||
"\n",
|
||||
"The module provides multiple algorithms for calculating similarity between entities. Similarity is the foundation of duplicate detection.\n",
|
||||
"\n",
|
||||
"### Available Similarity Methods\n",
|
||||
"\n",
|
||||
"1. **Exact Matching**: Binary match/no-match for identical strings\n",
|
||||
"2. **Levenshtein Distance**: Edit distance between strings (insertions, deletions, substitutions)\n",
|
||||
"3. **Jaro-Winkler**: Character-based similarity with prefix bonus for common prefixes\n",
|
||||
"4. **Cosine Similarity**: Vector similarity for embeddings using dot product\n",
|
||||
"5. **Jaccard Similarity**: Set-based similarity (intersection over union)\n",
|
||||
"6. **Property Similarity**: Weighted comparison of property values\n",
|
||||
"7. **Relationship Similarity**: Jaccard similarity of relationship sets\n",
|
||||
"8. **Multi-factor Similarity**: Weighted aggregation of all components\n",
|
||||
"\n",
|
||||
"### SimilarityCalculator Class\n",
|
||||
"\n",
|
||||
"The `SimilarityCalculator` class provides a unified interface for all similarity calculations with configurable weights for different components.\n"
|
||||
"You can customize the weights for each factor."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -245,144 +120,39 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"### Example: Duplicate Detection\n",
|
||||
"\n",
|
||||
"# Initialize DuplicateDetector\n",
|
||||
"detector = DuplicateDetector(\n",
|
||||
" similarity_threshold=0.7,\n",
|
||||
" confidence_threshold=0.6,\n",
|
||||
" use_clustering=True,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Detect duplicate candidates (pairwise)\n",
|
||||
"candidates = detector.detect_duplicates(entities)\n",
|
||||
"print(f\"Found {len(candidates)} duplicate candidate(s)\")\n",
|
||||
"for candidate in candidates:\n",
|
||||
" print(f\" {candidate.entity1['name']} <-> {candidate.entity2['name']}\")\n",
|
||||
" print(f\" Similarity: {candidate.similarity_score:.3f}, Confidence: {candidate.confidence:.3f}\")\n",
|
||||
"\n",
|
||||
"# Detect duplicate groups\n",
|
||||
"duplicate_groups = detector.detect_duplicate_groups(entities)\n",
|
||||
"print(f\"\\nFound {len(duplicate_groups)} duplicate group(s)\")\n",
|
||||
"for i, group in enumerate(duplicate_groups, 1):\n",
|
||||
" print(f\" Group {i}: {[e['name'] for e in group.entities]} (confidence: {group.confidence:.3f})\")\n",
|
||||
"\n",
|
||||
"# Incremental detection\n",
|
||||
"existing_entities = entities[:3]\n",
|
||||
"new_entities = entities[3:]\n",
|
||||
"incremental_candidates = detector.incremental_detect(new_entities, existing_entities, threshold=0.7)\n",
|
||||
"print(f\"\\nFound {len(incremental_candidates)} incremental duplicate(s)\")\n",
|
||||
"for candidate in incremental_candidates:\n",
|
||||
" print(f\" {candidate.entity1['name']} duplicates {candidate.entity2['name']} (confidence: {candidate.confidence:.3f})\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Duplicate Detection {#detection}\n",
|
||||
"\n",
|
||||
"The module detects duplicate entities using similarity metrics and confidence scoring. Detection can be performed pairwise, in groups, or incrementally.\n",
|
||||
"\n",
|
||||
"### Detection Methods\n",
|
||||
"\n",
|
||||
"1. **Pairwise Detection**: Compare all entity pairs (O(n²) complexity)\n",
|
||||
"2. **Group Detection**: Find clusters of duplicates using Union-Find algorithm\n",
|
||||
"3. **Incremental Detection**: Efficiently detect duplicates between new and existing entities (O(n×m))\n",
|
||||
"4. **Relationship Detection**: Identify duplicate relationships\n",
|
||||
"\n",
|
||||
"### Confidence Scoring\n",
|
||||
"\n",
|
||||
"The module calculates confidence scores using multiple factors:\n",
|
||||
"- Similarity score between entities\n",
|
||||
"- Name matching (exact or fuzzy)\n",
|
||||
"- Property value matches\n",
|
||||
"- Entity type matches\n",
|
||||
"- Relationship overlap\n",
|
||||
"\n",
|
||||
"### DuplicateDetector Class\n",
|
||||
"\n",
|
||||
"The `DuplicateDetector` class provides all duplicate detection capabilities with configurable thresholds and clustering options.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"### Example: Similarity Calculation\n",
|
||||
"\n",
|
||||
"# Initialize SimilarityCalculator\n",
|
||||
"from semantica.deduplication import SimilarityCalculator, SimilarityResult\n",
|
||||
"# Initialize calculator with custom weights\n",
|
||||
"calculator = SimilarityCalculator(\n",
|
||||
" string_weight=0.4,\n",
|
||||
" property_weight=0.3,\n",
|
||||
" relationship_weight=0.2,\n",
|
||||
" embedding_weight=0.1,\n",
|
||||
" string_weight=0.5, # High importance on name\n",
|
||||
" property_weight=0.3, # Medium importance on properties\n",
|
||||
" relationship_weight=0.2 # Lower importance on relationships\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Calculate overall similarity (multi-factor)\n",
|
||||
"entity1, entity2 = entities[0], entities[1]\n",
|
||||
"result = calculator.calculate_similarity(entity1, entity2)\n",
|
||||
"print(f\"Overall Similarity: {result.score:.3f}\")\n",
|
||||
"print(f\"Components: {result.components}\")\n",
|
||||
"# Compare \"Apple Inc.\" (e1) vs \"Apple Inc\" (e2)\n",
|
||||
"score_e1_e2 = calculator.calculate_similarity(entities[0], entities[1])\n",
|
||||
"\n",
|
||||
"# String similarity methods\n",
|
||||
"str1, str2 = \"Apple Inc.\", \"Apple Inc\"\n",
|
||||
"for method in [\"levenshtein\", \"jaro_winkler\", \"cosine\"]:\n",
|
||||
" score = calculator.calculate_string_similarity(str1, str2, method=method)\n",
|
||||
" print(f\"{method}: {score:.3f}\")\n",
|
||||
"print(f\"Similarity between '{entities[0]['name']}' and '{entities[1]['name']}':\")\n",
|
||||
"print(f\" Total Score: {score_e1_e2.score:.4f}\")\n",
|
||||
"print(f\" Breakdown: {score_e1_e2.components}\")\n",
|
||||
"\n",
|
||||
"# Property and relationship similarity\n",
|
||||
"prop_score = calculator.calculate_property_similarity(entity1, entity2)\n",
|
||||
"rel_score = calculator.calculate_relationship_similarity(entity1, entity2)\n",
|
||||
"print(f\"\\nProperty Similarity: {prop_score:.3f}\")\n",
|
||||
"print(f\"Relationship Similarity: {rel_score:.3f}\")\n",
|
||||
"# Compare \"Apple Inc.\" (e1) vs \"Microsoft\" (e5)\n",
|
||||
"score_e1_e5 = calculator.calculate_similarity(entities[0], entities[4])\n",
|
||||
"\n",
|
||||
"# Batch similarity calculation\n",
|
||||
"similarity_pairs = calculator.batch_calculate_similarity(entities, threshold=0.5)\n",
|
||||
"print(f\"\\nFound {len(similarity_pairs)} similar pairs (threshold >= 0.5)\")\n",
|
||||
"for e1, e2, score in similarity_pairs:\n",
|
||||
" print(f\" {e1['name']} <-> {e2['name']}: {score:.3f}\")\n"
|
||||
"print(f\"\\nSimilarity between '{entities[0]['name']}' and '{entities[4]['name']}':\")\n",
|
||||
"print(f\" Total Score: {score_e1_e5.score:.4f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"## 3. Duplicate Detection\n",
|
||||
"\n",
|
||||
"## Entity Merging {#merging}\n",
|
||||
"The `DuplicateDetector` uses the similarity calculator to scan your dataset for duplicates. It can find:\n",
|
||||
"- **Pairs**: Simple A matches B.\n",
|
||||
"- **Groups**: A matches B, and B matches C.\n",
|
||||
"\n",
|
||||
"The module merges duplicate entities into single canonical representations using configurable strategies. Merging preserves provenance, handles conflicts, and maintains merge history.\n",
|
||||
"\n",
|
||||
"### Merge Strategies\n",
|
||||
"\n",
|
||||
"1. **KEEP_FIRST**: Preserve the first entity encountered, merge others into it\n",
|
||||
"2. **KEEP_LAST**: Preserve the last entity encountered, merge others into it\n",
|
||||
"3. **KEEP_MOST_COMPLETE**: Preserve entity with most properties and relationships\n",
|
||||
"4. **KEEP_HIGHEST_CONFIDENCE**: Preserve entity with highest confidence score\n",
|
||||
"5. **MERGE_ALL**: Create new entity combining all properties and relationships\n",
|
||||
"6. **CUSTOM**: User-defined merge logic\n",
|
||||
"\n",
|
||||
"### Conflict Resolution\n",
|
||||
"\n",
|
||||
"When merging entities with conflicting property values, the module supports:\n",
|
||||
"- Voting: Majority value selection\n",
|
||||
"- Credibility-weighted: Weighted by source credibility\n",
|
||||
"- Temporal: Most recent value\n",
|
||||
"- Confidence-based: Highest confidence value\n",
|
||||
"- Custom functions: User-defined resolution logic\n",
|
||||
"\n",
|
||||
"### EntityMerger Class\n",
|
||||
"\n",
|
||||
"The `EntityMerger` class provides entity merging with automatic duplicate detection, provenance preservation, and merge history tracking.\n",
|
||||
"\n",
|
||||
"### MergeStrategyManager Class\n",
|
||||
"\n",
|
||||
"The `MergeStrategyManager` class provides advanced merge management with property-specific rules and custom conflict resolution functions.\n"
|
||||
"It uses a `similarity_threshold` to decide what counts as a match."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -391,145 +161,29 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"### Example: Entity Merging\n",
|
||||
"# Import specific classes for Duplicate Detection\n",
|
||||
"from semantica.deduplication import DuplicateDetector, DuplicateCandidate, DuplicateGroup\n",
|
||||
"from semantica.deduplication import DeduplicationConfig\n",
|
||||
"\n",
|
||||
"# Initialize EntityMerger\n",
|
||||
"merger = EntityMerger(preserve_provenance=True)\n",
|
||||
"\n",
|
||||
"# Merge duplicates (automatic detection)\n",
|
||||
"merge_operations = merger.merge_duplicates(entities)\n",
|
||||
"print(f\"Original entities: {len(entities)}\")\n",
|
||||
"print(f\"Merge operations: {len(merge_operations)}\")\n",
|
||||
"for i, op in enumerate(merge_operations, 1):\n",
|
||||
" print(f\" Operation {i}: Merged {len(op.source_entities)} entities → {op.merged_entity.get('name')}\")\n",
|
||||
" if op.merge_result.conflicts:\n",
|
||||
" print(f\" Conflicts: {len(op.merge_result.conflicts)}\")\n",
|
||||
"\n",
|
||||
"# Merge with specific strategy\n",
|
||||
"operations = merger.merge_duplicates(entities, strategy=MergeStrategy.KEEP_MOST_COMPLETE)\n",
|
||||
"print(f\"\\nMerged using KEEP_MOST_COMPLETE: {len(operations)} operations\")\n",
|
||||
"\n",
|
||||
"# Merge specific group\n",
|
||||
"duplicate_entities = [entities[0], entities[1]]\n",
|
||||
"operation = merger.merge_entity_group(duplicate_entities, strategy=MergeStrategy.KEEP_FIRST)\n",
|
||||
"print(f\"\\nMerged group: {[e['name'] for e in operation.source_entities]} → {operation.merged_entity['name']}\")\n",
|
||||
"\n",
|
||||
"# Get merge history\n",
|
||||
"history = merger.get_merge_history()\n",
|
||||
"print(f\"\\nTotal merge operations in history: {len(history)}\")\n",
|
||||
"\n",
|
||||
"# Validate merge quality\n",
|
||||
"if operations:\n",
|
||||
" validation = merger.validate_merge_quality(operations[0])\n",
|
||||
" print(f\"\\nValidation: Valid={validation['valid']}, Quality={validation['quality_score']:.3f}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Clustering {#clustering}\n",
|
||||
"\n",
|
||||
"The module provides clustering capabilities for efficient batch deduplication of large datasets. Clustering groups similar entities together before deduplication.\n",
|
||||
"\n",
|
||||
"### Clustering Methods\n",
|
||||
"\n",
|
||||
"1. **Graph-Based Clustering**: Union-Find algorithm for connected components\n",
|
||||
" - Builds similarity graph from pairwise similarities\n",
|
||||
" - Uses Union-Find (Disjoint Set Union) for efficient component detection\n",
|
||||
" - Suitable for medium-sized datasets\n",
|
||||
"\n",
|
||||
"2. **Hierarchical Clustering**: Agglomerative bottom-up clustering\n",
|
||||
" - Builds cluster hierarchy by merging similar clusters\n",
|
||||
" - Suitable for large datasets\n",
|
||||
" - Provides cluster quality metrics (cohesion, separation)\n",
|
||||
"\n",
|
||||
"### Cluster Quality Metrics\n",
|
||||
"\n",
|
||||
"- **Cohesion**: Average similarity within clusters\n",
|
||||
"- **Separation**: Average similarity between clusters\n",
|
||||
"- **Cluster Quality Score**: Combined metric for cluster evaluation\n",
|
||||
"\n",
|
||||
"### ClusterBuilder Class\n",
|
||||
"\n",
|
||||
"The `ClusterBuilder` class provides clustering with configurable thresholds, quality metrics, and incremental update capabilities.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"### Example: Advanced Merge Strategies\n",
|
||||
"\n",
|
||||
"# Initialize MergeStrategyManager\n",
|
||||
"strategy_manager = MergeStrategyManager(default_strategy=\"keep_most_complete\")\n",
|
||||
"\n",
|
||||
"# Add property-specific rules\n",
|
||||
"strategy_manager.add_property_rule(\"name\", MergeStrategy.KEEP_FIRST, priority=1)\n",
|
||||
"strategy_manager.add_property_rule(\"description\", MergeStrategy.MERGE_ALL, priority=1)\n",
|
||||
"\n",
|
||||
"# Custom conflict resolution\n",
|
||||
"def resolve_longest(values):\n",
|
||||
" return max(values, key=len)\n",
|
||||
"\n",
|
||||
"strategy_manager.add_property_rule(\n",
|
||||
" \"headquarters\", MergeStrategy.CUSTOM, conflict_resolution=resolve_longest, priority=2\n",
|
||||
"detector = DuplicateDetector(\n",
|
||||
" similarity_threshold=0.7, \n",
|
||||
" confidence_threshold=0.6 \n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"Added merge rules: name=KEEP_FIRST, description=MERGE_ALL, headquarters=CUSTOM\")\n",
|
||||
"# Detect pairs\n",
|
||||
"candidates = detector.detect_duplicates(entities)\n",
|
||||
"\n",
|
||||
"# Merge entities with property rules\n",
|
||||
"duplicate_pair = [entities[0], entities[1]]\n",
|
||||
"merge_result = strategy_manager.merge_entities(duplicate_pair)\n",
|
||||
"print(f\"\\nMerged Entity: {merge_result.merged_entity.get('name')}\")\n",
|
||||
"print(f\"Conflicts: {len(merge_result.conflicts)}\")\n",
|
||||
"\n",
|
||||
"# Validate merge quality\n",
|
||||
"validation = strategy_manager.validate_merge(merge_result)\n",
|
||||
"print(f\"Validation: Valid={validation['valid']}, Quality={validation['quality_score']:.3f}\")\n"
|
||||
"print(f\"Found {len(candidates)} duplicate pairs:\")\n",
|
||||
"for c in candidates:\n",
|
||||
" print(f\" - {c.entity1['name']} <==> {c.entity2['name']} (Score: {c.similarity_score:.2f})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Advanced Features {#advanced}\n",
|
||||
"\n",
|
||||
"The module provides advanced features for extensibility, configuration, and custom method registration.\n",
|
||||
"\n",
|
||||
"### Configuration Management\n",
|
||||
"\n",
|
||||
"The `DeduplicationConfig` class provides centralized configuration from multiple sources:\n",
|
||||
"- Programmatic configuration (via `set()` method)\n",
|
||||
"- Environment variables\n",
|
||||
"- Configuration files (YAML, JSON, TOML)\n",
|
||||
"- Default values\n",
|
||||
"\n",
|
||||
"Configuration can be set globally or per-method for fine-grained control.\n",
|
||||
"\n",
|
||||
"### Method Registry\n",
|
||||
"\n",
|
||||
"The `MethodRegistry` class allows registration of custom deduplication methods:\n",
|
||||
"- Custom similarity calculation methods\n",
|
||||
"- Custom duplicate detection methods\n",
|
||||
"- Custom entity merging methods\n",
|
||||
"- Custom clustering methods\n",
|
||||
"\n",
|
||||
"Registered methods can be used throughout the module via the registry.\n",
|
||||
"\n",
|
||||
"### Property-Specific Merge Rules\n",
|
||||
"\n",
|
||||
"The `MergeStrategyManager` supports property-specific merge rules:\n",
|
||||
"- Different merge strategies for different properties\n",
|
||||
"- Custom conflict resolution functions per property\n",
|
||||
"- Priority-based rule application\n",
|
||||
"- Flexible rule composition\n"
|
||||
"### Incremental Detection\n",
|
||||
"If you have an existing database and ingest new data, you don't want to re-compare everything. Use `incremental_detect`."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -538,47 +192,106 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"### Example: Clustering\n",
|
||||
"existing_db = entities[:3] # The Apple entities\n",
|
||||
"new_data = [entities[4]] # Microsoft\n",
|
||||
"# Check if new data matches anything in existing DB\n",
|
||||
"inc_candidates = detector.incremental_detect(new_data, existing_db)\n",
|
||||
"\n",
|
||||
"# Initialize ClusterBuilder\n",
|
||||
"cluster_builder = ClusterBuilder(\n",
|
||||
" similarity_threshold=0.7,\n",
|
||||
" min_cluster_size=2,\n",
|
||||
" max_cluster_size=100,\n",
|
||||
" use_hierarchical=False,\n",
|
||||
"print(f\"New matches found: {len(inc_candidates)}\")\n",
|
||||
"# Expected: 0, because Microsoft is not Apple."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Clustering\n",
|
||||
"\n",
|
||||
"Sometimes pairs aren't enough. `ClusterBuilder` groups related entities into clusters. This is useful for understanding the full scope of a duplicated entity."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Import specific classes for Clustering\n",
|
||||
"from semantica.deduplication import ClusterBuilder, Cluster, ClusterResult\n",
|
||||
"cluster_builder = ClusterBuilder(threshold=0.7)\n",
|
||||
"result = cluster_builder.build_clusters(entities)\n",
|
||||
"\n",
|
||||
"print(f\"Found {len(result.clusters)} clusters:\")\n",
|
||||
"for i, cluster in enumerate(result.clusters):\n",
|
||||
" names = [e['name'] for e in cluster.entities]\n",
|
||||
" print(f\" Cluster {i+1}: {names}\")\n",
|
||||
"\n",
|
||||
"cluster_builder = ClusterBuilder(threshold=0.7)\n",
|
||||
"result = cluster_builder.build_clusters(entities)\n",
|
||||
"\n",
|
||||
"print(f\"Found {len(result.clusters)} clusters:\")\n",
|
||||
"for i, cluster in enumerate(result.clusters):\n",
|
||||
" names = [e['name'] for e in cluster.entities]\n",
|
||||
" print(f\" Cluster {i+1}: {names}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Entity Merging\n",
|
||||
"\n",
|
||||
"Once duplicates are found, `EntityMerger` combines them. You need to choose a **Merge Strategy**:\n",
|
||||
"\n",
|
||||
"- `KEEP_FIRST` / `KEEP_LAST`: Based on order.\n",
|
||||
"- `KEEP_MOST_COMPLETE`: Keeps the entity with the most data (properties + relationships).\n",
|
||||
"- `KEEP_HIGHEST_CONFIDENCE`: Uses internal confidence scores.\n",
|
||||
"- `MERGE_ALL`: Combines everything (arrays are concatenated, conflicts resolved by voting)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Import specific classes for Entity Merging\n",
|
||||
"from semantica.deduplication import EntityMerger, MergeStrategy, MergeStrategyManager, MergeOperation, MergeResult"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"merger = EntityMerger()\n",
|
||||
"\n",
|
||||
"# We will use the 'KEEP_MOST_COMPLETE' strategy\n",
|
||||
"# This ensures we don't lose valuable information from richer entities\n",
|
||||
"merge_ops = merger.merge_duplicates(\n",
|
||||
" entities, \n",
|
||||
" strategy=MergeStrategy.KEEP_MOST_COMPLETE\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Graph-based clustering\n",
|
||||
"cluster_result = cluster_builder.build_clusters(entities)\n",
|
||||
"print(f\"Clusters: {len(cluster_result.clusters)}, Unclustered: {len(cluster_result.unclustered)}\")\n",
|
||||
"print(f\"Quality Metrics: {cluster_result.quality_metrics}\")\n",
|
||||
"for cluster in cluster_result.clusters:\n",
|
||||
" print(f\" {cluster.cluster_id}: {len(cluster.entities)} entities (quality: {cluster.quality_score:.3f})\")\n",
|
||||
"print(f\"Performed {len(merge_ops)} merge operations.\")\n",
|
||||
"\n",
|
||||
"# Hierarchical clustering\n",
|
||||
"hierarchical_builder = ClusterBuilder(similarity_threshold=0.7, use_hierarchical=True)\n",
|
||||
"hierarchical_result = hierarchical_builder.build_clusters(entities)\n",
|
||||
"print(f\"\\nHierarchical Clustering: {len(hierarchical_result.clusters)} clusters\")\n",
|
||||
"print(f\"Quality Metrics: {hierarchical_result.quality_metrics}\")\n"
|
||||
"print(\"\\n--- Merged Results ---\")\n",
|
||||
"for op in merge_ops:\n",
|
||||
" final_ent = op.merged_entity\n",
|
||||
" original_count = len(op.source_entities)\n",
|
||||
" print(f\"Merged {original_count} entities into: '{final_ent['name']}'\")\n",
|
||||
" print(f\" - Final Properties: {final_ent['properties']}\")\n",
|
||||
" print(f\" - Final Relationships: {len(final_ent.get('relationships', []))}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"## 6. Complete Workflow\n",
|
||||
"\n",
|
||||
"## Complete Workflow {#workflow}\n",
|
||||
"\n",
|
||||
"A typical deduplication workflow involves:\n",
|
||||
"1. Configuration: Set similarity thresholds and method preferences\n",
|
||||
"2. Clustering: Build clusters of similar entities (optional, for large datasets)\n",
|
||||
"3. Detection: Identify duplicate entities within clusters or entire dataset\n",
|
||||
"4. Merging: Merge duplicate entities using appropriate strategies\n",
|
||||
"5. Validation: Validate merge quality and completeness\n",
|
||||
"6. History: Track merge operations for audit and rollback\n",
|
||||
"\n",
|
||||
"The module provides both class-based and function-based interfaces for flexibility.\n"
|
||||
"Let's wrap this up into a clean function that takes dirty data and returns clean data."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -587,172 +300,78 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"### Example: Configuration and Method Registry\n",
|
||||
"\n",
|
||||
"# Configuration management\n",
|
||||
"threshold = dedup_config.get(\"similarity_threshold\", default=0.7)\n",
|
||||
"confidence = dedup_config.get(\"confidence_threshold\", default=0.6)\n",
|
||||
"print(f\"Current: similarity_threshold={threshold}, confidence_threshold={confidence}\")\n",
|
||||
"\n",
|
||||
"# Set configuration programmatically\n",
|
||||
"dedup_config.set(\"similarity_threshold\", 0.8)\n",
|
||||
"dedup_config.set(\"confidence_threshold\", 0.7)\n",
|
||||
"print(f\"Updated: similarity_threshold={dedup_config.get('similarity_threshold')}\")\n",
|
||||
"\n",
|
||||
"# Method-specific configuration\n",
|
||||
"dedup_config.set_method_config(\"levenshtein\", case_sensitive=False)\n",
|
||||
"levenshtein_config = dedup_config.get_method_config(\"levenshtein\")\n",
|
||||
"print(f\"Method config (levenshtein): {levenshtein_config}\")\n",
|
||||
"\n",
|
||||
"# Custom method registration\n",
|
||||
"def word_overlap_similarity(entity1, entity2, **kwargs):\n",
|
||||
" \"\"\"Custom similarity based on word overlap.\"\"\"\n",
|
||||
" name1 = entity1.get(\"name\", \"\").lower().split()\n",
|
||||
" name2 = entity2.get(\"name\", \"\").lower().split()\n",
|
||||
"def deduplicate_dataset(raw_entities):\n",
|
||||
" print(\"1. Detecting duplicates...\")\n",
|
||||
" # Step 1: Detect\n",
|
||||
" detector = DuplicateDetector(similarity_threshold=0.75)\n",
|
||||
" # We can skip explicit detection calls if we just want to merge, \n",
|
||||
" # as EntityMerger calls detection internally, but doing it manually allows inspection.\n",
|
||||
" \n",
|
||||
" if not name1 or not name2:\n",
|
||||
" return SimilarityResult(score=0.0, method=\"word_overlap\")\n",
|
||||
" print(\"2. Merging entities...\")\n",
|
||||
" # Step 2: Merge\n",
|
||||
" merger = EntityMerger()\n",
|
||||
" ops = merger.merge_duplicates(raw_entities, strategy=MergeStrategy.KEEP_MOST_COMPLETE)\n",
|
||||
" \n",
|
||||
" set1, set2 = set(name1), set(name2)\n",
|
||||
" intersection = len(set1 & set2)\n",
|
||||
" union = len(set1 | set2)\n",
|
||||
" score = intersection / union if union > 0 else 0.0\n",
|
||||
" return SimilarityResult(score=score, method=\"word_overlap\")\n",
|
||||
" # Let's collect all final IDs to see what remains\n",
|
||||
" merged_entities = [op.merged_entity for op in ops]\n",
|
||||
" \n",
|
||||
" # Find entities that were NOT part of any merge (singletons)\n",
|
||||
" merged_ids = set()\n",
|
||||
" for op in ops:\n",
|
||||
" for source in op.source_entities:\n",
|
||||
" merged_ids.add(source['id'])\n",
|
||||
" \n",
|
||||
" singletons = [e for e in raw_entities if e['id'] not in merged_ids]\n",
|
||||
" \n",
|
||||
" final_dataset = merged_entities + singletons\n",
|
||||
" return final_dataset\n",
|
||||
"\n",
|
||||
"# Register custom method\n",
|
||||
"method_registry.register(\"similarity\", \"word_overlap\", word_overlap_similarity)\n",
|
||||
"print(\"\\nRegistered 'word_overlap' similarity method\")\n",
|
||||
"# Run the workflow\n",
|
||||
"clean_data = deduplicate_dataset(entities)\n",
|
||||
"\n",
|
||||
"# Use custom method\n",
|
||||
"custom_method = method_registry.get(\"similarity\", \"word_overlap\")\n",
|
||||
"if custom_method:\n",
|
||||
" result = custom_method(entities[0], entities[1])\n",
|
||||
" print(f\"Word Overlap Similarity: {result.score:.3f}\")\n",
|
||||
"\n",
|
||||
"# List all registered methods\n",
|
||||
"all_registered = method_registry.list_all()\n",
|
||||
"print(f\"\\nRegistered Methods: {all_registered}\")\n"
|
||||
"print(f\"\\nOriginal Size: {len(entities)}\")\n",
|
||||
"print(f\"Cleaned Size: {len(clean_data)}\")\n",
|
||||
"print(\"\\nFinal Entity Names:\")\n",
|
||||
"for e in clean_data:\n",
|
||||
" print(f\" - {e['name']}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"## Practical Examples\n",
|
||||
"You've learned how to:\n",
|
||||
"1. **Import** the necessary Deduplication classes.\n",
|
||||
"2. **Calculate Similarity** between entities.\n",
|
||||
"3. **Detect Duplicates** using configurable thresholds.\n",
|
||||
"4. **Cluster** similar entities.\n",
|
||||
"5. **Merge** duplicates into a clean, canonical dataset.\n",
|
||||
"\n",
|
||||
"The following sections demonstrate practical usage of the module components.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"### Example: Complete Workflow\n",
|
||||
"\n",
|
||||
"# Complete deduplication workflow\n",
|
||||
"\n",
|
||||
"# Step 1: Configure\n",
|
||||
"dedup_config.set(\"similarity_threshold\", 0.75)\n",
|
||||
"dedup_config.set(\"confidence_threshold\", 0.65)\n",
|
||||
"\n",
|
||||
"# Step 2: Build clusters\n",
|
||||
"cluster_builder = ClusterBuilder(similarity_threshold=0.75, min_cluster_size=2, max_cluster_size=50)\n",
|
||||
"cluster_result = cluster_builder.build_clusters(entities)\n",
|
||||
"print(f\"Step 1: Created {len(cluster_result.clusters)} clusters\")\n",
|
||||
"\n",
|
||||
"# Step 3: Detect duplicates\n",
|
||||
"detector = DuplicateDetector(similarity_threshold=0.75, confidence_threshold=0.65)\n",
|
||||
"all_duplicate_groups = []\n",
|
||||
"for cluster in cluster_result.clusters:\n",
|
||||
" groups = detector.detect_duplicate_groups(cluster.entities)\n",
|
||||
" all_duplicate_groups.extend(groups)\n",
|
||||
"print(f\"Step 2: Found {len(all_duplicate_groups)} duplicate groups\")\n",
|
||||
"\n",
|
||||
"# Step 4: Merge duplicates\n",
|
||||
"merger = EntityMerger(preserve_provenance=True)\n",
|
||||
"merge_operations = merger.merge_duplicates(entities, strategy=MergeStrategy.KEEP_MOST_COMPLETE)\n",
|
||||
"print(f\"Step 3: Performed {len(merge_operations)} merge operations\")\n",
|
||||
"\n",
|
||||
"# Step 5: Extract results\n",
|
||||
"merged_entities = [op.merged_entity for op in merge_operations]\n",
|
||||
"print(f\"\\nResults:\")\n",
|
||||
"print(f\" Original: {len(entities)} entities\")\n",
|
||||
"print(f\" Merged: {len(merged_entities)} entities\")\n",
|
||||
"print(f\" Reduction: {len(entities) - len(merged_entities)} entities\")\n",
|
||||
"\n",
|
||||
"# Step 6: Validate merge quality\n",
|
||||
"for i, op in enumerate(merge_operations, 1):\n",
|
||||
" validation = merger.validate_merge_quality(op)\n",
|
||||
" print(f\" Merge {i}: Valid={validation['valid']}, Quality={validation['quality_score']:.3f}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Example: Similarity Calculation\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Complete deduplication workflow\n",
|
||||
"\n",
|
||||
"# Step 1: Configure\n",
|
||||
"dedup_config.set(\"similarity_threshold\", 0.75)\n",
|
||||
"dedup_config.set(\"confidence_threshold\", 0.65)\n",
|
||||
"\n",
|
||||
"# Step 2: Build clusters\n",
|
||||
"cluster_builder = ClusterBuilder(similarity_threshold=0.75, min_cluster_size=2, max_cluster_size=50)\n",
|
||||
"cluster_result = cluster_builder.build_clusters(entities)\n",
|
||||
"print(f\"Step 1: Created {len(cluster_result.clusters)} clusters\")\n",
|
||||
"\n",
|
||||
"# Step 3: Detect duplicates\n",
|
||||
"detector = DuplicateDetector(similarity_threshold=0.75, confidence_threshold=0.65)\n",
|
||||
"all_duplicate_groups = []\n",
|
||||
"for cluster in cluster_result.clusters:\n",
|
||||
" groups = detector.detect_duplicate_groups(cluster.entities)\n",
|
||||
" all_duplicate_groups.extend(groups)\n",
|
||||
"print(f\"Step 2: Found {len(all_duplicate_groups)} duplicate groups\")\n",
|
||||
"\n",
|
||||
"# Step 4: Merge duplicates\n",
|
||||
"merger = EntityMerger(preserve_provenance=True)\n",
|
||||
"merge_operations = merger.merge_duplicates(entities, strategy=MergeStrategy.KEEP_MOST_COMPLETE)\n",
|
||||
"print(f\"Step 3: Performed {len(merge_operations)} merge operations\")\n",
|
||||
"\n",
|
||||
"# Step 5: Extract results\n",
|
||||
"merged_entities = [op.merged_entity for op in merge_operations]\n",
|
||||
"print(f\"\\nResults:\")\n",
|
||||
"print(f\" Original: {len(entities)} entities\")\n",
|
||||
"print(f\" Merged: {len(merged_entities)} entities\")\n",
|
||||
"print(f\" Reduction: {len(entities) - len(merged_entities)} entities\")\n",
|
||||
"\n",
|
||||
"# Step 6: Validate merge quality\n",
|
||||
"for i, op in enumerate(merge_operations, 1):\n",
|
||||
" validation = merger.validate_merge_quality(op)\n",
|
||||
" print(f\" Merge {i}: Valid={validation['valid']}, Quality={validation['quality_score']:.3f}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Example: Duplicate Detection\n"
|
||||
"This module is essential for maintaining high-quality Knowledge Graphs, especially when ingesting data from multiple, potentially messy sources."
|
||||
]
|
||||
}
|
||||
],
|
||||
"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.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
|
||||
@@ -2,256 +2,417 @@
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c21e9c8d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/introduction/19_Context_Module.ipynb)\n",
|
||||
"\n",
|
||||
"# Context Engineering Module\n",
|
||||
"# Context Module — Practical Guide\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"Semantica’s `context` module is the layer that makes an agent “stateful”. It combines:\n",
|
||||
"\n",
|
||||
"This notebook provides a comprehensive guide to Semantica's **Context Engineering Module** - a powerful system for building context graphs, managing agent memory, retrieving context, and linking entities. You'll learn how to use the new synchronous Architecture 2.0 features, including hierarchical memory with token management.\n",
|
||||
"- **Memory** (short-term + long-term) via `AgentMemory`\n",
|
||||
"- **Graph context** via `ContextGraph`\n",
|
||||
"- **Hybrid retrieval** (vector + memory + graph) via `ContextRetriever`\n",
|
||||
"- **High-level UX** via `AgentContext` (recommended entry point)\n",
|
||||
"- **Entity linking** via `EntityLinker`\n",
|
||||
"- **Extensibility + config** via `registry` and `config`\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/context/)\n",
|
||||
"\n",
|
||||
"### Learning Objectives\n",
|
||||
"\n",
|
||||
"- **Hierarchical Memory**: Manage short-term (token-buffered) and long-term (vector-stored) memory\n",
|
||||
"- **Context Graph**: Build and query dynamic knowledge graphs\n",
|
||||
"- **Hybrid Retrieval**: Combine vector search, graph traversal, and keyword matching\n",
|
||||
"- **Entity Linking**: Resolve entities across conversations\n",
|
||||
"- **Configuration**: Customize behavior via YAML or environment variables\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"## Installation\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"pip install semantica\n",
|
||||
"```"
|
||||
"This notebook focuses on small, runnable examples and keeps imports scoped to each cell."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "257bad40",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Setup: Create a mock vector store for demonstration\n",
|
||||
"from typing import List, Dict, Any, Optional\n",
|
||||
"from semantica.context import VectorStore\n",
|
||||
"\n",
|
||||
"class MockVectorStore(VectorStore):\n",
|
||||
" def __init__(self):\n",
|
||||
" self.items = {}\n",
|
||||
" self.counter = 0\n",
|
||||
" \n",
|
||||
" def add(self, texts: List[str], metadata: Optional[List[Dict[str, Any]]] = None, **kwargs) -> List[str]:\n",
|
||||
" ids = []\n",
|
||||
" for i, text in enumerate(texts):\n",
|
||||
" id_ = f\"id_{self.counter}\"\n",
|
||||
" self.items[id_] = {\"text\": text, \"metadata\": metadata[i] if metadata else {}}\n",
|
||||
" ids.append(id_)\n",
|
||||
" self.counter += 1\n",
|
||||
" return ids\n",
|
||||
" \n",
|
||||
" def search(self, query: str, limit: int = 5, **kwargs) -> List[Dict[str, Any]]:\n",
|
||||
" # Simple keyword match for mock\n",
|
||||
" results = []\n",
|
||||
" for id_, item in self.items.items():\n",
|
||||
" if any(w.lower() in item[\"text\"].lower() for w in query.split()):\n",
|
||||
" results.append({\n",
|
||||
" \"id\": id_,\n",
|
||||
" \"content\": item[\"text\"],\n",
|
||||
" \"score\": 0.9,\n",
|
||||
" \"metadata\": item[\"metadata\"]\n",
|
||||
" })\n",
|
||||
" return results[:limit]\n",
|
||||
" \n",
|
||||
" def delete(self, ids: List[str], **kwargs) -> bool:\n",
|
||||
" for id_ in ids:\n",
|
||||
" self.items.pop(id_, None)\n",
|
||||
" return True\n",
|
||||
"\n",
|
||||
"vs = MockVectorStore()"
|
||||
"!pip install -q semantica"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a48e0f10",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. High-Level Interface: AgentContext\n",
|
||||
"## 1) Vector store (for long-term memory)\n",
|
||||
"\n",
|
||||
"The `AgentContext` class is the easiest way to get started. It unifies vector storage, knowledge graphs, and memory management."
|
||||
"The `VectorStore` can generate embeddings via its internal embedder. If no embedder is available in your environment, it falls back to random vectors so the API stays usable for demos."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8c845a94",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.vector_store import VectorStore\n",
|
||||
"\n",
|
||||
"vs = VectorStore(backend=\"inmemory\", dimension=384)\n",
|
||||
"\n",
|
||||
"if getattr(vs, \"embedder\", None) and hasattr(vs.embedder, \"set_text_model\"):\n",
|
||||
" vs.embedder.set_text_model(method=\"fastembed\", model_name=\"BAAI/bge-small-en-v1.5\")\n",
|
||||
"\n",
|
||||
"vs.backend, vs.dimension"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c1b1ba34",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2) Quick start with `AgentContext` (recommended)\n",
|
||||
"\n",
|
||||
"`AgentContext` is the user-friendly interface that ties memory, vector store, and graph together. If you pass a `ContextGraph`, the system can do GraphRAG-style retrieval."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f4d788b5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.context import AgentContext, ContextGraph\n",
|
||||
"\n",
|
||||
"# Initialize with vector store and a new in-memory knowledge graph\n",
|
||||
"kg = ContextGraph()\n",
|
||||
"context = AgentContext(\n",
|
||||
" vector_store=vs,\n",
|
||||
" knowledge_graph=kg,\n",
|
||||
" token_limit=2000, # Max tokens in short-term memory\n",
|
||||
" short_term_limit=10 # Max items in short-term memory\n",
|
||||
")\n",
|
||||
"context = AgentContext(vector_store=vs, knowledge_graph=kg)\n",
|
||||
"\n",
|
||||
"# Store a memory (automatically goes to short-term and long-term)\n",
|
||||
"context.store(\n",
|
||||
" \"The user, Alice, is a data scientist interested in Python.\",\n",
|
||||
"context.config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "638bdbc8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3) Store and retrieve memory\n",
|
||||
"\n",
|
||||
"A single string is treated as a memory item. You can attach `conversation_id` and `user_id` through metadata-friendly parameters."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5d65eb00",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"memory_id = context.store(\n",
|
||||
" \"User prefers short answers about Python.\",\n",
|
||||
" conversation_id=\"conv_1\",\n",
|
||||
" user_id=\"alice_01\"\n",
|
||||
" user_id=\"user_1\",\n",
|
||||
" metadata={\"type\": \"preference\"},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Retrieve context (automatically uses hybrid retrieval)\n",
|
||||
"results = context.retrieve(\"What does Alice do?\")\n",
|
||||
"\n",
|
||||
"for res in results:\n",
|
||||
" print(f\"Found: {res['content']} (Score: {res['score']})\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Hierarchical Memory Management\n",
|
||||
"\n",
|
||||
"Semantica uses a two-tier memory system:\n",
|
||||
"1. **Short-Term Memory**: A fast, in-memory buffer limited by tokens (to fit in LLM context windows) and item count.\n",
|
||||
"2. **Long-Term Memory**: Persistent storage backed by the vector store.\n",
|
||||
"\n",
|
||||
"Let's observe how the token limit works."
|
||||
"context.get_memory(memory_id)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3c1be718",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.context import AgentMemory\n",
|
||||
"\n",
|
||||
"# Initialize memory with strict limits for demonstration\n",
|
||||
"memory = AgentMemory(\n",
|
||||
" vector_store=vs,\n",
|
||||
" token_limit=50, # Very small token limit\n",
|
||||
" short_term_limit=5 # Max 5 items\n",
|
||||
"context.store(\n",
|
||||
" \"User is working on Semantica context module examples.\",\n",
|
||||
" conversation_id=\"conv_1\",\n",
|
||||
" user_id=\"user_1\",\n",
|
||||
" metadata={\"type\": \"note\"},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Add memories\n",
|
||||
"for i in range(10):\n",
|
||||
" memory.store(f\"Memory item {i}: This is a sentence with some tokens.\")\n",
|
||||
" print(f\"Added item {i}. Short-term size: {len(memory.short_term_memory)}\")\n",
|
||||
"\n",
|
||||
"print(\"\\nFinal short-term memory content:\")\n",
|
||||
"for item in memory.short_term_memory:\n",
|
||||
" print(f\"- {item.content}\")\n",
|
||||
" \n",
|
||||
"# Notice that older items are pruned to respect the token limit and item count."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Context Graph & GraphRAG\n",
|
||||
"\n",
|
||||
"The `ContextGraph` allows you to structure information as nodes and edges, enabling \"GraphRAG\" - retrieving information based on relationships rather than just semantic similarity."
|
||||
"context.retrieve(\"Python answers\", max_results=3)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "485acf33",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.context import ContextGraph\n",
|
||||
"\n",
|
||||
"graph = ContextGraph()\n",
|
||||
"\n",
|
||||
"# Manually building a graph\n",
|
||||
"graph.add_node(\"n1\", \"person\", \"Alice\")\n",
|
||||
"graph.add_node(\"n2\", \"language\", \"Python\")\n",
|
||||
"graph.add_node(\"n3\", \"library\", \"Semantica\")\n",
|
||||
"\n",
|
||||
"graph.add_edge(\"n1\", \"n2\", \"uses\")\n",
|
||||
"graph.add_edge(\"n2\", \"n3\", \"powers\")\n",
|
||||
"\n",
|
||||
"# Query the graph\n",
|
||||
"neighbors = graph.get_neighbors(\"n2\", hops=1)\n",
|
||||
"print(\"Neighbors of Python:\", neighbors)\n",
|
||||
"\n",
|
||||
"# Using the graph in AgentContext\n",
|
||||
"context = AgentContext(vector_store=vs, knowledge_graph=graph)\n",
|
||||
"\n",
|
||||
"# Retrieve with graph expansion\n",
|
||||
"results = context.retrieve(\n",
|
||||
" \"Alice\",\n",
|
||||
" use_graph=True,\n",
|
||||
" expand_graph=True # Will pull in 'Python' because Alice uses it\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"\\nGraph-enhanced Retrieval:\")\n",
|
||||
"for res in results:\n",
|
||||
" print(f\"- {res['content']}\")"
|
||||
"context.conversation(\"conv_1\", max_items=10)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1e43cddd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Entity Linking\n",
|
||||
"## 4) Export, save, load\n",
|
||||
"\n",
|
||||
"The `EntityLinker` helps ensure that \"Alice\", \"Alice Smith\", and \"she\" (in context) refer to the same entity ID."
|
||||
"`AgentContext` includes simple persistence helpers. This example uses a temporary directory."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a264ef4d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"export_json = context.export(conversation_id=\"conv_1\", format=\"json\")\n",
|
||||
"export_json[:300]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b62d1859",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import tempfile\n",
|
||||
"\n",
|
||||
"with tempfile.TemporaryDirectory() as d:\n",
|
||||
" context.save(d)\n",
|
||||
" context.load(d)\n",
|
||||
"\n",
|
||||
"context.conversation_summary(\"conv_1\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3b8bf553",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5) Store documents and build a context graph\n",
|
||||
"\n",
|
||||
"If you store a list, `AgentContext.store(...)` treats it as documents. To keep this notebook lightweight and deterministic, we pass pre-extracted entities and relationships per document."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "72930ae7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"documents = [\n",
|
||||
" {\n",
|
||||
" \"id\": \"doc_1\",\n",
|
||||
" \"content\": \"Python is used for machine learning.\",\n",
|
||||
" \"metadata\": {\"source\": \"docs\"},\n",
|
||||
" \"entities\": [\n",
|
||||
" {\"id\": \"e_python\", \"text\": \"Python\", \"type\": \"PROGRAMMING_LANGUAGE\"},\n",
|
||||
" {\"id\": \"e_ml\", \"text\": \"Machine Learning\", \"type\": \"CONCEPT\"},\n",
|
||||
" ],\n",
|
||||
" \"relationships\": [\n",
|
||||
" {\n",
|
||||
" \"source_id\": \"e_python\",\n",
|
||||
" \"target_id\": \"e_ml\",\n",
|
||||
" \"type\": \"used_for\",\n",
|
||||
" \"confidence\": 0.9,\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"doc_2\",\n",
|
||||
" \"content\": \"PyTorch is a machine learning framework.\",\n",
|
||||
" \"metadata\": {\"source\": \"docs\"},\n",
|
||||
" \"entities\": [\n",
|
||||
" {\"id\": \"e_pytorch\", \"text\": \"PyTorch\", \"type\": \"FRAMEWORK\"},\n",
|
||||
" {\"id\": \"e_ml\", \"text\": \"Machine Learning\", \"type\": \"CONCEPT\"},\n",
|
||||
" ],\n",
|
||||
" \"relationships\": [\n",
|
||||
" {\n",
|
||||
" \"source_id\": \"e_pytorch\",\n",
|
||||
" \"target_id\": \"e_ml\",\n",
|
||||
" \"type\": \"implements\",\n",
|
||||
" \"confidence\": 0.95,\n",
|
||||
" }\n",
|
||||
" ],\n",
|
||||
" },\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"stats = context.store(\n",
|
||||
" documents,\n",
|
||||
" extract_entities=False,\n",
|
||||
" extract_relationships=False,\n",
|
||||
" link_entities=True,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"stats"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "24f8dba8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kg.stats()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f4671f2a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 6) Explore the graph with `ContextGraph`\n",
|
||||
"\n",
|
||||
"The graph supports keyword querying and neighbor expansion."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "df2e5fcd",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kg.query(\"machine learning\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0836feeb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"kg.get_neighbors(\"e_python\", hops=2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1be1adf1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 7) Entity linking with `EntityLinker`\n",
|
||||
"\n",
|
||||
"`EntityLinker` assigns stable URIs and can link related or duplicate entities across sources."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "24b011c0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.context import EntityLinker\n",
|
||||
"\n",
|
||||
"linker = EntityLinker()\n",
|
||||
"linker = EntityLinker(knowledge_graph={\"entities\": [{\"id\": \"e_py\", \"text\": \"Python\", \"type\": \"PROGRAMMING_LANGUAGE\"}]})\n",
|
||||
"\n",
|
||||
"# Generate a canonical URI\n",
|
||||
"uri = linker.generate_uri(\"Python Programming Language\")\n",
|
||||
"print(f\"Canonical URI: {uri}\")\n",
|
||||
"entities = [\n",
|
||||
" {\"id\": \"e1\", \"text\": \"Python\", \"type\": \"PROGRAMMING_LANGUAGE\"},\n",
|
||||
" {\"id\": \"e2\", \"text\": \"PyTorch\", \"type\": \"FRAMEWORK\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Check similarity\n",
|
||||
"score = linker._calculate_text_similarity(\"Python\", \"Python Lang\")\n",
|
||||
"print(f\"Similarity Score: {score}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Configuration\n",
|
||||
"\n",
|
||||
"You can configure the context module using the `config` object or environment variables."
|
||||
"linked = linker.link(\"Python and PyTorch\", entities=entities)\n",
|
||||
"[(e.entity_id, e.uri, len(e.linked_entities)) for e in linked]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a282de3a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.context import config\n",
|
||||
"linker.link_entities(\"e1\", \"e2\", link_type=\"related_to\", confidence=0.8)\n",
|
||||
"linker.get_entity_links(\"e1\")[:2]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2d11f87f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"linker.build_entity_web()[\"statistics\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "072efafd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 8) Low-level building blocks: `AgentMemory` and `ContextRetriever`\n",
|
||||
"\n",
|
||||
"# Set global configuration\n",
|
||||
"config.context_config.set(\"token_limit\", 4096)\n",
|
||||
"config.context_config.set(\"retention_days\", 30)\n",
|
||||
"If you want more control than `AgentContext`, you can wire the parts directly."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3791d6c6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.context import AgentMemory, ContextRetriever\n",
|
||||
"\n",
|
||||
"print(f\"Current Token Limit: {config.context_config.get('token_limit')}\")"
|
||||
"memory = AgentMemory(vector_store=vs, knowledge_graph=kg, retention_policy=\"unlimited\")\n",
|
||||
"memory.store(\"Python powers Semantica.\", metadata={\"type\": \"fact\", \"conversation_id\": \"conv_2\"})\n",
|
||||
"\n",
|
||||
"retriever = ContextRetriever(memory_store=memory, knowledge_graph=kg, vector_store=vs)\n",
|
||||
"results = retriever.retrieve(\"Python Semantica\", max_results=5)\n",
|
||||
"\n",
|
||||
"[(r.content, r.source, round(r.score, 3)) for r in results]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "92060402",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 9) Methods, registry, and configuration\n",
|
||||
"\n",
|
||||
"The `methods` layer exposes convenience functions, while `registry` lets you plug in your own implementations. `config` provides runtime configuration."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "896e7001",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.context.config import context_config\n",
|
||||
"\n",
|
||||
"context_config.set(\"retention_policy\", \"7_days\")\n",
|
||||
"context_config.get(\"retention_policy\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e925a2e0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.context.methods import build_context_graph\n",
|
||||
"from semantica.context.registry import method_registry\n",
|
||||
"\n",
|
||||
"def custom_graph_method(entities, relationships, conversations=None, **kwargs):\n",
|
||||
" return {\n",
|
||||
" \"nodes\": [],\n",
|
||||
" \"edges\": [],\n",
|
||||
" \"statistics\": {\"node_count\": 0, \"edge_count\": 0},\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"method_registry.register(\"graph\", \"custom_demo\", custom_graph_method)\n",
|
||||
"method_registry.list_all(\"graph\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "21fa6cb3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"build_context_graph(\n",
|
||||
" entities=[{\"id\": \"e1\", \"text\": \"Python\", \"type\": \"PROGRAMMING_LANGUAGE\"}],\n",
|
||||
" relationships=[{\"source_id\": \"e1\", \"target_id\": \"e2\", \"type\": \"related_to\"}],\n",
|
||||
" method=\"custom_demo\",\n",
|
||||
")"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -271,7 +432,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.10"
|
||||
"version": "3.11.9"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -1,774 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"[](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/introduction/20_Triple_Store.ipynb)\n",
|
||||
"\n",
|
||||
"# Triple Store - Comprehensive Guide\n",
|
||||
"\n",
|
||||
"## Overview\n",
|
||||
"\n",
|
||||
"This notebook provides a **comprehensive walkthrough** of Semantica's triple_store module, demonstrating RDF triple storage, SPARQL querying, and multi-backend support for knowledge graph persistence.\n",
|
||||
"\n",
|
||||
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/triple_store/)\n",
|
||||
"\n",
|
||||
"### Learning Objectives\n",
|
||||
"\n",
|
||||
"By the end of this notebook, you will be able to:\n",
|
||||
"\n",
|
||||
"- Register and manage triple stores (Blazegraph, Jena, RDF4J, Virtuoso)\n",
|
||||
"- Perform CRUD operations on RDF triples\n",
|
||||
"- Execute SPARQL queries with optimization\n",
|
||||
"- Use bulk loading for large datasets\n",
|
||||
"- Work with multiple store backends\n",
|
||||
"- Validate and track triple operations\n",
|
||||
"- Choose the right backend for your use case\n",
|
||||
"\n",
|
||||
"### What You'll Learn\n",
|
||||
"\n",
|
||||
"| Component | Purpose | When to Use |\n",
|
||||
"|-----------|---------|-------------|\n",
|
||||
"| `TripleManager` | Store coordination | All triple operations |\n",
|
||||
"| `QueryEngine` | SPARQL execution | Query optimization |\n",
|
||||
"| `BulkLoader` | High-volume loading | Large datasets |\n",
|
||||
"| `BlazegraphAdapter` | Blazegraph backend | High performance |\n",
|
||||
"| `JenaAdapter` | Jena backend | Java integration |\n",
|
||||
"| `RDF4JAdapter` | RDF4J backend | Transaction support |\n",
|
||||
"| `VirtuosoAdapter` | Virtuoso backend | Enterprise scale |\n",
|
||||
"\n",
|
||||
"---\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",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 1: Basic Triple Store Operations\n",
|
||||
"\n",
|
||||
"Let's start with the `TripleManager` for basic triple store operations.\n",
|
||||
"\n",
|
||||
"### What is TripleManager?\n",
|
||||
"\n",
|
||||
"`TripleManager` is the main coordinator for triple store operations:\n",
|
||||
"- **Store Registration**: Register multiple backends\n",
|
||||
"- **CRUD Operations**: Add, get, update, delete triples\n",
|
||||
"- **Multi-Store**: Manage multiple stores simultaneously"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.triple_store import TripleManager\n",
|
||||
"from semantica.semantic_extract.triple_extractor import Triple\n",
|
||||
"\n",
|
||||
"# Create triple manager\n",
|
||||
"manager = TripleManager()\n",
|
||||
"\n",
|
||||
"# Register a Blazegraph store (in-memory for demo)\n",
|
||||
"store = manager.register_store(\n",
|
||||
" store_id=\"demo\",\n",
|
||||
" store_type=\"blazegraph\",\n",
|
||||
" endpoint=\"http://localhost:9999/blazegraph/sparql\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"Registered store: {store.store_id}\")\n",
|
||||
"print(f\"Store type: {store.store_type}\")\n",
|
||||
"print(f\"Endpoint: {store.endpoint}\")\n",
|
||||
"\n",
|
||||
"# Create a triple\n",
|
||||
"triple = Triple(\n",
|
||||
" subject=\"http://example.org/Alice\",\n",
|
||||
" predicate=\"http://example.org/knows\",\n",
|
||||
" object=\"http://example.org/Bob\",\n",
|
||||
" confidence=0.95\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Add triple to store\n",
|
||||
"result = manager.add_triple(triple, store_id=\"demo\")\n",
|
||||
"print(f\"\\nTriple added: {result['success']}\")\n",
|
||||
"print(f\"Triple: {triple.subject} -> {triple.predicate} -> {triple.object}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Store Registration and Management\n",
|
||||
"\n",
|
||||
"Register multiple stores and manage them.\n",
|
||||
"\n",
|
||||
"### Supported Backends\n",
|
||||
"\n",
|
||||
"| Backend | Best For | Performance | Features |\n",
|
||||
"|---------|----------|-------------|----------|\n",
|
||||
"| **Blazegraph** | Large datasets | Excellent | GPU acceleration, full-text |\n",
|
||||
"| **Jena** | Java apps | Good | SHACL, inference |\n",
|
||||
"| **RDF4J** | Transactions | Good | ACID, federation |\n",
|
||||
"| **Virtuoso** | Enterprise | Excellent | SQL integration, clustering |"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.triple_store import register_store\n",
|
||||
"\n",
|
||||
"# Register multiple stores using convenience function\n",
|
||||
"blazegraph_store = register_store(\n",
|
||||
" \"blazegraph_main\",\n",
|
||||
" \"blazegraph\",\n",
|
||||
" \"http://localhost:9999/blazegraph/sparql\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"jena_store = register_store(\n",
|
||||
" \"jena_backup\",\n",
|
||||
" \"jena\",\n",
|
||||
" \"http://localhost:3030/ds\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# List all registered stores\n",
|
||||
"stores = manager.list_stores()\n",
|
||||
"print(f\"Registered stores: {stores}\")\n",
|
||||
"\n",
|
||||
"# Get specific store\n",
|
||||
"store = manager.get_store(\"blazegraph_main\")\n",
|
||||
"print(f\"\\nStore details:\")\n",
|
||||
"print(f\" ID: {store.store_id}\")\n",
|
||||
"print(f\" Type: {store.store_type}\")\n",
|
||||
"print(f\" Endpoint: {store.endpoint}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: CRUD Operations\n",
|
||||
"\n",
|
||||
"Perform Create, Read, Update, Delete operations on triples.\n",
|
||||
"\n",
|
||||
"### Operations Overview\n",
|
||||
"\n",
|
||||
"- **Create**: `add_triple()`, `add_triples()`\n",
|
||||
"- **Read**: `get_triple()`\n",
|
||||
"- **Update**: `update_triple()`\n",
|
||||
"- **Delete**: `delete_triple()`"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.triple_store import add_triple, add_triples, get_triples, update_triple, delete_triple\n",
|
||||
"\n",
|
||||
"# Create - Add single triple\n",
|
||||
"triple1 = Triple(\n",
|
||||
" subject=\"http://example.org/Alice\",\n",
|
||||
" predicate=\"http://example.org/hasAge\",\n",
|
||||
" object=\"30\"\n",
|
||||
")\n",
|
||||
"result = add_triple(triple1, store_id=\"demo\")\n",
|
||||
"print(f\"Added single triple: {result['success']}\")\n",
|
||||
"\n",
|
||||
"# Create - Add multiple triples\n",
|
||||
"triples = [\n",
|
||||
" Triple(\"http://example.org/Alice\", \"http://example.org/hasCity\", \"New York\"),\n",
|
||||
" Triple(\"http://example.org/Bob\", \"http://example.org/hasAge\", \"25\"),\n",
|
||||
" Triple(\"http://example.org/Bob\", \"http://example.org/hasCity\", \"Boston\")\n",
|
||||
"]\n",
|
||||
"result = add_triples(triples, store_id=\"demo\")\n",
|
||||
"print(f\"\\nAdded {result['total_triples']} triples in {result['batches']} batches\")\n",
|
||||
"\n",
|
||||
"# Read - Get triples for a subject\n",
|
||||
"alice_triples = get_triples(\n",
|
||||
" subject=\"http://example.org/Alice\",\n",
|
||||
" store_id=\"demo\"\n",
|
||||
")\n",
|
||||
"print(f\"\\nFound {len(alice_triples)} triples for Alice\")\n",
|
||||
"\n",
|
||||
"# Update - Change Alice's age\n",
|
||||
"old_triple = Triple(\"http://example.org/Alice\", \"http://example.org/hasAge\", \"30\")\n",
|
||||
"new_triple = Triple(\"http://example.org/Alice\", \"http://example.org/hasAge\", \"31\")\n",
|
||||
"result = update_triple(old_triple, new_triple, store_id=\"demo\")\n",
|
||||
"print(f\"\\nUpdated triple: {result['success']}\")\n",
|
||||
"\n",
|
||||
"# Delete - Remove a triple\n",
|
||||
"triple_to_delete = Triple(\"http://example.org/Bob\", \"http://example.org/hasCity\", \"Boston\")\n",
|
||||
"result = delete_triple(triple_to_delete, store_id=\"demo\")\n",
|
||||
"print(f\"Deleted triple: {result['success']}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: SPARQL Query Execution\n",
|
||||
"\n",
|
||||
"Execute SPARQL queries with the QueryEngine.\n",
|
||||
"\n",
|
||||
"### Query Types\n",
|
||||
"\n",
|
||||
"- **SELECT**: Retrieve variable bindings\n",
|
||||
"- **ASK**: Boolean queries\n",
|
||||
"- **CONSTRUCT**: Build RDF graphs\n",
|
||||
"- **DESCRIBE**: Describe resources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.triple_store import QueryEngine, BlazegraphAdapter\n",
|
||||
"\n",
|
||||
"# Create query engine with caching\n",
|
||||
"engine = QueryEngine(enable_caching=True, enable_optimization=True)\n",
|
||||
"\n",
|
||||
"# Create adapter\n",
|
||||
"adapter = BlazegraphAdapter(endpoint=\"http://localhost:9999/blazegraph/sparql\")\n",
|
||||
"\n",
|
||||
"# SELECT query\n",
|
||||
"select_query = \"\"\"\n",
|
||||
"PREFIX ex: <http://example.org/>\n",
|
||||
"\n",
|
||||
"SELECT ?person ?age ?city\n",
|
||||
"WHERE {\n",
|
||||
" ?person ex:hasAge ?age .\n",
|
||||
" ?person ex:hasCity ?city .\n",
|
||||
"}\n",
|
||||
"ORDER BY DESC(?age)\n",
|
||||
"LIMIT 10\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"result = engine.execute_query(select_query, adapter)\n",
|
||||
"\n",
|
||||
"print(f\"Query Results:\")\n",
|
||||
"print(f\" Variables: {result.variables}\")\n",
|
||||
"print(f\" Results: {len(result.bindings)}\")\n",
|
||||
"print(f\" Execution time: {result.execution_time:.2f}s\")\n",
|
||||
"print(f\" Cached: {result.metadata.get('cached', False)}\")\n",
|
||||
"\n",
|
||||
"print(\"\\nResults:\")\n",
|
||||
"for binding in result.bindings:\n",
|
||||
" person = binding.get('person', {}).get('value', '')\n",
|
||||
" age = binding.get('age', {}).get('value', '')\n",
|
||||
" city = binding.get('city', {}).get('value', '')\n",
|
||||
" print(f\" {person}: Age {age}, City {city}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 5: Query Optimization\n",
|
||||
"\n",
|
||||
"Optimize SPARQL queries for better performance.\n",
|
||||
"\n",
|
||||
"### Optimization Features\n",
|
||||
"\n",
|
||||
"- **Query Planning**: Analyze execution steps\n",
|
||||
"- **Cost Estimation**: Estimate query cost\n",
|
||||
"- **Query Rewriting**: Optimize query structure\n",
|
||||
"- **Caching**: Cache query results"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.triple_store import optimize_query, plan_query\n",
|
||||
"\n",
|
||||
"# Original query\n",
|
||||
"query = \"\"\"\n",
|
||||
"SELECT ?s ?p ?o\n",
|
||||
"WHERE {\n",
|
||||
" ?s ?p ?o .\n",
|
||||
"}\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"# Optimize query (adds LIMIT if missing)\n",
|
||||
"optimized = optimize_query(query, add_limit=True, default_limit=1000)\n",
|
||||
"print(\"Optimized Query:\")\n",
|
||||
"print(optimized)\n",
|
||||
"\n",
|
||||
"# Create query plan\n",
|
||||
"plan = plan_query(query)\n",
|
||||
"print(f\"\\nQuery Plan:\")\n",
|
||||
"print(f\" Original length: {len(plan.query)}\")\n",
|
||||
"print(f\" Optimized length: {len(plan.optimized_query)}\")\n",
|
||||
"print(f\" Estimated cost: {plan.estimated_cost}\")\n",
|
||||
"print(f\" Execution steps:\")\n",
|
||||
"for i, step in enumerate(plan.execution_steps, 1):\n",
|
||||
" print(f\" {i}. {step}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 6: Bulk Loading\n",
|
||||
"\n",
|
||||
"Load large datasets efficiently with progress tracking.\n",
|
||||
"\n",
|
||||
"### Bulk Loading Features\n",
|
||||
"\n",
|
||||
"- **Batch Processing**: Process in configurable batches\n",
|
||||
"- **Progress Tracking**: Monitor loading progress\n",
|
||||
"- **Retry Mechanism**: Handle failures gracefully\n",
|
||||
"- **Validation**: Validate before loading"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.triple_store import BulkLoader, LoadProgress\n",
|
||||
"\n",
|
||||
"# Create bulk loader\n",
|
||||
"loader = BulkLoader(\n",
|
||||
" batch_size=1000,\n",
|
||||
" max_retries=3\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Generate sample triples\n",
|
||||
"large_dataset = [\n",
|
||||
" Triple(\n",
|
||||
" f\"http://example.org/entity{i}\",\n",
|
||||
" \"http://example.org/hasName\",\n",
|
||||
" f\"Entity {i}\"\n",
|
||||
" )\n",
|
||||
" for i in range(5000)\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Progress callback\n",
|
||||
"def progress_callback(progress: LoadProgress):\n",
|
||||
" print(f\"Progress: {progress.progress_percentage:.1f}% \"\n",
|
||||
" f\"({progress.loaded_triples}/{progress.total_triples}) \"\n",
|
||||
" f\"Batch {progress.current_batch}/{progress.total_batches}\")\n",
|
||||
"\n",
|
||||
"# Load triples with progress tracking\n",
|
||||
"adapter = BlazegraphAdapter(endpoint=\"http://localhost:9999/blazegraph/sparql\")\n",
|
||||
"progress = loader.load_triples(\n",
|
||||
" large_dataset,\n",
|
||||
" adapter,\n",
|
||||
" progress_callback=progress_callback\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"\\nLoading Complete:\")\n",
|
||||
"print(f\" Loaded: {progress.loaded_triples}/{progress.total_triples}\")\n",
|
||||
"print(f\" Failed: {progress.failed_triples}\")\n",
|
||||
"print(f\" Elapsed time: {progress.elapsed_time:.2f}s\")\n",
|
||||
"print(f\" Throughput: {progress.metadata.get('throughput', 0):.0f} triples/sec\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 7: Store Adapters\n",
|
||||
"\n",
|
||||
"Work with different triple store backends.\n",
|
||||
"\n",
|
||||
"### Blazegraph Adapter\n",
|
||||
"\n",
|
||||
"High-performance triple store with GPU acceleration."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.triple_store import BlazegraphAdapter\n",
|
||||
"\n",
|
||||
"# Create Blazegraph adapter\n",
|
||||
"blazegraph = BlazegraphAdapter(\n",
|
||||
" endpoint=\"http://localhost:9999/blazegraph/sparql\",\n",
|
||||
" namespace=\"kb\",\n",
|
||||
" timeout=30\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Add triples\n",
|
||||
"triples = [\n",
|
||||
" Triple(\"http://example.org/Alice\", \"http://example.org/hasSkill\", \"Python\")\n",
|
||||
"]\n",
|
||||
"result = blazegraph.add_triples(triples)\n",
|
||||
"print(f\"Blazegraph - Added: {result['success']}\")\n",
|
||||
"\n",
|
||||
"# Execute SPARQL query\n",
|
||||
"query = \"SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 5\"\n",
|
||||
"result = blazegraph.execute_sparql(query)\n",
|
||||
"print(f\"Blazegraph - Found {len(result['bindings'])} results\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Jena Adapter\n",
|
||||
"\n",
|
||||
"Full-featured RDF framework with inference support."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.triple_store import JenaAdapter\n",
|
||||
"\n",
|
||||
"# Create Jena adapter (in-memory)\n",
|
||||
"jena = JenaAdapter()\n",
|
||||
"\n",
|
||||
"# Or connect to Fuseki endpoint\n",
|
||||
"# jena = JenaAdapter(\n",
|
||||
"# endpoint=\"http://localhost:3030/ds\",\n",
|
||||
"# dataset=\"default\",\n",
|
||||
"# enable_inference=True\n",
|
||||
"# )\n",
|
||||
"\n",
|
||||
"# Add triples with inference\n",
|
||||
"triples = [\n",
|
||||
" Triple(\n",
|
||||
" \"http://example.org/Dog\",\n",
|
||||
" \"http://www.w3.org/2000/01/rdf-schema#subClassOf\",\n",
|
||||
" \"http://example.org/Animal\"\n",
|
||||
" ),\n",
|
||||
" Triple(\n",
|
||||
" \"http://example.org/Fido\",\n",
|
||||
" \"http://www.w3.org/1999/02/22-rdf-syntax-ns#type\",\n",
|
||||
" \"http://example.org/Dog\"\n",
|
||||
" )\n",
|
||||
"]\n",
|
||||
"result = jena.add_triples(triples)\n",
|
||||
"print(f\"Jena - Added: {result['success']}\")\n",
|
||||
"\n",
|
||||
"# Query with inference (Fido is inferred to be an Animal)\n",
|
||||
"query = \"\"\"\n",
|
||||
"PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>\n",
|
||||
"PREFIX ex: <http://example.org/>\n",
|
||||
"SELECT ?animal WHERE {\n",
|
||||
" ?animal rdf:type ex:Animal .\n",
|
||||
"}\n",
|
||||
"\"\"\"\n",
|
||||
"result = jena.query(query)\n",
|
||||
"print(f\"Jena - Found {len(result)} animals (with inference)\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### RDF4J Adapter\n",
|
||||
"\n",
|
||||
"Java-based RDF framework with transaction support."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.triple_store import RDF4JAdapter\n",
|
||||
"\n",
|
||||
"# Create RDF4J adapter\n",
|
||||
"rdf4j = RDF4JAdapter(\n",
|
||||
" server_url=\"http://localhost:8080/rdf4j-server\",\n",
|
||||
" repository_id=\"test\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Add triples with transaction\n",
|
||||
"rdf4j.begin_transaction()\n",
|
||||
"try:\n",
|
||||
" triple = Triple(\n",
|
||||
" \"http://example.org/Alice\",\n",
|
||||
" \"http://example.org/hasEmail\",\n",
|
||||
" \"alice@example.org\"\n",
|
||||
" )\n",
|
||||
" rdf4j.add_triple(\n",
|
||||
" subject=triple.subject,\n",
|
||||
" predicate=triple.predicate,\n",
|
||||
" object_literal=triple.object\n",
|
||||
" )\n",
|
||||
" rdf4j.commit_transaction()\n",
|
||||
" print(\"RDF4J - Transaction committed\")\n",
|
||||
"except Exception as e:\n",
|
||||
" rdf4j.rollback_transaction()\n",
|
||||
" print(f\"RDF4J - Transaction rolled back: {e}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Virtuoso Adapter\n",
|
||||
"\n",
|
||||
"Enterprise-grade RDF store with SQL integration."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.triple_store import VirtuosoAdapter\n",
|
||||
"\n",
|
||||
"# Create Virtuoso adapter\n",
|
||||
"virtuoso = VirtuosoAdapter(\n",
|
||||
" host=\"localhost\",\n",
|
||||
" port=1111,\n",
|
||||
" user=\"dba\",\n",
|
||||
" password=\"dba\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Create named graph\n",
|
||||
"graph_uri = \"http://example.org/graph1\"\n",
|
||||
"virtuoso.create_graph(graph_uri)\n",
|
||||
"\n",
|
||||
"# Add triples to named graph\n",
|
||||
"triple = Triple(\n",
|
||||
" \"http://example.org/Alice\",\n",
|
||||
" \"http://example.org/worksAt\",\n",
|
||||
" \"http://example.org/Company1\"\n",
|
||||
")\n",
|
||||
"virtuoso.add_triple(\n",
|
||||
" subject=triple.subject,\n",
|
||||
" predicate=triple.predicate,\n",
|
||||
" object=triple.object,\n",
|
||||
" graph=graph_uri\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"Virtuoso - Added triple to graph: {graph_uri}\")\n",
|
||||
"\n",
|
||||
"# Query specific graph\n",
|
||||
"query = f\"\"\"\n",
|
||||
"PREFIX ex: <http://example.org/>\n",
|
||||
"SELECT ?person ?company\n",
|
||||
"FROM <{graph_uri}>\n",
|
||||
"WHERE {{\n",
|
||||
" ?person ex:worksAt ?company .\n",
|
||||
"}}\n",
|
||||
"\"\"\"\n",
|
||||
"result = virtuoso.query(query)\n",
|
||||
"print(f\"Virtuoso - Found {len(result)} results in graph\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 8: Triple Validation\n",
|
||||
"\n",
|
||||
"Validate triples before adding them to the store.\n",
|
||||
"\n",
|
||||
"### Validation Checks\n",
|
||||
"\n",
|
||||
"- **Required Fields**: Subject, predicate, object\n",
|
||||
"- **Confidence Range**: 0-1 if provided\n",
|
||||
"- **URI Format**: Valid URIs\n",
|
||||
"- **Empty Components**: No empty values"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.triple_store import validate_triples\n",
|
||||
"\n",
|
||||
"# Create triples (some invalid)\n",
|
||||
"triples_to_validate = [\n",
|
||||
" Triple(\"http://example.org/Alice\", \"http://example.org/knows\", \"http://example.org/Bob\"), # Valid\n",
|
||||
" Triple(\"\", \"http://example.org/knows\", \"http://example.org/Charlie\"), # Invalid (empty subject)\n",
|
||||
" Triple(\"http://example.org/Dave\", \"\", \"http://example.org/Eve\"), # Invalid (empty predicate)\n",
|
||||
" Triple(\"http://example.org/Frank\", \"http://example.org/knows\", \"http://example.org/Grace\", confidence=1.5), # Invalid (confidence > 1)\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"# Validate triples\n",
|
||||
"validation = validate_triples(triples_to_validate)\n",
|
||||
"\n",
|
||||
"print(\"Validation Results:\")\n",
|
||||
"print(f\" Valid: {validation['valid']}\")\n",
|
||||
"print(f\" Valid triples: {validation['valid_triples']}/{validation['total_triples']}\")\n",
|
||||
"print(f\"\\nErrors: {len(validation['errors'])}\")\n",
|
||||
"for error in validation['errors']:\n",
|
||||
" print(f\" - {error}\")\n",
|
||||
"print(f\"\\nWarnings: {len(validation['warnings'])}\")\n",
|
||||
"for warning in validation['warnings']:\n",
|
||||
" print(f\" - {warning}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 9: Multi-Store Operations\n",
|
||||
"\n",
|
||||
"Work with multiple stores simultaneously.\n",
|
||||
"\n",
|
||||
"### Use Cases\n",
|
||||
"\n",
|
||||
"- **Primary/Backup**: Replicate to backup store\n",
|
||||
"- **Read/Write Split**: Separate read and write stores\n",
|
||||
"- **Multi-Tenant**: Different stores for different tenants"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Register multiple stores\n",
|
||||
"manager = TripleManager()\n",
|
||||
"\n",
|
||||
"primary = manager.register_store(\n",
|
||||
" \"primary\",\n",
|
||||
" \"blazegraph\",\n",
|
||||
" \"http://localhost:9999/blazegraph/sparql\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"backup = manager.register_store(\n",
|
||||
" \"backup\",\n",
|
||||
" \"jena\",\n",
|
||||
" \"http://localhost:3030/ds\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Add to primary store\n",
|
||||
"triple = Triple(\n",
|
||||
" \"http://example.org/Document1\",\n",
|
||||
" \"http://example.org/hasAuthor\",\n",
|
||||
" \"http://example.org/Alice\"\n",
|
||||
")\n",
|
||||
"manager.add_triple(triple, store_id=\"primary\")\n",
|
||||
"print(\"Added to primary store\")\n",
|
||||
"\n",
|
||||
"# Replicate to backup store\n",
|
||||
"manager.add_triple(triple, store_id=\"backup\")\n",
|
||||
"print(\"Replicated to backup store\")\n",
|
||||
"\n",
|
||||
"# List all stores\n",
|
||||
"stores = manager.list_stores()\n",
|
||||
"print(f\"\\nActive stores: {stores}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 10: Best Practices\n",
|
||||
"\n",
|
||||
"### Choosing the Right Backend\n",
|
||||
"\n",
|
||||
"1. **Blazegraph**: High-performance, large datasets, GPU acceleration\n",
|
||||
"2. **Jena**: Java integration, SHACL validation, inference\n",
|
||||
"3. **RDF4J**: Transaction support, ACID guarantees, federation\n",
|
||||
"4. **Virtuoso**: Enterprise scale, SQL integration, clustering\n",
|
||||
"\n",
|
||||
"### Performance Tips\n",
|
||||
"\n",
|
||||
"- **Batch Operations**: Use `add_triples()` for multiple triples\n",
|
||||
"- **Query Optimization**: Enable optimization and caching\n",
|
||||
"- **Bulk Loading**: Use `BulkLoader` for large datasets\n",
|
||||
"- **Validation**: Validate before loading to avoid errors\n",
|
||||
"\n",
|
||||
"### Configuration\n",
|
||||
"\n",
|
||||
"- **Batch Size**: 1000-10000 for bulk loading\n",
|
||||
"- **Cache Size**: 1000-5000 for query caching\n",
|
||||
"- **Timeout**: 30-60 seconds for queries\n",
|
||||
"- **Retries**: 3-5 for bulk operations"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"### What You've Learned\n",
|
||||
"\n",
|
||||
"In this notebook, you've learned how to:\n",
|
||||
"\n",
|
||||
"- Register and manage triple stores\n",
|
||||
"- Perform CRUD operations on RDF triples\n",
|
||||
"- Execute and optimize SPARQL queries\n",
|
||||
"- Use bulk loading for large datasets\n",
|
||||
"- Work with multiple store backends\n",
|
||||
"- Validate triples before operations\n",
|
||||
"- Choose the right backend for your use case\n",
|
||||
"\n",
|
||||
"### Key Takeaways\n",
|
||||
"\n",
|
||||
"1. **Multi-Backend Support**: Choose the right backend for your needs\n",
|
||||
"2. **SPARQL Power**: Full SPARQL 1.1 support with optimization\n",
|
||||
"3. **Bulk Loading**: Efficient loading with progress tracking\n",
|
||||
"4. **Query Optimization**: Automatic query optimization and caching\n",
|
||||
"5. **Validation**: Pre-load validation prevents errors\n",
|
||||
"6. **Multi-Store**: Manage multiple stores simultaneously\n",
|
||||
"\n",
|
||||
"### Next Steps\n",
|
||||
"\n",
|
||||
"**Further Reading**:\n",
|
||||
"- [Triple Store API Reference](https://semantica.readthedocs.io/reference/triple_store/)\n",
|
||||
"- [SPARQL 1.1 Specification](https://www.w3.org/TR/sparql11-query/)\n",
|
||||
"- [Knowledge Graph Building](../use_cases/advanced_rag/01_GraphRAG_Complete.ipynb)\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"**Questions or Issues?** Check out our [GitHub repository](https://github.com/Hawksight-AI/semantica) or [documentation](https://semantica.readthedocs.io)."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.0"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Getting Started with Triplet Store\n",
|
||||
"\n",
|
||||
"This notebook introduces the **Semantica Triplet Store** module, which allows you to store and query knowledge graph data using industry-standard RDF Triple Stores.\n",
|
||||
"\n",
|
||||
"## What is a Triplet Store?\n",
|
||||
"\n",
|
||||
"A Triplet Store (or RDF Store) is a database optimized for storing and retrieving triples: **Subject - Predicate - Object**.\n",
|
||||
"For example: `Alice` (Subject) `knows` (Predicate) `Bob` (Object).\n",
|
||||
"\n",
|
||||
"Semantica supports:\n",
|
||||
"- **Blazegraph** (Default, High Performance)\n",
|
||||
"- **Apache Jena** (Great for inference)\n",
|
||||
"- **RDF4J** (Standard Java framework)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import sys\n",
|
||||
"import os\n",
|
||||
"\n",
|
||||
"# Add the project root to the path so we can import the local version of semantica\n",
|
||||
"sys.path.append(os.path.abspath('../../'))\n",
|
||||
"\n",
|
||||
"# If running in Google Colab, uncomment the following line to install dependencies\n",
|
||||
"# !pip install -q semantica"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Import the TripletStore class\n",
|
||||
"from semantica.triplet_store import TripletStore\n",
|
||||
"from semantica.semantic_extract.triplet_extractor import Triplet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. Connecting to a Store\n",
|
||||
"\n",
|
||||
"To use the Triplet Store, you need a backend running. In this example, we assume a Blazegraph instance is running locally.\n",
|
||||
"\n",
|
||||
"> **Note:** If you don't have a store running, the code below shows how you *would* connect."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Connect to a Blazegraph instance\n",
|
||||
"# You can also use backend=\"jena\" or backend=\"rdf4j\"\n",
|
||||
"store = TripletStore(\n",
|
||||
" backend=\"blazegraph\",\n",
|
||||
" endpoint=\"http://localhost:9999/blazegraph\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Check connection status\n",
|
||||
"if hasattr(store._store_backend, 'connected') and store._store_backend.connected:\n",
|
||||
" print(f\"Successfully connected to {store.backend_type} store at {store.endpoint}\")\n",
|
||||
"else:\n",
|
||||
" print(f\"Warning: Could not connect to {store.backend_type} at {store.endpoint}\")\n",
|
||||
" print(\"Operations requiring a live store connection will be skipped or fail.\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Creating Triplets\n",
|
||||
"\n",
|
||||
"We use the `Triplet` class to define our data."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Define a single triplet\n",
|
||||
"triplet1 = Triplet(\n",
|
||||
" subject=\"http://example.org/Alice\",\n",
|
||||
" predicate=\"http://xmlns.com/foaf/0.1/knows\",\n",
|
||||
" object=\"http://example.org/Bob\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(f\"Created triplet: {triplet1.subject} -> {triplet1.predicate} -> {triplet1.object}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Adding Data\n",
|
||||
"\n",
|
||||
"You can add triplets one by one or in bulk."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from semantica.utils.exceptions import ProcessingError\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" # Add a single triplet\n",
|
||||
" store.add_triplet(triplet1)\n",
|
||||
" print(\"Added single triplet successfully.\")\n",
|
||||
"\n",
|
||||
" # Create more triplets\n",
|
||||
" triplets = [\n",
|
||||
" Triplet(\n",
|
||||
" subject=\"http://example.org/Bob\",\n",
|
||||
" predicate=\"http://xmlns.com/foaf/0.1/knows\",\n",
|
||||
" object=\"http://example.org/Charlie\"\n",
|
||||
" ),\n",
|
||||
" Triplet(\n",
|
||||
" subject=\"http://example.org/Charlie\",\n",
|
||||
" predicate=\"http://xmlns.com/foaf/0.1/knows\",\n",
|
||||
" object=\"http://example.org/David\"\n",
|
||||
" )\n",
|
||||
" ]\n",
|
||||
"\n",
|
||||
" # Bulk add\n",
|
||||
" store.add_triplets(triplets)\n",
|
||||
" print(\"Added bulk triplets successfully.\")\n",
|
||||
"\n",
|
||||
"except ProcessingError as e:\n",
|
||||
" print(f\"Operation skipped: {e}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"An error occurred: {e}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Querying Data (SPARQL)\n",
|
||||
"\n",
|
||||
"Use SPARQL queries to retrieve data from the store."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Simple query to get all triplets (limited to 10)\n",
|
||||
"query = \"\"\"\n",
|
||||
"SELECT ?s ?p ?o\n",
|
||||
"WHERE {\n",
|
||||
" ?s ?p ?o\n",
|
||||
"}\n",
|
||||
"LIMIT 10\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"try:\n",
|
||||
" results = store.execute_query(query)\n",
|
||||
" print(\"Query Results:\", results)\n",
|
||||
"except ProcessingError as e:\n",
|
||||
" print(f\"Query skipped: {e}\")\n",
|
||||
"except Exception as e:\n",
|
||||
" print(f\"An error occurred: {e}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Deleting Data\n",
|
||||
"\n",
|
||||
"Remove triplets when they are no longer needed."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"store.delete_triplet(triplet1)\n",
|
||||
"print(\"Deleted triplet1\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Next Steps\n",
|
||||
"\n",
|
||||
"Check out the **Advanced Triplet Store** guide in the `cookbook/advanced` folder for more complex operations like bulk loading optimization, transactions, and advanced SPARQL features."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"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": 4
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
api_keys:
|
||||
openai: your_key_here
|
||||
anthropic: your_key_here
|
||||
embedding:
|
||||
provider: openai
|
||||
model: text-embedding-3-large
|
||||
dimensions: 3072
|
||||
knowledge_graph:
|
||||
backend: networkx
|
||||
temporal: true
|
||||
@@ -0,0 +1,63 @@
|
||||
@prefix : <https://docs.semantica.dev/ontology/v1.0> .
|
||||
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
||||
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
||||
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
|
||||
|
||||
<https://docs.semantica.dev/ontology/founded> a owl:DatatypeProperty ;
|
||||
rdfs:label "founded" ;
|
||||
rdfs:domain <https://docs.semantica.dev/ontology/Company> ;
|
||||
rdfs:range xsd:string .
|
||||
|
||||
<https://docs.semantica.dev/ontology/leads> a owl:ObjectProperty ;
|
||||
rdfs:label "leads" ;
|
||||
rdfs:domain <https://docs.semantica.dev/ontology/OwlThing> ;
|
||||
rdfs:range <https://docs.semantica.dev/ontology/OwlThing> .
|
||||
|
||||
<https://docs.semantica.dev/ontology/manages> a owl:ObjectProperty ;
|
||||
rdfs:label "manages" ;
|
||||
rdfs:domain <https://docs.semantica.dev/ontology/OwlThing> ;
|
||||
rdfs:range <https://docs.semantica.dev/ontology/OwlThing> .
|
||||
|
||||
<https://docs.semantica.dev/ontology/name> a owl:DatatypeProperty ;
|
||||
rdfs:label "name" ;
|
||||
rdfs:domain <https://docs.semantica.dev/ontology/Company>,
|
||||
<https://docs.semantica.dev/ontology/Department>,
|
||||
<https://docs.semantica.dev/ontology/Person>,
|
||||
<https://docs.semantica.dev/ontology/Project> ;
|
||||
rdfs:range xsd:string .
|
||||
|
||||
<https://docs.semantica.dev/ontology/partOf> a owl:ObjectProperty ;
|
||||
rdfs:label "partOf" ;
|
||||
rdfs:domain <https://docs.semantica.dev/ontology/OwlThing> ;
|
||||
rdfs:range <https://docs.semantica.dev/ontology/OwlThing> .
|
||||
|
||||
<https://docs.semantica.dev/ontology/role> a owl:DatatypeProperty ;
|
||||
rdfs:label "role" ;
|
||||
rdfs:domain <https://docs.semantica.dev/ontology/Person> ;
|
||||
rdfs:range xsd:string .
|
||||
|
||||
: a owl:Ontology ;
|
||||
rdfs:label "CorporateOntology" ;
|
||||
owl:versionInfo "1.0" .
|
||||
|
||||
<https://docs.semantica.dev/ontology/worksOn> a owl:ObjectProperty ;
|
||||
rdfs:label "worksOn" ;
|
||||
rdfs:domain <https://docs.semantica.dev/ontology/OwlThing> ;
|
||||
rdfs:range <https://docs.semantica.dev/ontology/OwlThing> .
|
||||
|
||||
<https://docs.semantica.dev/ontology/Department> a owl:Class ;
|
||||
rdfs:label "Department" ;
|
||||
rdfs:comment "Class representing department entities" .
|
||||
|
||||
<https://docs.semantica.dev/ontology/Project> a owl:Class ;
|
||||
rdfs:label "Project" ;
|
||||
rdfs:comment "Class representing project entities" .
|
||||
|
||||
<https://docs.semantica.dev/ontology/Company> a owl:Class ;
|
||||
rdfs:label "Company" ;
|
||||
rdfs:comment "Class representing company entities" .
|
||||
|
||||
<https://docs.semantica.dev/ontology/Person> a owl:Class ;
|
||||
rdfs:label "Person" ;
|
||||
rdfs:comment "Class representing person entities" .
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
Graph Retrieval-Augmented Generation (GraphRAG): A New Era for Intelligent Search
|
||||
|
||||
GraphRAG is an advanced technique that combines the retrieval capabilities of vector databases with the structural reasoning of knowledge graphs. Unlike traditional RAG, which relies solely on vector similarity, GraphRAG leverages the relationships between entities to provide more contextually accurate and comprehensive answers.
|
||||
|
||||
Key Components:
|
||||
1. Knowledge Graph: A structured representation of data where nodes represent entities and edges represent relationships.
|
||||
2. Vector Search: Finds semantically similar text chunks.
|
||||
3. Graph Traversal: Navigates the knowledge graph to find related entities that might not be semantically similar but are structurally relevant.
|
||||
|
||||
Benefits:
|
||||
- Improved Context: By following relationships, the system can understand the broader context of a query.
|
||||
- Multi-hop Reasoning: Can answer complex questions that require connecting multiple pieces of information.
|
||||
- Reduced Hallucinations: Grounding answers in a verified knowledge structure reduces the likelihood of generating false information.
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
RETINOL CLINICAL GUIDE
|
||||
Mechanism: Binds to retinoic acid receptors to increase cellular turnover.
|
||||
Precautions: Should not be used with high-concentration AHA/BHA exfoliants.
|
||||
Synergy: Highly effective when paired with Niacinamide to offset potential erythema.
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
RETINOL CLINICAL GUIDE v2.1
|
||||
Mechanism: Binds to retinoic acid receptors (RAR) to increase cellular turnover.
|
||||
Precautions: Should not be used with high-concentration AHA/BHA exfoliants.
|
||||
Synergy: Highly effective when paired with Niacinamide to offset potential erythema.
|
||||
Target: Stratum corneum thickening and dermal collagen synthesis.
|
||||
@@ -0,0 +1,254 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
|
||||
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
|
||||
|
||||
<key id="type" for="node" attr.name="type" attr.type="string"/>
|
||||
<key id="confidence" for="node" attr.name="confidence" attr.type="double"/>
|
||||
|
||||
<graph id="G" edgedefault="directed">
|
||||
|
||||
<node id="makeup_and_beauty_blog">
|
||||
<data key="label">Makeup and Beauty Blog</data>
|
||||
<data key="type">ORG</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="monday_poll">
|
||||
<data key="label">Monday Poll</data>
|
||||
<data key="type">EVENT</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="2007">
|
||||
<data key="label">2007</data>
|
||||
<data key="type">DATE</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="rosacea">
|
||||
<data key="label">Rosacea</data>
|
||||
<data key="type">CONCEPT</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="dr._bailey">
|
||||
<data key="label">Dr. Bailey</data>
|
||||
<data key="type">PERSON</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="green_tea_antioxidant_skin_therapy">
|
||||
<data key="label">Green Tea Antioxidant Skin Therapy</data>
|
||||
<data key="type">PRODUCT</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="vol._892">
|
||||
<data key="label">Vol. 892</data>
|
||||
<data key="type">EVENT</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="laneige">
|
||||
<data key="label">Laneige</data>
|
||||
<data key="type">ORG</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="sausalito">
|
||||
<data key="label">Sausalito</data>
|
||||
<data key="type">GPE</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="ulta">
|
||||
<data key="label">Ulta</data>
|
||||
<data key="type">ORG</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="december_15,_2025">
|
||||
<data key="label">December 15, 2025</data>
|
||||
<data key="type">DATE</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="jo_malone">
|
||||
<data key="label">Jo Malone</data>
|
||||
<data key="type">ORG</data>
|
||||
<data key="confidence">1</data>
|
||||
</node>
|
||||
<node id="trader_joe">
|
||||
<data key="label">Trader Joe</data>
|
||||
<data key="type">ORG</data>
|
||||
<data key="confidence">1</data>
|
||||
</node>
|
||||
<node id="hawaii">
|
||||
<data key="label">hawaii</data>
|
||||
<data key="type">GPE</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="benzoyl_peroxide_cream">
|
||||
<data key="label">Benzoyl Peroxide Cream</data>
|
||||
<data key="type">PRODUCT</data>
|
||||
<data key="confidence">1</data>
|
||||
</node>
|
||||
<node id="facial_dandruff">
|
||||
<data key="label">Facial dandruff</data>
|
||||
<data key="type">CONCEPT</data>
|
||||
<data key="confidence">1</data>
|
||||
</node>
|
||||
<node id="calming_zinc_soap">
|
||||
<data key="label">Calming Zinc Soap</data>
|
||||
<data key="type">PRODUCT</data>
|
||||
<data key="confidence">1</data>
|
||||
</node>
|
||||
<node id="hydrate">
|
||||
<data key="label">Hydrate</data>
|
||||
<data key="type">CONCEPT</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="daily_moisturizing_face_cream">
|
||||
<data key="label">Daily Moisturizing Face Cream</data>
|
||||
<data key="type">PRODUCT</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
<node id="omega_enriched_face_booster_oil">
|
||||
<data key="label">Omega Enriched Face Booster Oil</data>
|
||||
<data key="type">PRODUCT</data>
|
||||
<data key="confidence">1.0</data>
|
||||
</node>
|
||||
|
||||
<edge source="Makeup and Beauty Blog" target="Monday Poll">
|
||||
<data key="label">hosts</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Monday Poll" target="December 15, 2025">
|
||||
<data key="label">occurs on</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Makeup and Beauty Blog" target="Makeup and Beauty Blog Monday Poll, Vol. 893">
|
||||
<data key="label">publishes</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Makeup and Beauty Blog" target="Monday">
|
||||
<data key="label">has</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Makeup and Beauty Blog" target="2007">
|
||||
<data key="label">has</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Makeup and Beauty Blog" target="Monday Poll">
|
||||
<data key="label">hosts</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Makeup and Beauty Blog" target="Makeup and Beauty Blog Monday Poll">
|
||||
<data key="label">posts</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Makeup and Beauty Blog" target="Vol. 892">
|
||||
<data key="label">posts</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Makeup and Beauty Blog" target="2007">
|
||||
<data key="label">has been active since</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="MBB" target="Makeup and Beauty Blog">
|
||||
<data key="label">related_to</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Makeup and Beauty Blog" target="Makeup and Beauty Blog">
|
||||
<data key="label">related_to</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Makeup and Beauty Blog" target="Monday Poll">
|
||||
<data key="label">hosts</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Makeup and Beauty Blog" target="Vol. 891">
|
||||
<data key="label">posts</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Makeup and Beauty Blog" target="Monday Poll">
|
||||
<data key="label">posts</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Cavallo Point" target="Sausalito">
|
||||
<data key="label">located_in</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Dr. Bailey" target="Green Tea Antioxidant Skin Therapy">
|
||||
<data key="label">prescribes</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Green Tea Antioxidant Skin Therapy" target="Rosacea Therapy Skin Care Kit">
|
||||
<data key="label">part of</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Dr. Bailey" target="Rosacea Therapy Skin Care Kit">
|
||||
<data key="label">uses</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Rosacea Therapy Skin Care Kit" target="rosacea treatment routine">
|
||||
<data key="label">part of</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Dr. Bailey" target="rosacea treatment routine">
|
||||
<data key="label">uses</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Facial dandruff" target="rosacea">
|
||||
<data key="label">often occurs with</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Facial dandruff" target="rosacea">
|
||||
<data key="label">needs to be addressed</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Calming Zinc Soap" target="Facial dandruff">
|
||||
<data key="label">is often sufficient to control</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Calming Zinc Soap" target="rosacea">
|
||||
<data key="label">is often sufficient to control</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Green Tea Antioxidant Skin Therapy" target="Facial dandruff">
|
||||
<data key="label">is often sufficient to control</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Green Tea Antioxidant Skin Therapy" target="rosacea">
|
||||
<data key="label">is often sufficient to control</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Dr. Bailey's Skincare" target="Calming Zinc Soap">
|
||||
<data key="label">produces</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Dr. Bailey's Skincare" target="Green Tea Antioxidant Skin Therapy">
|
||||
<data key="label">produces</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Dr. Bailey" target="Calming Zinc Soap">
|
||||
<data key="label">prescribes</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Dr. Bailey" target="Green Tea Antioxidant Skin Therapy">
|
||||
<data key="label">prescribes</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Hydrate" target="Daily Moisturizing Face Cream">
|
||||
<data key="label">is_achieved_by</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Daily Moisturizing Face Cream" target="Omega Enriched Face Booster Oil">
|
||||
<data key="label">can_be_combined_with</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Omega Enriched Face Booster Oil" target="castor seed oil">
|
||||
<data key="label">contains</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Omega Enriched Face Booster Oil" target="sea buckthorn">
|
||||
<data key="label">contains</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
<edge source="Daily Moisturizing Face Cream" target="Omega Enriched Face Booster Oil">
|
||||
<data key="label">can_be_replaced_with</data>
|
||||
<data key="confidence">0.9</data>
|
||||
</edge>
|
||||
</graph>
|
||||
</graphml>
|
||||
@@ -0,0 +1,678 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "makeup_and_beauty_blog",
|
||||
"label": "Makeup and Beauty Blog",
|
||||
"type": "ORG",
|
||||
"attributes": {
|
||||
"confidence": 1.0,
|
||||
"provenance": {
|
||||
"merged_from": [
|
||||
{
|
||||
"id": "makeup_and_beauty_blog",
|
||||
"name": "Makeup and Beauty Blog",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "makeup_and_beauty_blog",
|
||||
"name": "Makeup and Beauty Blog",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "makeup_and_beauty_blog_monday_poll,_vol._893",
|
||||
"name": "Makeup and Beauty Blog Monday Poll, Vol. 893",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "makeup_and_beauty_blog_monday_poll",
|
||||
"name": "Makeup and Beauty Blog Monday Poll",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "mbb",
|
||||
"name": "MBB",
|
||||
"source": null
|
||||
}
|
||||
],
|
||||
"merge_count": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "monday_poll",
|
||||
"label": "Monday Poll",
|
||||
"type": "EVENT",
|
||||
"attributes": {
|
||||
"confidence": 1.0,
|
||||
"provenance": {
|
||||
"merged_from": [
|
||||
{
|
||||
"id": "monday_poll",
|
||||
"name": "Monday Poll",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "monday_poll",
|
||||
"name": "Monday Poll",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "monday",
|
||||
"name": "Monday",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "holiday",
|
||||
"name": "holiday",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "holiday",
|
||||
"name": "holiday",
|
||||
"source": null
|
||||
}
|
||||
],
|
||||
"merge_count": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "2007",
|
||||
"label": "2007",
|
||||
"type": "DATE",
|
||||
"attributes": {
|
||||
"confidence": 1.0,
|
||||
"provenance": {
|
||||
"merged_from": [
|
||||
{
|
||||
"id": "2007",
|
||||
"name": "2007",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "2007",
|
||||
"name": "2007",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "2024",
|
||||
"name": "2024",
|
||||
"source": null
|
||||
}
|
||||
],
|
||||
"merge_count": 3
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rosacea",
|
||||
"label": "Rosacea",
|
||||
"type": "CONCEPT",
|
||||
"attributes": {
|
||||
"confidence": 1.0,
|
||||
"provenance": {
|
||||
"merged_from": [
|
||||
{
|
||||
"id": "rosacea",
|
||||
"name": "Rosacea",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "rosacea",
|
||||
"name": "rosacea",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "rosacea_treatment_routine",
|
||||
"name": "rosacea treatment routine",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "rosie",
|
||||
"name": "Rosie",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "rosacea_therapy_skin_care_kit",
|
||||
"name": "Rosacea Therapy Skin Care Kit",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "marnie",
|
||||
"name": "Marnie",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "cavallo_point",
|
||||
"name": "Cavallo Point",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "castor_seed_oil",
|
||||
"name": "castor seed oil",
|
||||
"source": null
|
||||
}
|
||||
],
|
||||
"merge_count": 8
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "dr._bailey",
|
||||
"label": "Dr. Bailey",
|
||||
"type": "PERSON",
|
||||
"attributes": {
|
||||
"confidence": 1.0,
|
||||
"provenance": {
|
||||
"merged_from": [
|
||||
{
|
||||
"id": "dr._bailey",
|
||||
"name": "Dr. Bailey",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "dr._bailey",
|
||||
"name": "Dr. Bailey",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "dr._bailey's_skincare",
|
||||
"name": "Dr. Bailey's Skincare",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "dr._bailey's_skincare",
|
||||
"name": "Dr. Bailey's Skincare",
|
||||
"source": null
|
||||
}
|
||||
],
|
||||
"merge_count": 4
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "green_tea_antioxidant_skin_therapy",
|
||||
"label": "Green Tea Antioxidant Skin Therapy",
|
||||
"type": "PRODUCT",
|
||||
"attributes": {
|
||||
"confidence": 1.0,
|
||||
"provenance": {
|
||||
"merged_from": [
|
||||
{
|
||||
"id": "green_tea_antioxidant_skin_therapy",
|
||||
"name": "Green Tea Antioxidant Skin Therapy",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "green_tea_antioxidant_skin_therapy",
|
||||
"name": "Green Tea Antioxidant Skin Therapy",
|
||||
"source": null
|
||||
}
|
||||
],
|
||||
"merge_count": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "vol._892",
|
||||
"label": "Vol. 892",
|
||||
"type": "EVENT",
|
||||
"attributes": {
|
||||
"confidence": 1.0,
|
||||
"provenance": {
|
||||
"merged_from": [
|
||||
{
|
||||
"id": "vol._892",
|
||||
"name": "Vol. 892",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "vol._891",
|
||||
"name": "Vol. 891",
|
||||
"source": null
|
||||
}
|
||||
],
|
||||
"merge_count": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "laneige",
|
||||
"label": "Laneige",
|
||||
"type": "ORG",
|
||||
"attributes": {
|
||||
"confidence": 1.0,
|
||||
"provenance": {
|
||||
"merged_from": [
|
||||
{
|
||||
"id": "laneige",
|
||||
"name": "Laneige",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "lanikai",
|
||||
"name": "Lanikai",
|
||||
"source": null
|
||||
}
|
||||
],
|
||||
"merge_count": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "sausalito",
|
||||
"label": "Sausalito",
|
||||
"type": "GPE",
|
||||
"attributes": {
|
||||
"confidence": 1.0,
|
||||
"provenance": {
|
||||
"merged_from": [
|
||||
{
|
||||
"id": "sausalito",
|
||||
"name": "Sausalito",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "sea_buckthorn",
|
||||
"name": "sea buckthorn",
|
||||
"source": null
|
||||
}
|
||||
],
|
||||
"merge_count": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ulta",
|
||||
"label": "Ulta",
|
||||
"type": "ORG",
|
||||
"attributes": {
|
||||
"confidence": 1.0,
|
||||
"provenance": {
|
||||
"merged_from": [
|
||||
{
|
||||
"id": "ulta",
|
||||
"name": "Ulta",
|
||||
"source": null
|
||||
},
|
||||
{
|
||||
"id": "clotrimazole",
|
||||
"name": "clotrimazole",
|
||||
"source": null
|
||||
}
|
||||
],
|
||||
"merge_count": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "december_15,_2025",
|
||||
"label": "December 15, 2025",
|
||||
"type": "DATE",
|
||||
"attributes": {
|
||||
"confidence": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "jo_malone",
|
||||
"label": "Jo Malone",
|
||||
"type": "ORG",
|
||||
"attributes": {
|
||||
"confidence": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "trader_joe",
|
||||
"label": "Trader Joe",
|
||||
"type": "ORG",
|
||||
"attributes": {
|
||||
"confidence": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "hawaii",
|
||||
"label": "hawaii",
|
||||
"type": "GPE",
|
||||
"attributes": {
|
||||
"confidence": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "benzoyl_peroxide_cream",
|
||||
"label": "Benzoyl Peroxide Cream",
|
||||
"type": "PRODUCT",
|
||||
"attributes": {
|
||||
"confidence": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "facial_dandruff",
|
||||
"label": "Facial dandruff",
|
||||
"type": "CONCEPT",
|
||||
"attributes": {
|
||||
"confidence": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "calming_zinc_soap",
|
||||
"label": "Calming Zinc Soap",
|
||||
"type": "PRODUCT",
|
||||
"attributes": {
|
||||
"confidence": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "hydrate",
|
||||
"label": "Hydrate",
|
||||
"type": "CONCEPT",
|
||||
"attributes": {
|
||||
"confidence": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "daily_moisturizing_face_cream",
|
||||
"label": "Daily Moisturizing Face Cream",
|
||||
"type": "PRODUCT",
|
||||
"attributes": {
|
||||
"confidence": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "omega_enriched_face_booster_oil",
|
||||
"label": "Omega Enriched Face Booster Oil",
|
||||
"type": "PRODUCT",
|
||||
"attributes": {
|
||||
"confidence": 1.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "Monday Poll",
|
||||
"type": "hosts",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Monday Poll",
|
||||
"target": "December 15, 2025",
|
||||
"type": "occurs on",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "Makeup and Beauty Blog Monday Poll, Vol. 893",
|
||||
"type": "publishes",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "Monday",
|
||||
"type": "has",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "2007",
|
||||
"type": "has",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "Monday Poll",
|
||||
"type": "hosts",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "Makeup and Beauty Blog Monday Poll",
|
||||
"type": "posts",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "Vol. 892",
|
||||
"type": "posts",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "2007",
|
||||
"type": "has been active since",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "MBB",
|
||||
"target": "Makeup and Beauty Blog",
|
||||
"type": "related_to",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "Makeup and Beauty Blog",
|
||||
"type": "related_to",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "Monday Poll",
|
||||
"type": "hosts",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "Vol. 891",
|
||||
"type": "posts",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Makeup and Beauty Blog",
|
||||
"target": "Monday Poll",
|
||||
"type": "posts",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Cavallo Point",
|
||||
"target": "Sausalito",
|
||||
"type": "located_in",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Dr. Bailey",
|
||||
"target": "Green Tea Antioxidant Skin Therapy",
|
||||
"type": "prescribes",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Green Tea Antioxidant Skin Therapy",
|
||||
"target": "Rosacea Therapy Skin Care Kit",
|
||||
"type": "part of",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Dr. Bailey",
|
||||
"target": "Rosacea Therapy Skin Care Kit",
|
||||
"type": "uses",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Rosacea Therapy Skin Care Kit",
|
||||
"target": "rosacea treatment routine",
|
||||
"type": "part of",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Dr. Bailey",
|
||||
"target": "rosacea treatment routine",
|
||||
"type": "uses",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Facial dandruff",
|
||||
"target": "rosacea",
|
||||
"type": "often occurs with",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Facial dandruff",
|
||||
"target": "rosacea",
|
||||
"type": "needs to be addressed",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Calming Zinc Soap",
|
||||
"target": "Facial dandruff",
|
||||
"type": "is often sufficient to control",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Calming Zinc Soap",
|
||||
"target": "rosacea",
|
||||
"type": "is often sufficient to control",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Green Tea Antioxidant Skin Therapy",
|
||||
"target": "Facial dandruff",
|
||||
"type": "is often sufficient to control",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Green Tea Antioxidant Skin Therapy",
|
||||
"target": "rosacea",
|
||||
"type": "is often sufficient to control",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Dr. Bailey's Skincare",
|
||||
"target": "Calming Zinc Soap",
|
||||
"type": "produces",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Dr. Bailey's Skincare",
|
||||
"target": "Green Tea Antioxidant Skin Therapy",
|
||||
"type": "produces",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Dr. Bailey",
|
||||
"target": "Calming Zinc Soap",
|
||||
"type": "prescribes",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Dr. Bailey",
|
||||
"target": "Green Tea Antioxidant Skin Therapy",
|
||||
"type": "prescribes",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Hydrate",
|
||||
"target": "Daily Moisturizing Face Cream",
|
||||
"type": "is_achieved_by",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Daily Moisturizing Face Cream",
|
||||
"target": "Omega Enriched Face Booster Oil",
|
||||
"type": "can_be_combined_with",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Omega Enriched Face Booster Oil",
|
||||
"target": "castor seed oil",
|
||||
"type": "contains",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Omega Enriched Face Booster Oil",
|
||||
"target": "sea buckthorn",
|
||||
"type": "contains",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "Daily Moisturizing Face Cream",
|
||||
"target": "Omega Enriched Face Booster Oil",
|
||||
"type": "can_be_replaced_with",
|
||||
"attributes": {
|
||||
"confidence": 0.9
|
||||
}
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"num_entities": 20,
|
||||
"num_relationships": 35,
|
||||
"temporal_enabled": false,
|
||||
"timestamp": "2025-12-24T12:46:41.535755",
|
||||
"entity_resolution_applied": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"entities": [{"id": "python_org", "name": "Python Software Foundation", "type": "Organization"}, {"id": "guido_van_rossum", "name": "Guido van Rossum", "type": "Person"}], "relationships": [{"source": "guido_van_rossum", "target": "python_org", "type": "FOUNDED"}]}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"entities": [
|
||||
{
|
||||
"id": "hyaluronic_acid",
|
||||
"name": "Hyaluronic Acid",
|
||||
"type": "Ingredient",
|
||||
"properties": {
|
||||
"role": "Humectant"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "retinol",
|
||||
"name": "Retinol",
|
||||
"type": "Ingredient",
|
||||
"properties": {
|
||||
"role": "Anti-aging actives"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "niacinamide",
|
||||
"name": "Niacinamide",
|
||||
"type": "Ingredient",
|
||||
"properties": {
|
||||
"role": "Barrier repair"
|
||||
}
|
||||
}
|
||||
],
|
||||
"relationships": [
|
||||
{
|
||||
"source": "hyaluronic_acid",
|
||||
"target": "niacinamide",
|
||||
"type": "COMPLEMENTS",
|
||||
"properties": {
|
||||
"benefit": "Hydration + Barrier"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
Apoptotic signatures allow early and rapid screening of drug-induced liver injury to accelerate drug discovery
|
||||
@@ -0,0 +1 @@
|
||||
SynergyGraph: predicting cell line specific drug combination synergy scores using knowledge graph representation and hypergraph modeling
|
||||
@@ -0,0 +1 @@
|
||||
Unraveling the mechanism of curcumin in coronary slow flow phenomenon through network pharmacology and molecular docking
|
||||
@@ -0,0 +1 @@
|
||||
Penicillium chrysogenum originated chloro-diydropyridyl-oxopropanimidic acid derivative as a potent EPSP synthase-targeted bioherbicide against invasive weed species
|
||||
@@ -0,0 +1 @@
|
||||
Enhancing the anti-cancer potential of resveratrol through cocrystal technology in colorectal cancerous rats
|
||||
@@ -0,0 +1 @@
|
||||
Synthesis, spectral, thermal, and biological characterization of Se(IV) nanocomplexes derived from vitamin E and amino acid mixed ligands as a metal-drug model
|
||||
@@ -0,0 +1 @@
|
||||
BT-11 targets the LANCL2 pathway to attenuate cognitive deficits and hippocampal pathology in Alzheimer’s transgenic rats
|
||||
@@ -0,0 +1 @@
|
||||
Saffron as a natural modulator of reverse cholesterol transport genes in atherosclerotic rabbits, with molecular docking insights
|
||||
@@ -0,0 +1 @@
|
||||
Simultaneous targeting of KRAS and CDK4 synergistically induces durable growth arrest in pancreatic cancer cells
|
||||
@@ -0,0 +1 @@
|
||||
Antiproliferative activity of Moringa oleifera (L.) Lam. and Moringa stenopetala (Bak.) Cufod. leaves extract against selected cancer cells in primary cell culture
|
||||
@@ -0,0 +1 @@
|
||||
Applications of Sombor topological indices and entropy measures for QSPR modeling of anticancer drugs: a Python-based methodology
|
||||
@@ -0,0 +1 @@
|
||||
In-silico studies, synthesis, and pharmacological screening of novel multitarget diphenylpyrazole scaffold as EGFR/BRAF and cyclooxygenase-2 inhibitors
|
||||
@@ -0,0 +1 @@
|
||||
Rational design and in silico characterization of a multiepitope mRNA vaccine candidate against human metapneumovirus (hMPV) using reverse vaccinology and immunoinformatics approaches
|
||||
@@ -0,0 +1 @@
|
||||
Unveiling novel potential drug targets for lung cancer through Mendelian randomization analysis
|
||||
@@ -0,0 +1 @@
|
||||
Comparative analysis of OECD guideline data and Tox21 assays to improve reproductive and developmental toxicity prediction
|
||||
@@ -0,0 +1 @@
|
||||
High-throughput triazole-based combinatorial click chemistry for the synthesis and identification of functional metal complexes
|
||||
@@ -0,0 +1 @@
|
||||
Efficacy and safety assessment of gelatin hemostatic matrix in a burr hole neurosurgical beagle model
|
||||
@@ -0,0 +1 @@
|
||||
Biological and computer-aided evaluation of 3-methoxy-13α-estrone-16α-diphenylphosphine oxide as a new antiestrogenic agent
|
||||
@@ -0,0 +1 @@
|
||||
Design and optimization of intranasal aripiprazole-loaded nanostructured lipid carriers for enhanced brain targeting in schizophrenia: in vitro and ex vivo evaluation
|
||||
@@ -0,0 +1 @@
|
||||
Endosome-phagophore linking assemblies for the degradation of membrane/extracellular proteins
|
||||
@@ -0,0 +1 @@
|
||||
Protodioscin enhances Methotrexate-induced senescence and senolytic activity in HepG2 liver cancer spheroids by modulating cell cycle regulators and the TGF-β/p-Smad2-4 signaling pathway
|
||||
@@ -0,0 +1 @@
|
||||
Morpholino-RNA duplex exhibits robust, sustained, and safe steric-block antisense activity by intracerebroventricular and intrathecal injection
|
||||
@@ -0,0 +1 @@
|
||||
Pushing the limits of hydrogen/deuterium exchange mass spectrometry to study protein:fragment low affinity interactions
|
||||
@@ -0,0 +1 @@
|
||||
Cannabidiol perturbs macrophage polarization by interfering with the metabolic flux and PI3K/Akt pathway
|
||||
@@ -0,0 +1 @@
|
||||
Bidirectional reinforcement learning neural network for constrained molecular design
|
||||
@@ -0,0 +1 @@
|
||||
Phytochemical investigation and antibacterial activities of Cordia africana roots extracts
|
||||
@@ -0,0 +1 @@
|
||||
Similar short-term efficacy of oral levosulpiride and intravitreal ranibizumab in patients with diabetic macular oedema
|
||||
@@ -0,0 +1 @@
|
||||
SIMD: Synergistic integration mutualistic platform based on single-cell and proteotranscriptomics for drug repositioning
|
||||
@@ -0,0 +1 @@
|
||||
Elucidating the anti-fibrotic mechanisms of Abrus cantoniensis in hepatic fibrosis using network pharmacology and proteomics
|
||||
@@ -0,0 +1 @@
|
||||
Identification of bioactive phytoconstituents as promising ABL2 inhibitors using virtual screening and molecular dynamics simulation
|
||||
@@ -0,0 +1,9 @@
|
||||
|
||||
Aspirin (acetylsalicylic acid) is a medication used to reduce pain, fever, or inflammation.
|
||||
It targets cyclooxygenase enzymes COX-1 and COX-2. Aspirin is commonly used for cardiovascular protection.
|
||||
Ibuprofen is a nonsteroidal anti-inflammatory drug (NSAID) that targets COX-1 and COX-2 enzymes.
|
||||
Metformin is an antidiabetic medication that targets AMP-activated protein kinase (AMPK).
|
||||
Insulin targets the insulin receptor (INSR) to regulate glucose metabolism.
|
||||
Warfarin is an anticoagulant that targets vitamin K epoxide reductase complex subunit 1 (VKORC1).
|
||||
Atorvastatin is a statin medication that targets HMG-CoA reductase.
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
|
||||
Variant rs699 is located in the AGT gene and associated with hypertension.
|
||||
Variant rs7412 in APOE gene is linked to Alzheimer's disease risk.
|
||||
BRCA1 variant c.5266dupC increases breast cancer susceptibility.
|
||||
CFTR variant F508del causes cystic fibrosis.
|
||||
Variant rs1800566 in NAT2 gene affects drug metabolism.
|
||||
Variant rs1042713 in ADRB2 gene is associated with asthma response.
|
||||
TP53 variant R273H is linked to multiple cancer types.
|
||||
Variant rs1799853 in CYP2C9 gene affects warfarin metabolism.
|
||||
Variant rs1057910 in CYP2C9 affects phenytoin metabolism.
|
||||
Variant rs9923231 in VKORC1 gene influences warfarin dosing.
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
|
||||
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
|
||||
|
||||
<key id="type" for="node" attr.name="type" attr.type="string"/>
|
||||
<key id="confidence" for="node" attr.name="confidence" attr.type="double"/>
|
||||
|
||||
<graph id="G" edgedefault="directed">
|
||||
|
||||
|
||||
</graph>
|
||||
</graphml>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
|
||||
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
|
||||
|
||||
<key id="type" for="node" attr.name="type" attr.type="string"/>
|
||||
<key id="confidence" for="node" attr.name="confidence" attr.type="double"/>
|
||||
|
||||
<graph id="G" edgedefault="directed">
|
||||
|
||||
|
||||
</graph>
|
||||
</graphml>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
||||
|
||||
Transaction 0x123 transfers 1000 ETH from wallet 0xABC to wallet 0xDEF at block 18500000.
|
||||
Transaction 0x456 transfers 500 BTC from wallet 0xGHI to wallet 0xJKL at block 18500001.
|
||||
Large transaction 0x789 moves 10000 ETH (whale movement) from wallet 0xMNO to wallet 0xPQR at block 18500002.
|
||||
Transaction 0xabc transfers 200 USDT from wallet 0xSTU to wallet 0xVWX at block 18500003.
|
||||
Transaction 0xdef transfers 5000 ETH from wallet 0xYZA to wallet 0xBCD at block 18500004.
|
||||
Transaction 0x111 transfers 3000 DAI from wallet 0xEFG to wallet 0xHIJ at block 18500005.
|
||||
Transaction 0x222 transfers 1500 USDC from wallet 0xKLM to wallet 0xNOP at block 18500006.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user