Compare commits

...
44 Commits
Author SHA1 Message Date
KaifAhmad1 a047ebf74f Merge main into pipeline and resolve visualization conflicts 2025-12-13 15:08:47 +05:30
KaifAhmad1 88c12b1867 Add pipeline orchestration fixes and E2E tests 2025-12-13 15:03:34 +05:30
KaifAhmad1 094bb8d82b Recommit pipeline orchestration and e2e tests 2025-12-13 15:01:37 +05:30
Mohd Kaif 7ff2fd9981 Merge pull request #87 from Hawksight-AI/visualization
Enhancement of Visualization Module & Comprehensive Testing Suite
2025-12-12 23:14:00 +05:30
KaifAhmad1 0a555145e4 Enhance visualization module with comprehensive testing and robust dependency handling 2025-12-12 23:10:17 +05:30
Mohd Kaif 994e58a170 Delete PR_DESCRIPTION.md 2025-12-12 20:24:25 +05:30
Mohd Kaif 244144dee3 Merge pull request #86 from Hawksight-AI/vector-store
Refactor: Remove Pinecone and Enhance Vector Store Backend Support
2025-12-12 20:23:51 +05:30
KaifAhmad1 5dfca85500 Merge branch 'main' into vector-store: Resolve PR_DESCRIPTION.md modify/delete conflict by keeping local version 2025-12-12 20:23:15 +05:30
KaifAhmad1 f3dd7a05bd Refactor: Remove Pinecone and enhance vector store backend support
- Removed all Pinecone references, adapters, and documentation to align with open-source, self-hosted focus.
- Removed PineconeAdapter and related dependencies.
- Updated VectorStore to enforce supported backends (FAISS, Weaviate, Qdrant, Milvus, InMemory).
- Updated cookbooks (e.g., 13_Vector_Store.ipynb) to use Weaviate/FAISS examples instead of Pinecone.
- Updated core documentation (modules.md, rchitecture.md, etc.) to reflect backend changes.
- Added new tests (	est_pinecone_removal.py, 	est_vector_store_deepdive.py) to verify removal and validate remaining backends.
- Verified all vector store tests pass.
2025-12-12 20:19:17 +05:30
Mohd Kaif d03a237278 Delete PR_DESCRIPTION.md 2025-12-12 18:50:33 +05:30
Mohd Kaif f3ac9fbffa Merge pull request #85 from Hawksight-AI/triplet-store
Refactor: Rename `triple_store` to `triplet_store`
2025-12-12 18:48:41 +05:30
KaifAhmad1 6856580a7a Refactor: Rename triple_store to triplet_store across codebase
- Renamed semantica/triple_store to semantica/triplet_store
- Updated all imports and class references in core modules and adapters
- Refactored Jupyter notebooks in cookbook/
- Updated documentation files (README, docs/, etc.)
- Updated tests and verified passing status
2025-12-12 18:45:00 +05:30
KaifAhmad1 4a282628ea Merge branch 'main' of https://github.com/Hawksight-AI/semantica 2025-12-12 16:31:43 +05:30
KaifAhmad1 c73e35a2fe docs: update chunking cookbook and PR description 2025-12-12 16:30:59 +05:30
Mohd Kaif a99f18b71b Merge pull request #84 from Hawksight-AI/split
Fix & Align Split Module with Documentation
2025-12-12 16:21:55 +05:30
KaifAhmad1 84b90b45a2 fix: align split methods with documentation and registry 2025-12-12 16:15:57 +05:30
Mohd Kaif d7d589f64e Merge pull request #83 from Hawksight-AI/semantic-extract
Refactor Semantic Extract Module to Class-Based Interfaces
2025-12-12 13:25:58 +05:30
KaifAhmad1 d3366bbcf0 Refactor Semantic Extract module: Update notebooks, docs, and implementation to use class-based interfaces 2025-12-12 13:23:37 +05:30
Mohd Kaif 95c5486d22 Merge pull request #82 from Hawksight-AI/seed
Enhance SeedDataManager with Robust CSV/JSON Support
2025-12-12 12:10:09 +05:30
KaifAhmad1 8b6e8608c3 Enhance SeedDataManager with robust CSV/JSON support and improved validation 2025-12-12 12:04:24 +05:30
Mohd Kaif 315e2edb14 Merge pull request #81 from Hawksight-AI/seed
Seed Module Tests: Comprehensive Coverage for SeedDataManager
2025-12-11 22:08:19 +05:30
KaifAhmad1 a93ed8f13a Add comprehensive tests for SeedDataManager 2025-12-11 22:04:36 +05:30
Mohd Kaif 921bf18041 Merge pull request #80 from Hawksight-AI/reasoning
Reasoning Module Enhancement: Variable Unification & Advanced Inference
2025-12-11 21:57:13 +05:30
KaifAhmad1 971b42631e Enhance reasoning module with variable unification and add comprehensive tests 2025-12-11 21:54:16 +05:30
Mohd Kaif 3e4bc8521f Merge pull request #79 from Hawksight-AI/pipeline
Comprehensive Test Suite for Pipeline Orchestration Module
2025-12-11 21:36:16 +05:30
KaifAhmad1 521e2e27d8 Add comprehensive tests for pipeline orchestration module 2025-12-11 21:28:51 +05:30
KaifAhmad1 c8f745cef0 chore: remove PR descriptions and temporary test output files 2025-12-11 20:18:12 +05:30
KaifAhmad1 c307011311 Merge branch 'main' of https://github.com/Hawksight-AI/semantica 2025-12-11 19:34:26 +05:30
KaifAhmad1 79ff296001 Removing unnecessary Files 2025-12-11 19:34:03 +05:30
Mohd Kaif 2a28e833b9 Merge pull request #78 from Hawksight-AI/parse
Comprehensive Testing and Fixes for Parse Module
2025-12-11 18:57:53 +05:30
KaifAhmad1 30cede84c7 feat(parse): deep dive and comprehensive testing of parse module
- Added 	ests/parse/test_parse_comprehensive.py covering all core parsers (CSV, JSON, XML, PDF, DOCX, Code, Email, HTML).
- Added 	ests/parse/test_notebook_03.py to verify the document parsing cookbook.
- Fixed HTMLParser metadata extraction and return type (returning HTMLData with dict metadata).
- Fixed HTMLParser import of get_progress_tracker.
- Fixed StructuredDataParser progress tracker initialization.
- Updated PR description.
2025-12-11 18:53:34 +05:30
Mohd Kaif 9c8d0c032b Merge pull request #77 from Hawksight-AI/ontology
Comprehensive Testing and Bug Fixes for Ontology Module
2025-12-11 18:16:31 +05:30
KaifAhmad1 e0e42dc539 feat(ontology): comprehensive testing and bug fixes for ontology module
- Added comprehensive test suite (test_ontology_comprehensive.py) covering all core classes.
- Added test_notebook_14.py to verify documentation examples.
- Fixed PropertyGenerator to respect min_occurrences config.
- Fixed NamingConventions for singularization (ss endings) and camelCase preservation.
- Fixed OntologyVisualizer to handle list-type domains/ranges.
- Fixed ModuleManager method usage in tests.
- Validated all 32 tests pass.
2025-12-11 18:11:58 +05:30
Mohd Kaif f59fe1d689 Merge pull request #76 from Hawksight-AI/normalize
Normalize Module Enhancements & Comprehensive Testing
2025-12-11 17:00:46 +05:30
KaifAhmad1 e7e67bd673 Enhance normalize module: fix recursion, add comprehensive tests (57 passed) 2025-12-11 16:58:14 +05:30
Mohd Kaif 1cfbf626d0 Merge pull request #75 from Hawksight-AI/knowledge-engineering
feat: Knowledge Engineering Module Enhancements and Testing
2025-12-11 15:23:54 +05:30
KaifAhmad1 5d5928badf feat: enhance kg module with tests, conflict resolution placeholders, and doc updates 2025-12-11 15:21:39 +05:30
Mohd Kaif 2f94986b01 Merge pull request #74 from Hawksight-AI/ingest
validate and fix ingest module and notebooks
2025-12-11 00:31:15 +05:30
KaifAhmad1 3e7863aa23 feat(ingest): validate and fix ingest module and notebooks
- Fix ProgressTracker usage in MCPIngestor and RepoIngestor
- Fix recursive calls in methods.py
- Add comprehensive test suite for all ingest submodules (tests/ingest/test_submodules.py)
- Add integration tests for key cookbooks (tests/ingest/test_cookbook_integration.py)
- Fix and align existing tests (test_notebook_02.py, test_notebook_06.py)
- Ensure full coverage of all 15 data sources
2025-12-11 00:28:25 +05:30
Mohd Kaif d23ca2d743 Update README.md 2025-12-10 21:56:26 +05:30
Mohd Kaif 507a1f9c71 Merge pull request #73 from Hawksight-AI/graph-store
Remove KuzuDB backend support and cleanup references
2025-12-10 20:33:29 +05:30
Mohd Kaif bad6bd0326 Merge pull request #72 from Hawksight-AI/export
Fix export_yaml schema export bug and update docs
2025-12-10 18:43:35 +05:30
Mohd Kaif 3457f4d7c8 Merge pull request #71 from Hawksight-AI/export
Enhanced Export Module Testing & Notebook Fixes
2025-12-10 18:19:23 +05:30
Mohd Kaif a163a46c56 Merge pull request #70 from Hawksight-AI/embeddings
Dynamic Embedding Model Switching & Enhanced Testing
2025-12-10 17:37:17 +05:30
173 changed files with 11178 additions and 3300 deletions
+1 -1
View File
@@ -58,7 +58,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
-237
View File
@@ -1,237 +0,0 @@
# Add Intelligence Cookbook Notebooks with MCP, Agents, and Orchestrator-Worker Pattern
## Overview
Add comprehensive intelligence-focused notebooks to `cookbook/use_cases/intelligence/` with complete end-to-end pipelines. The **Intelligence Analysis** notebook will use the **Orchestrator-Worker Pattern** with detailed graph analytics, hybrid RAG, and ontology building. Update documentation in `docs/cookbook.md` and `docs/use-cases.md`.
## New Notebooks to Create
### 1. Criminal Network Analysis (`Criminal_Network_Analysis.ipynb`)
Complete pipeline from data sources to GraphRAG with agent-based workflows:
- **Data Sources**: Ingest from police reports, court records, surveillance data, communication logs
- **MCP Integration**: Utilize MCP for accessing public records databases, court records APIs, and real-time data streams
- **Semantica Agents**:
- Data Gathering Agent (autonomous data collection with AgentMemory)
- Network Analysis Agent (graph analytics and community detection)
- Pattern Detection Agent (identifying suspicious patterns)
- Report Generation Agent (compiling intelligence reports)
- **Agent Coordination**: Use Pipeline module for parallel agent workflows
- **Agent Memory**: AgentMemory for persistent context across interactions
- **Complete Pipeline**: Data sources → MCP → Parsing → Extraction → KG → Graph Analytics → GraphRAG → Agent Analysis → Visualization → Reporting
### 2. Law Enforcement and Forensics (`Law_Enforcement_Forensics.ipynb`)
Complete forensic analysis pipeline with agent-based workflows:
- **Data Sources**: Case files, evidence logs, witness statements, forensic reports, crime scene data
- **Semantica Agents**:
- Evidence Collection Agent (autonomous evidence gathering)
- Timeline Analysis Agent (temporal case timelines)
- Cross-Case Correlation Agent (connections across cases)
- Forensic Report Agent (comprehensive report generation)
- **Agent Coordination**: Multi-agent pipeline for parallel evidence processing
- **Agent Memory**: Persistent memory for case context and evidence chains
- **Complete Pipeline**: Case files → Parsing → Evidence Extraction → Temporal KG → Graph Analytics → GraphRAG → Agent Analysis → Visualization → Reporting
### 3. Intelligence Analysis (`Intelligence_Analysis.ipynb`) - **ORCHESTRATOR-WORKER PATTERN**
Comprehensive intelligence analysis using **Orchestrator-Worker Pattern** with detailed implementation:
#### Orchestrator-Worker Architecture:
- **Orchestrator**: ExecutionEngine coordinates all workers using PipelineBuilder and ParallelismManager
- **Worker 1 - Data Ingestion Worker**: Handles multi-source data ingestion (FileIngestor, WebIngestor, StreamIngestor, FeedIngestor, DBIngestor)
- **Worker 2 - Ontology Building Worker**: Complete 6-stage ontology generation pipeline
- Stage 1: Semantic Network Parsing (extract domain concepts)
- Stage 2: YAML-to-Definition (transform concepts to class definitions)
- Stage 3: Definition-to-Types (map to OWL types)
- Stage 4: Hierarchy Generation (build taxonomic structures)
- Stage 5: TTL Generation (generate OWL/Turtle syntax)
- Stage 6: Symbolic Validation (HermiT/Pellet reasoning)
- **Worker 3 - Graph Construction Worker**: Builds knowledge graphs (GraphBuilder, TemporalGraphQuery)
- **Worker 4 - Graph Analytics Worker**: Comprehensive graph analytics including:
- Centrality Measures: PageRank, Betweenness, Closeness, Eigenvector
- Community Detection: Louvain algorithm
- Connectivity Analysis: Path finding, shortest paths, connectivity metrics
- Graph Metrics: Density, clustering coefficient, diameter, radius
- **Worker 5 - Hybrid RAG Worker**: Complete hybrid RAG implementation:
- Vector Store setup with embeddings
- Knowledge Graph queries
- Hybrid Search (combining vector similarity + graph traversal)
- Context Retrieval (ContextRetriever)
- Query Orchestration across KG and vector store
- **Worker 6 - Intelligence Analysis Worker**: Threat assessment, geospatial analysis, pattern detection
- **Worker 7 - Report Generation Worker**: Compiles comprehensive intelligence reports
#### Complete Features:
- **Data Sources**: OSINT feeds, threat intelligence, social media, news, public records, geospatial data
- **MCP Integration**: Real-time data fetching, web scraping, API integration, browser automation for OSINT
- **Agent Memory**: Persistent memory for threat context and intelligence history
- **Complete Pipeline**: OSINT sources → MCP → Orchestrator → Parallel Workers → Ontology → KG → Graph Analytics → Hybrid RAG → Intelligence Analysis → Visualization → Reporting
## Files to Create/Modify
### New Notebooks (in `cookbook/use_cases/intelligence/`)
- `Criminal_Network_Analysis.ipynb`
- `Law_Enforcement_Forensics.ipynb`
- `Intelligence_Analysis.ipynb` (with Orchestrator-Worker Pattern)
### Documentation Updates
- `docs/cookbook.md` - Add new notebooks to Intelligence section
- `docs/use-cases.md` - Add use case cards for Criminal Network Analysis and Law Enforcement & Forensics
## Implementation Details
### Intelligence Analysis - Orchestrator-Worker Pipeline Structure:
1. **Orchestrator Setup** - Initialize ExecutionEngine, PipelineBuilder, ParallelismManager
2. **Data Sources** - Multiple ingestion (FileIngestor, DBIngestor, WebIngestor, StreamIngestor, FeedIngestor)
3. **MCP Integration** - External data access, web scraping, browser automation
4. **Worker 1 - Data Ingestion Worker** - Parallel data gathering from multiple sources
5. **Data Parsing** - Parse structured/unstructured data (JSONParser, XMLParser, CSVParser, DocumentParser, StructuredDataParser)
6. **Data Normalization** - Clean and standardize (TextNormalizer, DataNormalizer)
7. **Entity & Relation Extraction** - Extract entities, relationships, events (NERExtractor, RelationExtractor, TripleExtractor, EventDetector)
8. **Worker 2 - Ontology Building Worker** - Complete 6-stage ontology generation:
- Use OntologyGenerator, ClassInferrer, PropertyGenerator
- Generate OWL/Turtle with OWLGenerator
- Validate with OntologyValidator (HermiT/Pellet)
9. **Worker 3 - Graph Construction Worker** - Build knowledge graphs:
- GraphBuilder for entity/relationship graphs
- TemporalGraphQuery for time-aware graphs
10. **Worker 4 - Graph Analytics Worker** - All graph analytics:
- GraphAnalyzer: PageRank, Betweenness, Closeness, Eigenvector centrality
- CommunityDetector: Louvain community detection
- ConnectivityAnalyzer: Path finding, shortest paths, connectivity
- CentralityCalculator: All centrality measures
- Graph metrics: density, clustering, diameter, radius
11. **Worker 5 - Hybrid RAG Worker** - Complete hybrid RAG:
- EmbeddingGenerator: Generate embeddings for entities and text
- VectorStore: Store and index embeddings
- HybridSearch: Combine vector similarity + graph queries
- ContextRetriever: Retrieve relevant context from KG and vectors
- Query orchestration: Coordinate queries across KG and vector store
12. **Worker 6 - Intelligence Analysis Worker** - Threat assessment, geospatial analysis, pattern detection
13. **Agent Memory Integration** - Store and retrieve agent context using AgentMemory
14. **Orchestrator Coordination** - Coordinate all workers with parallel execution
15. **Visualization** - Network graphs, analytics dashboards, maps (KGVisualizer, AnalyticsVisualizer, TemporalVisualizer)
16. **Worker 7 - Report Generation Worker** - Compile comprehensive intelligence reports
17. **Report Generation** - Professional HTML reports (ReportGenerator, HTMLExporter)
### Other Notebooks - Standard Pipeline Structure:
1. **Data Sources** - Multiple ingestion
2. **MCP Integration** - (Criminal Network Analysis only)
3. **Semantica Agent Setup** - Initialize AgentMemory, create specialized agents
4. **Agent-Based Data Gathering** - Autonomous agents gather data
5. **Data Parsing** - Parse structured/unstructured data
6. **Data Normalization** - Clean and standardize
7. **Entity & Relation Extraction** - Extract entities, relationships, events
8. **Knowledge Graph Construction** - Build graphs
9. **Agent-Based Analysis** - Specialized agents perform parallel analysis
10. **Graph Analytics** - Community detection, centrality, connectivity
11. **GraphRAG Implementation** - Embeddings, vector store, hybrid search
12. **Agent Memory Integration** - Store and retrieve agent context
13. **Detailed Analysis** - Reasoning, inference, pattern detection
14. **Agent Coordination** - Pipeline module for multi-agent workflow orchestration
15. **Visualization** - Network graphs, analytics dashboards, maps
16. **Agent-Based Report Generation** - Agents compile comprehensive reports
17. **Report Generation** - Professional HTML reports
### Semantica Agent Implementation:
- **AgentMemory**: Persistent context storage, memory retrieval, conversation history
- **Pipeline Coordination**: PipelineBuilder, ExecutionEngine, ParallelismManager for multi-agent workflows
- **Specialized Agents**: Each agent has specific role (data gathering, analysis, reporting)
- **Agent Examples**: Code demonstrations of agent workflows with memory integration
### MCP Integration:
- **Intelligence Analysis**: MCP browser tools for OSINT, resources for external feeds
- **Criminal Network Analysis**: MCP for public records, court databases, API integration
- **Agent-MCP Coordination**: Agents use MCP for autonomous data gathering
### Notebook Structure:
#### Intelligence Analysis (Orchestrator-Worker Pattern):
- Overview with Orchestrator-Worker pattern explanation
- Semantica modules used (30+ modules including Orchestrator, Workers, Ontology, Graph Analytics, Hybrid RAG)
- **Orchestrator Architecture**: Detailed explanation of orchestrator and worker roles
- **Worker Implementation**: Detailed code for each worker (7 workers)
- **Ontology Building**: Complete 6-stage ontology generation pipeline demonstration
- **Graph Analytics**: All analytics methods (PageRank, Betweenness, Closeness, Eigenvector, Louvain, connectivity, paths)
- **Hybrid RAG**: Complete implementation with KG queries + vector search, query orchestration
- MCP integration demonstration
- Step-by-step implementation with orchestrator coordinating workers
- Parallel worker execution examples
- Agent memory integration
- Best practices for orchestrator-worker pattern
- Best practices for agents and MCP
- Conclusion with key takeaways
#### Other Notebooks:
- Overview with complete pipeline description
- Semantica modules used (20+ modules including AgentMemory, Pipeline)
- Agent Architecture explanation
- MCP integration demonstration (Criminal Network Analysis)
- Step-by-step implementation with agent workflows
- Agent memory integration examples
- Multi-agent pipeline orchestration
- Best practices for agents and MCP
- Conclusion with key takeaways
## Key Implementation Details for Orchestrator-Worker Pattern:
### Orchestrator Code Example:
```python
from semantica.pipeline import PipelineBuilder, ExecutionEngine, ParallelismManager
from semantica.ontology import OntologyGenerator
from semantica.kg import GraphBuilder, GraphAnalyzer
from semantica.vector_store import VectorStore, HybridSearch
from semantica.context import AgentMemory
# Initialize orchestrator
orchestrator = ExecutionEngine()
parallelism_manager = ParallelismManager(max_workers=7)
# Define workers
def data_ingestion_worker(sources):
# Worker 1: Multi-source data ingestion
pass
def ontology_building_worker(entities, relationships):
# Worker 2: Complete 6-stage ontology generation
ontology_gen = OntologyGenerator()
ontology = ontology_gen.generate_ontology({"entities": entities, "relationships": relationships})
return ontology
def graph_construction_worker(entities, relationships):
# Worker 3: Build knowledge graph
graph_builder = GraphBuilder()
kg = graph_builder.build(entities, relationships)
return kg
def graph_analytics_worker(kg):
# Worker 4: All graph analytics
analyzer = GraphAnalyzer()
pagerank = analyzer.compute_centrality(kg, method="pagerank")
betweenness = analyzer.compute_centrality(kg, method="betweenness")
communities = analyzer.detect_communities(kg, method="louvain")
# ... all analytics
return {"pagerank": pagerank, "betweenness": betweenness, "communities": communities}
def hybrid_rag_worker(kg, vector_store):
# Worker 5: Hybrid RAG with KG and vector store
hybrid_search = HybridSearch(vector_store=vector_store, knowledge_graph=kg)
# Query orchestration
pass
# Build pipeline with workers
pipeline = PipelineBuilder() \
.add_step("data_ingestion", "custom", func=data_ingestion_worker) \
.add_step("ontology_building", "custom", func=ontology_building_worker) \
.add_step("graph_construction", "custom", func=graph_construction_worker) \
.add_step("graph_analytics", "custom", func=graph_analytics_worker) \
.add_step("hybrid_rag", "custom", func=hybrid_rag_worker) \
.build()
# Execute with parallel workers
result = orchestrator.execute_pipeline(pipeline, parallel=True, max_workers=7)
```
Each notebook demonstrates the full journey from raw data sources through autonomous agent workflows (or orchestrator-worker pattern) and GraphRAG to actionable intelligence.
-33
View File
@@ -1,33 +0,0 @@
# PR: Context Module Testing & Validation
## Description
This PR adds comprehensive testing and validation for the **Context Engineering Module** (`semantica.context`). It includes unit tests for core components, verification of notebook examples, and a critical bug fix in the deduplication module.
## Changes
### 1. New Unit Tests (`tests/context/`)
Added `tests/context/test_context.py` covering:
- **AgentContext**: End-to-end storage and retrieval (RAG & GraphRAG).
- **AgentMemory**: Hierarchical memory management (short-term buffer vs. long-term vector store) and retention policies.
- **ContextGraph**: Node/edge addition and neighbor traversal.
- **EntityLinker**: URI assignment and entity linking logic.
- **ContextRetriever**: Hybrid retrieval strategies (Vector + Graph).
### 2. Notebook Verification
Verified functionality of the following notebooks by converting them to test scripts:
- `19_Context_Module.ipynb`: Verified high-level interface, token limits, and graph construction.
- `11_Advanced_Context_Engineering.ipynb`: Verified custom memory pruning, hybrid tuning, and custom graph builders.
### 3. Bug Fixes
- **`semantica/deduplication/merge_strategy.py`**: Fixed a `NameError` caused by a missing `Tuple` import. This was discovered during global import validation.
### 4. Verification
- All new tests passed.
- Global import check confirmed no other hidden dependency issues.
- Integration test `verify_context_sync.py` passed, confirming correct synchronization between memory, graph, and vector store.
## Testing Instructions
Run the new tests with:
```bash
python -m unittest tests/context/test_context.py
```
-34
View File
@@ -1,34 +0,0 @@
# Enhanced Export Module Testing, Bug Fixes & Notebook Updates
## Summary
This PR significantly hardens the `semantica.export` module by adding comprehensive unit tests, fixing critical bugs in export wrappers and logic, and updating documentation and cookbooks to match current API signatures.
## Key Changes
### 1. Bug Fixes & Logic Improvements
- **`semantica/export/methods.py`**:
- Fixed `export_yaml(method="schema")` to correctly call `export_ontology_schema` and handle file writing (previously failed as the underlying method returns a string).
- Added safeguards to all convenience functions (`export_rdf`, `export_json`, etc.) to prevent infinite recursion if the registry returns the wrapper function itself.
- **`semantica/kg/graph_builder.py`**: Fixed a critical bug where `ConflictDetector` was receiving the entire graph dictionary instead of the entity list.
- **`semantica/export/rdf_exporter.py`**: Fixed `export_to_rdf` to correctly return serialized data for all formats.
### 2. Comprehensive Testing (`tests/`)
- **`tests/test_export_module.py`**: A full suite of unit tests covering all 11 export classes (`JSON`, `CSV`, `RDF`, `GraphML`, `YAML`, `OWL`, `Vector`, `LPG`, etc.).
- **`tests/test_export_methods_wrapper.py`**: Added specific tests for convenience wrapper functions in `methods.py`, verifying the fix for schema export.
- **`tests/test_notebook_15_export.py`** & **`tests/test_notebooks_simulation.py`**: Simulation tests that replicate cookbook logic to ensure end-to-end functionality.
### 3. Documentation & Notebook Updates
- **`docs/reference/export.md`** & **`semantica/export/export_usage.md`**: Updated to correctly document `YAMLSchemaExporter.export_ontology_schema` instead of the deprecated `export` method.
- **Cookbooks** (`15_Export.ipynb`, `05_Multi_Format_Export.ipynb`):
- Updated `GraphBuilder.build()` calls to pass combined lists (fixing API mismatch).
- Corrected `YAMLSchemaExporter` usage.
- Fixed `VectorExporter` data preparation.
- Adjusted `CSVExporter` paths.
## Verification
All tests passed successfully:
```bash
$ pytest tests/test_export_module.py tests/test_notebooks_simulation.py tests/test_notebook_15_export.py tests/test_export_methods_wrapper.py
...
13 passed in 3.82s
```
+1 -3
View File
@@ -319,7 +319,7 @@ result = kg.query("Who founded the company?", return_format="structured")
print(f"Nodes: {kg.node_count}, Answer: {result.answer}")
```
[**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 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) • [**Visualization**](https://github.com/Hawksight-AI/semantica/tree/main/cookbook/introduction/16_Visualization.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)
@@ -503,8 +503,6 @@ print(f"Answer: {result.answer} | Nodes: {kg.node_count}, Edges: {kg.edge_count}
|:-----------:|:-----------|
| [**Discord**](https://discord.gg/semantica) | Real-time help, showcases |
| [**GitHub Discussions**](https://github.com/Hawksight-AI/semantica/discussions) | Q&A, feature requests |
| [**Twitter**](https://twitter.com/semantica_ai) | Updates, tips |
| [**YouTube**](https://youtube.com/@semantica) | Tutorials, webinars |
### Learning Resources
-206
View File
@@ -1,206 +0,0 @@
# Add Intelligence Cookbook Notebooks with MCP and Semantica Agents
## Overview
Add comprehensive intelligence-focused notebooks to `cookbook/use_cases/intelligence/` with complete end-to-end pipelines covering data ingestion (including MCP integration), knowledge graph construction, GraphRAG implementation, **Semantica agent-based workflows**, and detailed analysis. Update documentation in `docs/cookbook.md` and `docs/use-cases.md`.
## New Notebooks to Create
### 1. Criminal Network Analysis (`Criminal_Network_Analysis.ipynb`)
Complete pipeline from data sources to GraphRAG with **agent-based workflows**:
- **Data Sources**: Ingest from police reports, court records, surveillance data, communication logs
- **MCP Integration**: Utilize MCP for accessing public records databases, court records APIs, and real-time data streams
- **Semantica Agents**:
- **Data Gathering Agent**: Autonomous agent using AgentMemory to gather and track data from multiple sources
- **Network Analysis Agent**: Specialized agent for graph analytics and community detection
- **Pattern Detection Agent**: Agent for identifying suspicious patterns and relationships
- **Report Generation Agent**: Agent for compiling intelligence reports
- **Agent Coordination**: Use Pipeline module (PipelineBuilder, ExecutionEngine, ParallelismManager) to coordinate parallel agent workflows
- **Agent Memory**: Use AgentMemory for persistent context across agent interactions
- **Parsing**: Parse structured/unstructured documents, JSON, CSV, PDFs
- **Extraction**: Extract suspects, organizations, locations, events, relationships
- **Knowledge Graph**: Build criminal network graph with temporal relationships
- **Graph Analytics**: Community detection, centrality measures, key player identification
- **GraphRAG**: Vector store, hybrid search, context retrieval for intelligence queries
- **Detailed Analysis**: Pattern detection, network structure analysis, threat assessment
- **Visualization**: Network graphs, community visualization, centrality rankings
- **Reporting**: Generate intelligence reports on criminal structures
### 2. Law Enforcement and Forensics (`Law_Enforcement_Forensics.ipynb`)
Complete forensic analysis pipeline with **agent-based workflows**:
- **Data Sources**: Case files, evidence logs, witness statements, forensic reports, crime scene data
- **Semantica Agents**:
- **Evidence Collection Agent**: Autonomous agent for gathering and organizing evidence
- **Timeline Analysis Agent**: Agent for building temporal case timelines
- **Cross-Case Correlation Agent**: Agent for finding connections across multiple cases
- **Forensic Report Agent**: Agent for generating comprehensive forensic reports
- **Agent Coordination**: Multi-agent pipeline for parallel evidence processing
- **Agent Memory**: Persistent memory for case context and evidence chains
- **Parsing**: Parse PDFs, structured reports, evidence databases, temporal logs
- **Extraction**: Extract entities (persons, locations, evidence, events), relationships, timelines
- **Knowledge Graph**: Build temporal knowledge graph for case timelines and evidence correlation
- **Graph Analytics**: Timeline analysis, evidence correlation, pattern detection across cases
- **GraphRAG**: Semantic search across case files, evidence retrieval, context-aware queries
- **Detailed Analysis**: Cross-case correlation, evidence chain analysis, suspect identification
- **Visualization**: Timeline visualization, evidence networks, case correlation graphs
- **Reporting**: Generate forensic analysis reports with evidence chains
### 3. Intelligence Analysis (`Intelligence_Analysis.ipynb`)
Comprehensive intelligence analysis with **agent-based workflows**:
- **Data Sources**: OSINT feeds, threat intelligence, social media, news, public records, geospatial data
- **MCP Integration**: Utilize MCP for real-time data fetching, web scraping, API integration, external database access, and browser automation for OSINT gathering
- **Semantica Agents**:
- **OSINT Gathering Agent**: Autonomous agent using MCP browser tools for web scraping and OSINT collection
- **Threat Assessment Agent**: Specialized agent for threat analysis and risk scoring
- **Geospatial Intelligence Agent**: Agent for location-based tracking and geographic analysis
- **Multi-Source Fusion Agent**: Agent for correlating intelligence from multiple sources
- **Intelligence Report Agent**: Agent for generating comprehensive threat intelligence reports
- **Agent Coordination**: Complex multi-agent pipeline with parallel execution for intelligence gathering
- **Agent Memory**: Persistent memory for threat context, entity tracking, and intelligence history
- **Parsing**: Multi-format parsing (RSS feeds, JSON, XML, web scraping, geospatial formats)
- **Extraction**: Extract threat actors, locations, events, relationships, temporal patterns
- **Knowledge Graph**: Build multi-source intelligence graph with geospatial and temporal dimensions
- **Graph Analytics**: Threat assessment, risk scoring, entity relationship mapping, pattern detection
- **GraphRAG**: Multi-source intelligence fusion, hybrid search, contextual threat queries
- **Detailed Analysis**:
- Multi-source intelligence fusion and correlation
- Threat assessment and risk analysis
- Geospatial intelligence with location tracking
- Temporal threat evolution analysis
- **Visualization**: Geographic network maps, threat timelines, relationship networks
- **Reporting**: Generate comprehensive threat intelligence reports
## Files to Create/Modify
### New Notebooks (in `cookbook/use_cases/intelligence/`)
- `Criminal_Network_Analysis.ipynb`
- `Law_Enforcement_Forensics.ipynb`
- `Intelligence_Analysis.ipynb`
### Documentation Updates
- `docs/cookbook.md` - Add new notebooks to Intelligence section
- `docs/use-cases.md` - Add new use case cards for criminal networks and law enforcement
## Implementation Details
### Complete Pipeline Structure (All Notebooks):
1. **Data Sources** - Multiple ingestion sources (FileIngestor, DBIngestor, WebIngestor, StreamIngestor, FeedIngestor)
2. **MCP Integration** - Utilize MCP servers for external data access, real-time feeds, API integration, web scraping, and browser automation (in Intelligence Analysis and Criminal Network Analysis notebooks)
3. **Semantica Agent Setup** - Initialize AgentMemory, create specialized agents, set up agent coordination
4. **Agent-Based Data Gathering** - Autonomous agents gather data using MCP and Semantica ingestors
5. **Data Parsing** - Parse structured/unstructured data (JSONParser, XMLParser, CSVParser, DocumentParser, StructuredDataParser)
6. **Data Normalization** - Clean and standardize (TextNormalizer, DataNormalizer)
7. **Entity & Relation Extraction** - Extract entities, relationships, events (NERExtractor, RelationExtractor, TripleExtractor, EventDetector)
8. **Knowledge Graph Construction** - Build graphs (GraphBuilder, TemporalGraphQuery)
9. **Agent-Based Analysis** - Specialized agents perform parallel analysis tasks
10. **Graph Analytics** - Community detection, centrality, connectivity (GraphAnalyzer, ConnectivityAnalyzer, CentralityCalculator)
11. **GraphRAG Implementation** - Embeddings, vector store, hybrid search, context retrieval (EmbeddingGenerator, VectorStore, HybridSearch, ContextRetriever)
12. **Agent Memory Integration** - Store and retrieve agent context using AgentMemory
13. **Detailed Analysis** - Reasoning, inference, pattern detection (InferenceEngine, RuleManager, ExplanationGenerator)
14. **Agent Coordination** - Use Pipeline module for multi-agent workflow orchestration
15. **Visualization** - Network graphs, analytics dashboards, geographic maps (KGVisualizer, AnalyticsVisualizer, TemporalVisualizer)
16. **Agent-Based Report Generation** - Agents compile and generate professional reports
17. **Report Generation** - Professional HTML reports (ReportGenerator, HTMLExporter)
### Semantica Agent Implementation Details:
#### AgentMemory Usage:
- **Persistent Context**: Store agent interactions, decisions, and findings
- **Memory Retrieval**: Retrieve relevant context for agent decision-making
- **Conversation History**: Track agent conversations and analysis sessions
- **Context Accumulation**: Build up intelligence context over time
#### Pipeline Agent Coordination:
- **PipelineBuilder**: Define multi-agent workflows
- **ExecutionEngine**: Execute agent pipelines with error handling
- **ParallelismManager**: Run agents in parallel for efficiency
- **Specialized Agents**: Each agent has a specific role (data gathering, analysis, reporting)
#### Agent Workflow Examples:
```python
# Example: Multi-agent intelligence gathering
from semantica.context import AgentMemory
from semantica.pipeline import PipelineBuilder, ExecutionEngine, ParallelismManager
# Initialize agent memory
agent_memory = AgentMemory(vector_store=vs, knowledge_graph=kg)
# Define specialized agents
def osint_gathering_agent(query, memory):
"""Autonomous OSINT gathering agent"""
# Use MCP for web scraping
# Store findings in agent memory
findings = gather_osint(query)
memory.store(f"OSINT findings: {findings}", metadata={"agent": "osint", "query": query})
return findings
def threat_assessment_agent(intel_data, memory):
"""Threat assessment agent"""
# Retrieve relevant context from memory
context = memory.retrieve("threat patterns", max_results=10)
# Perform threat analysis
assessment = analyze_threats(intel_data, context)
memory.store(f"Threat assessment: {assessment}", metadata={"agent": "threat"})
return assessment
# Build multi-agent pipeline
pipeline = PipelineBuilder() \
.add_step("osint_gathering", "custom", func=osint_gathering_agent, args=(query, agent_memory)) \
.add_step("threat_assessment", "custom", func=threat_assessment_agent, args=(intel_data, agent_memory)) \
.build()
# Execute with parallel agents
engine = ExecutionEngine()
result = engine.execute_pipeline(pipeline, parallel=True)
```
### MCP Integration Details:
- **Intelligence Analysis Notebook**:
- Use MCP browser tools for web scraping and OSINT gathering
- Use MCP resources for accessing external intelligence feeds
- Demonstrate real-time data fetching via MCP
- Agents use MCP for autonomous data gathering
- **Criminal Network Analysis Notebook**:
- Use MCP for accessing public records and court databases
- Demonstrate API integration via MCP
- Show real-time data stream processing
- Agents coordinate MCP-based data gathering
### Notebook Structure:
- Overview with complete pipeline description
- Semantica modules used (20+ modules including AgentMemory, Pipeline)
- **Agent Architecture**: Explanation of agent roles and coordination
- MCP integration demonstration (for Intelligence Analysis and Criminal Network Analysis)
- Step-by-step implementation:
- **Agent Setup**: Initialize AgentMemory and create specialized agents
- Data ingestion from multiple sources (including MCP resources)
- **Agent-Based Data Gathering**: Autonomous agents gather data
- MCP-based external data fetching and API integration
- Parsing and normalization
- Entity and relation extraction
- Knowledge graph construction
- **Agent-Based Analysis**: Parallel agent workflows for analysis
- Graph analytics and pattern detection
- **Agent Memory Integration**: Store and retrieve agent context
- GraphRAG setup and query examples
- **Agent Coordination**: Multi-agent pipeline orchestration
- Detailed analysis with insights
- Visualization examples
- **Agent-Based Report Generation**: Agents compile reports
- Report generation
- Best practices and deployment recommendations
- **Agent Best Practices**: Agent memory management, coordination patterns
- MCP integration best practices
- Conclusion with key takeaways
Each notebook will be comprehensive, demonstrating the full journey from raw data sources (including MCP-enabled external sources) through **autonomous agent workflows** and GraphRAG to actionable intelligence and detailed analysis.
## Key Agent Features to Highlight:
1. **Autonomous Data Gathering**: Agents independently gather data from multiple sources
2. **Persistent Memory**: AgentMemory maintains context across sessions
3. **Parallel Coordination**: Multiple agents work simultaneously on different tasks
4. **Specialized Roles**: Each agent has a specific expertise area
5. **Context-Aware Analysis**: Agents use memory to make informed decisions
6. **Coordinated Workflows**: Pipeline module orchestrates complex multi-agent systems
7. **Intelligent Reporting**: Agents compile findings into comprehensive reports
BIN
View File
Binary file not shown.
@@ -312,7 +312,7 @@
"- NumPy format\n",
"- Binary format\n",
"- FAISS format\n",
"- Vector store integration (Pinecone, Weaviate, Qdrant)\n"
"- Vector store integration (Weaviate, Qdrant)\n"
]
},
{
@@ -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,7 @@
"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 → Triplet Store\n"
]
},
{
@@ -37,7 +37,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"
]
},
{
@@ -162,7 +162,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 5: Store in Triple Store\n"
"## Step 5: Store in Triplet Store\n"
]
},
{
@@ -171,8 +171,8 @@
"metadata": {},
"outputs": [],
"source": [
"triple_store = TripleStore()\n",
"triple_store.store(knowledge_graph, ontology)\n"
"triplet_store = TripletStore()\n",
"triplet_store.store(knowledge_graph, ontology)\n"
]
},
{
@@ -186,7 +186,7 @@
"- Ontology Generated\n",
"- Semantic Layer Created with Mappings\n",
"- RDF Export Completed\n",
"- Triple Store Storage Completed\n"
"- Triplet Store Storage Completed\n"
]
}
],
@@ -217,7 +217,7 @@
"## 5. Best Practices for Production\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",
"2. **Vector Store**: Use a production-grade vector store (e.g., 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.\")."
]
@@ -204,7 +204,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 +219,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",
@@ -638,4 +638,4 @@
},
"nbformat": 4,
"nbformat_minor": 2
}
}
@@ -180,7 +180,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 +196,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",
@@ -690,4 +690,4 @@
},
"nbformat": 4,
"nbformat_minor": 2
}
}
@@ -282,7 +282,7 @@
"entity_chunker = EntityAwareChunker(\n",
" chunk_size=200,\n",
" chunk_overlap=50,\n",
" ner_method=\"spacy\", # or \"llm\" for better accuracy\n",
" ner_method=\"ml\", # \"ml\" (spaCy), \"pattern\", or \"llm\"\n",
" preserve_entities=True\n",
")\n",
"\n",
@@ -850,4 +850,4 @@
},
"nbformat": 4,
"nbformat_minor": 2
}
}
File diff suppressed because it is too large Load Diff
@@ -6,31 +6,31 @@
"source": [
"[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Hawksight-AI/semantica/blob/main/cookbook/introduction/20_Triple_Store.ipynb)\n",
"\n",
"# Triple Store - Comprehensive Guide\n",
"# Triplet 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",
"This notebook provides a **comprehensive walkthrough** of Semantica's triplet_store module, demonstrating RDF triplet storage, SPARQL querying, and multi-backend support for knowledge graph persistence.\n",
"\n",
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/triple_store/)\n",
"**Documentation**: [API Reference](https://semantica.readthedocs.io/reference/triplet_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",
"- Register and manage triplet stores (Blazegraph, Jena, RDF4J, Virtuoso)\n",
"- Perform CRUD operations on RDF triplets\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",
"- Validate and track triplet 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",
"| `TripletManager` | Store coordination | All triplet operations |\n",
"| `QueryEngine` | SPARQL execution | Query optimization |\n",
"| `BulkLoader` | High-volume loading | Large datasets |\n",
"| `BlazegraphAdapter` | Blazegraph backend | High performance |\n",
@@ -57,13 +57,13 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 1: Basic Triple Store Operations\n",
"## Step 1: Basic Triplet Store Operations\n",
"\n",
"Let's start with the `TripleManager` for basic triple store operations.\n",
"Let's start with the `TripletManager` for basic triplet store operations.\n",
"\n",
"### What is TripleManager?\n",
"### What is TripletManager?\n",
"\n",
"`TripleManager` is the main coordinator for triple store operations:\n",
"`TripletManager` is the main coordinator for triplet store operations:\n",
"- **Store Registration**: Register multiple backends\n",
"- **CRUD Operations**: Add, get, update, delete triples\n",
"- **Multi-Store**: Manage multiple stores simultaneously"
@@ -75,11 +75,11 @@
"metadata": {},
"outputs": [],
"source": [
"from semantica.triple_store import TripleManager\n",
"from semantica.triplet_store import TripletManager\n",
"from semantica.semantic_extract.triple_extractor import Triple\n",
"\n",
"# Create triple manager\n",
"manager = TripleManager()\n",
"manager = TripletManager()\n",
"\n",
"# Register a Blazegraph store (in-memory for demo)\n",
"store = manager.register_store(\n",
@@ -130,7 +130,7 @@
"metadata": {},
"outputs": [],
"source": [
"from semantica.triple_store import register_store\n",
"from semantica.triplet_store import register_store\n",
"\n",
"# Register multiple stores using convenience function\n",
"blazegraph_store = register_store(\n",
@@ -179,7 +179,7 @@
"metadata": {},
"outputs": [],
"source": [
"from semantica.triple_store import add_triple, add_triples, get_triples, update_triple, delete_triple\n",
"from semantica.triplet_store import add_triple, add_triples, get_triples, update_triple, delete_triple\n",
"\n",
"# Create - Add single triple\n",
"triple1 = Triple(\n",
@@ -240,7 +240,7 @@
"metadata": {},
"outputs": [],
"source": [
"from semantica.triple_store import QueryEngine, BlazegraphAdapter\n",
"from semantica.triplet_store import QueryEngine, BlazegraphAdapter\n",
"\n",
"# Create query engine with caching\n",
"engine = QueryEngine(enable_caching=True, enable_optimization=True)\n",
@@ -299,7 +299,7 @@
"metadata": {},
"outputs": [],
"source": [
"from semantica.triple_store import optimize_query, plan_query\n",
"from semantica.triplet_store import optimize_query, plan_query\n",
"\n",
"# Original query\n",
"query = \"\"\"\n",
@@ -347,7 +347,7 @@
"metadata": {},
"outputs": [],
"source": [
"from semantica.triple_store import BulkLoader, LoadProgress\n",
"from semantica.triplet_store import BulkLoader, LoadProgress\n",
"\n",
"# Create bulk loader\n",
"loader = BulkLoader(\n",
@@ -392,11 +392,11 @@
"source": [
"## Step 7: Store Adapters\n",
"\n",
"Work with different triple store backends.\n",
"Work with different triplet store backends.\n",
"\n",
"### Blazegraph Adapter\n",
"\n",
"High-performance triple store with GPU acceleration."
"High-performance triplet store with GPU acceleration."
]
},
{
@@ -405,7 +405,7 @@
"metadata": {},
"outputs": [],
"source": [
"from semantica.triple_store import BlazegraphAdapter\n",
"from semantica.triplet_store import BlazegraphAdapter\n",
"\n",
"# Create Blazegraph adapter\n",
"blazegraph = BlazegraphAdapter(\n",
@@ -442,7 +442,7 @@
"metadata": {},
"outputs": [],
"source": [
"from semantica.triple_store import JenaAdapter\n",
"from semantica.triplet_store import JenaAdapter\n",
"\n",
"# Create Jena adapter (in-memory)\n",
"jena = JenaAdapter()\n",
@@ -497,7 +497,7 @@
"metadata": {},
"outputs": [],
"source": [
"from semantica.triple_store import RDF4JAdapter\n",
"from semantica.triplet_store import RDF4JAdapter\n",
"\n",
"# Create RDF4J adapter\n",
"rdf4j = RDF4JAdapter(\n",
@@ -540,7 +540,7 @@
"metadata": {},
"outputs": [],
"source": [
"from semantica.triple_store import VirtuosoAdapter\n",
"from semantica.triplet_store import VirtuosoAdapter\n",
"\n",
"# Create Virtuoso adapter\n",
"virtuoso = VirtuosoAdapter(\n",
@@ -604,7 +604,7 @@
"metadata": {},
"outputs": [],
"source": [
"from semantica.triple_store import validate_triples\n",
"from semantica.triplet_store import validate_triples\n",
"\n",
"# Create triples (some invalid)\n",
"triples_to_validate = [\n",
@@ -650,7 +650,7 @@
"outputs": [],
"source": [
"# Register multiple stores\n",
"manager = TripleManager()\n",
"manager = TripletManager()\n",
"\n",
"primary = manager.register_store(\n",
" \"primary\",\n",
@@ -720,7 +720,7 @@
"\n",
"In this notebook, you've learned how to:\n",
"\n",
"- Register and manage triple stores\n",
"- Register and manage triplet stores\n",
"- Perform CRUD operations on RDF triples\n",
"- Execute and optimize SPARQL queries\n",
"- Use bulk loading for large datasets\n",
@@ -740,7 +740,7 @@
"### Next Steps\n",
"\n",
"**Further Reading**:\n",
"- [Triple Store API Reference](https://semantica.readthedocs.io/reference/triple_store/)\n",
"- [Triplet Store API Reference](https://semantica.readthedocs.io/reference/triplet_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",
@@ -771,4 +771,4 @@
},
"nbformat": 4,
"nbformat_minor": 2
}
}
@@ -38,7 +38,7 @@
"- **Parsing**: DocumentParser, PDFParser, StructuredDataParser, CSVParser, MCPParser\n",
"- **Extraction**: NERExtractor, RelationExtractor, CoreferenceResolver, TripleExtractor\n",
"- **KG**: GraphBuilder, GraphValidator, EntityResolver, GraphAnalyzer\n",
"- **Triple Store**: TripleStore, TripleManager, QueryEngine\n",
"- **Triplet Store**: TripletStore, TripletManager, QueryEngine\n",
"- **Reasoning**: InferenceEngine, RuleManager, ExplanationGenerator\n",
"- **Quality**: KGQualityAssessor, ValidationEngine\n",
"- **Export**: JSONExporter, RDFExporter, OWLExporter, ReportGenerator\n",
@@ -67,7 +67,6 @@
"from semantica.kg import GraphBuilder, GraphValidator, EntityResolver, GraphAnalyzer\n",
"from semantica.triple_store import TripleStore, TripleManager, QueryEngine\n",
"from semantica.reasoning import InferenceEngine, RuleManager, ExplanationGenerator\n",
"from semantica.export import JSONExporter, RDFExporter, OWLExporter, ReportGenerator\n",
"from semantica.visualization import KGVisualizer, OntologyVisualizer, TemporalVisualizer\n",
"import tempfile\n",
@@ -22,7 +22,7 @@
"- **Materialized Knowledge Graphs**: Semantica's KG modules enable building persistent knowledge graphs from medical ontologies, clinical documents, and reports\n",
"- **Virtual Data Integration**: Semantica's DBIngestor and QueryEngine allow virtual integration with Electronic Health Records (EHRs) without data replication\n",
"- **Hybrid Design**: Semantica's architecture naturally separates structural knowledge from patient-level data\n",
"- **Dynamic Query Orchestration**: Semantica's Reasoning and Triple Store modules enable orchestration of queries across ontologies, documents, and EHRs\n",
"- **Dynamic Query Orchestration**: Semantica's Reasoning and Triplet Store modules enable orchestration of queries across ontologies, documents, and EHRs\n",
"- **Temporal & Semantic Dimensions**: Semantica's Temporal and Context modules provide historical analysis and semantic understanding\n",
"- **Traceable & Explainable**: Semantica's ExplanationGenerator and ContextRetriever provide traceable, explainable answers\n",
"\n",
@@ -55,7 +55,7 @@
"- **KG**: GraphBuilder, GraphAnalyzer, ConnectivityAnalyzer (materialized knowledge graph)\n",
"- **Embeddings**: EmbeddingGenerator, TextEmbedder (for embeddings)\n",
"- **Vector Store**: VectorStore, HybridSearch, MetadataFilter (for RAG)\n",
"- **Triple Store**: TripleManager, QueryEngine (for SPARQL queries on ontologies)\n",
"- **Triplet Store**: TripletManager, QueryEngine (for SPARQL queries on ontologies)\n",
"- **Reasoning**: InferenceEngine, RuleManager (for query orchestration and medical reasoning)\n",
"- **Context**: ContextRetriever, ContextGraphBuilder (for contextual retrieval)\n",
"- **Visualization**: KGVisualizer, TemporalVisualizer, AnalyticsVisualizer (for visualization)\n",
@@ -86,7 +86,7 @@
"from semantica.kg import GraphBuilder, GraphAnalyzer, ConnectivityAnalyzer\n",
"from semantica.embeddings import EmbeddingGenerator, TextEmbedder\n",
"from semantica.vector_store import VectorStore, HybridSearch, MetadataFilter\n",
"from semantica.triple_store import TripleManager, QueryEngine\n",
"from semantica.triplet_store import TripletManager, QueryEngine\n",
"from semantica.reasoning import InferenceEngine, RuleManager, ExplanationGenerator\n",
"from semantica.context import ContextRetriever, ContextGraphBuilder\n",
"from semantica.visualization import KGVisualizer, TemporalVisualizer, AnalyticsVisualizer\n",
@@ -440,9 +440,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 9: Setup Triple Store for Ontology Queries Using Semantica\n",
"## Step 9: Setup Triplet Store for Ontology Queries Using Semantica\n",
"\n",
"Using Semantica's triple store modules to enable SPARQL queries on medical ontologies.\n"
"Using Semantica's triplet store modules to enable SPARQL queries on medical ontologies.\n"
]
},
{
@@ -451,12 +451,12 @@
"metadata": {},
"outputs": [],
"source": [
"# Initialize Semantica triple store and query engine\n",
"triple_manager = TripleManager()\n",
"# Initialize Semantica triplet store and query engine\n",
"triplet_manager = TripletManager()\n",
"query_engine = QueryEngine()\n",
"\n",
"# Register triple store (using in-memory for demo)\n",
"store = triple_manager.register_store(\"healthcare_ontology\", \"jena\", \"http://localhost:3030/healthcare\")\n",
"# Register triplet store (using in-memory for demo)\n",
"store = triplet_manager.register_store(\"healthcare_ontology\", \"jena\", \"http://localhost:3030/healthcare\")\n",
"\n",
"# Convert ontology to triples and add to store\n",
"# In production, this would load the OWL ontology\n",
@@ -477,7 +477,7 @@
"\n",
"# Add triples using Semantica\n",
"for triple in sample_triples:\n",
" triple_manager.add_triple(triple, store_id=\"healthcare_ontology\")\n",
" triplet_manager.add_triple(triple, store_id=\"healthcare_ontology\")\n",
"\n",
"print(f\" - Triples added: {len(sample_triples)}\")\n",
"print(f\" - SPARQL queries enabled for ontology\")\n"
@@ -531,7 +531,7 @@
" \"context\": {}\n",
" }\n",
" \n",
" # 1. Query ontology using Semantica Triple Store\n",
" # 1. Query ontology using Semantica Triplet Store\n",
" sparql_query = f\"\"\"\n",
" SELECT ?concept WHERE {{\n",
" ?concept rdfs:label ?label .\n",
@@ -769,12 +769,12 @@
"2. **Materialized Knowledge Graphs**: Semantica's KG modules enable building persistent knowledge graphs from medical ontologies and documents\n",
"3. **Virtual Data Integration**: Semantica's DBIngestor allows virtual integration with EHRs without data replication\n",
"4. **Hybrid Search**: Semantica's HybridSearch combines vector similarity with knowledge graph queries\n",
"5. **Query Orchestration**: Semantica's Reasoning and Triple Store modules enable dynamic query orchestration\n",
"6. **Explainability**: Semantica's ExplanationGenerator provides traceable, explainable answers\n",
"5. **Query Orchestration**: Semantica's Reasoning and Triplet Store modules enable dynamic query orchestration\n",
"6. **Explainability**: Semantica's ExplanationGenerator provides traceable, explainable answers\n",
"\n",
"### Semantica-Specific Performance Considerations\n",
"\n",
"- **Vector Store**: Use Semantica's VectorStore with appropriate backend (FAISS for local, Pinecone/Weaviate for cloud)\n",
"- **Vector Store**: Use Semantica's VectorStore with appropriate backend (FAISS for local, Weaviate for cloud)\n",
"- **Graph Analytics**: Leverage Semantica's GraphAnalyzer for efficient centrality and community detection\n",
"- **Pipeline Execution**: Use Semantica's ExecutionEngine for parallel execution of pipeline steps\n",
"- **Caching**: Utilize Semantica's ContextRetriever caching for frequently accessed contexts\n",
@@ -30,7 +30,7 @@
"- **Parsing**: MCPParser, JSONParser, StructuredDataParser, DocumentParser\n",
"- **Extraction**: NERExtractor, RelationExtractor, TripleExtractor, SemanticAnalyzer\n",
"- **KG**: GraphBuilder, GraphValidator, EntityResolver, GraphAnalyzer\n",
"- **Triple Store**: TripleStore, TripleManager, QueryEngine\n",
"- **Triplet Store**: TripletStore, TripletManager, QueryEngine\n",
"- **Reasoning**: InferenceEngine, RuleManager, ExplanationGenerator\n",
"- **Quality**: KGQualityAssessor, ValidationEngine\n",
"- **Export**: JSONExporter, RDFExporter, OWLExporter, ReportGenerator\n",
@@ -67,9 +67,8 @@
"from semantica.parse import MCPParser, JSONParser, StructuredDataParser, DocumentParser\n",
"from semantica.semantic_extract import NERExtractor, RelationExtractor, TripleExtractor, SemanticAnalyzer\n",
"from semantica.kg import GraphBuilder, GraphValidator, EntityResolver, GraphAnalyzer\n",
"from semantica.triple_store import TripleStore, TripleManager, QueryEngine\n",
"from semantica.triplet_store import TripletStore, TripletManager, QueryEngine\n",
"from semantica.reasoning import InferenceEngine, RuleManager, ExplanationGenerator\n",
"from semantica.export import JSONExporter, RDFExporter, OWLExporter, ReportGenerator\n",
"from semantica.visualization import KGVisualizer, OntologyVisualizer, TemporalVisualizer\n",
"import json\n",
@@ -402,7 +401,7 @@
"source": [
"## Step 5: Build Healthcare Knowledge Graph\n",
"\n",
"Build a knowledge graph from the extracted medical entities and relationships, then store in triple store.\n"
"Build a knowledge graph from the extracted medical entities and relationships, then store in triplet store.\n"
]
},
{
@@ -426,13 +425,17 @@
"# Analyze graph structure\n",
"metrics = graph_analyzer.compute_metrics(resolved_kg)\n",
"\n",
"# Store in triple store\n",
"triple_store = TripleStore()\n",
"triple_manager = TripleManager()\n",
"# Store in triplet store\n",
"# triplet_store = TripletStore() # TripletStore is a configuration dataclass\n",
"triplet_manager = TripletManager()\n",
"query_engine = QueryEngine()\n",
"\n",
"triple_store.add_knowledge_graph(resolved_kg)\n",
"triple_manager.manage_triples(resolved_kg)\n",
"# Register default store (in-memory for demo)\n",
"store = triplet_manager.register_store(\"medical_kg\", \"jena\", \"http://localhost:3030/medical\")\n",
"\n",
"# Convert KG to triples and add to store (simplified)\n",
"# In a real scenario, we would convert entities/relations to triples first\n",
"# triplet_manager.add_triples(triples, store_id=\"medical_kg\")\n",
"\n",
"print(f\" Entities: {len(resolved_kg.get('entities', []))}\")\n",
"print(f\" Relationships: {len(resolved_kg.get('relationships', []))}\")\n",
@@ -22,13 +22,13 @@
"- **Extraction**: NERExtractor, RelationExtractor, CoreferenceResolver\n",
"- **KG**: GraphBuilder, TemporalGraphQuery, GraphValidator, EntityResolver\n",
"- **Ontology**: OntologyGenerator, ClassInferrer, PropertyGenerator, OntologyValidator\n",
"- **Triple Store**: TripleStore, TripleManager, QueryEngine\n",
"- **Triplet Store**: TripletStore, TripletManager, QueryEngine\n",
"- **Export**: RDFExporter, OWLExporter, JSONExporter\n",
"- **Visualization**: KGVisualizer, OntologyVisualizer, TemporalVisualizer\n",
"\n",
"### Pipeline\n",
"\n",
"**Patient Records → Parse → Extract Medical Entities → Build Temporal KG → Generate Ontology → Store in Triple Store → Query History → Export → Visualize**\n",
"**Patient Records → Parse → Extract Medical Entities → Build Temporal KG → Generate Ontology → Store in Triplet Store → Query History → Export → Visualize**\n",
"\n",
"## Installation\n",
"\n",
@@ -58,7 +58,7 @@
"from semantica.semantic_extract import NERExtractor, RelationExtractor, CoreferenceResolver\n",
"from semantica.kg import GraphBuilder, TemporalGraphQuery, GraphValidator, EntityResolver\n",
"from semantica.ontology import OntologyGenerator, ClassInferrer, PropertyGenerator, OntologyValidator\n",
"from semantica.triple_store import TripleStore, TripleManager, QueryEngine\n",
"from semantica.triplet_store import TripletStore, TripletManager, QueryEngine\n",
"from semantica.export import RDFExporter, OWLExporter, JSONExporter\n",
"from semantica.visualization import KGVisualizer, OntologyVisualizer, TemporalVisualizer\n",
"import tempfile\n",
@@ -261,9 +261,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 5: Store in Triple Store and Query\n",
"## Step 5: Store in Triplet Store and Query\n",
"\n",
"Store knowledge graph in triple store and query medical history.\n"
"Store knowledge graph in triplet store and query medical history.\n"
]
},
{
@@ -272,12 +272,12 @@
"metadata": {},
"outputs": [],
"source": [
"triple_store = TripleStore()\n",
"triple_manager = TripleManager()\n",
"triplet_store = TripletStore()\n",
"triple_manager = TripletManager()\n",
"query_engine = QueryEngine()\n",
"temporal_query = TemporalGraphQuery()\n",
"\n",
"triple_store.store_knowledge_graph(patient_kg)\n",
"triplet_store.store_knowledge_graph(patient_kg)\n",
"\n",
"patient_id = \"P001\"\n",
"start_time = \"2024-01-01\"\n",
@@ -290,7 +290,7 @@
" end_time=end_time\n",
")\n",
"\n",
"print(f\"Stored patient knowledge graph in triple store\")\n",
"print(f\"Stored patient knowledge graph in triplet store\")\n",
"print(f\"Retrieved {len(medical_history.get('entities', []))} medical events for patient {patient_id}\")\n"
]
},
@@ -326,7 +326,7 @@
"temporal_viz = temporal_visualizer.visualize_timeline(patient_kg, output=\"interactive\")\n",
"\n",
"print(f\"Total modules used: 20+\")\n",
"print(f\"Pipeline complete: Patient Records → Parse → Extract → Temporal KG → Ontology → Triple Store → Query → Export → Visualize\")\n"
"print(f\"Pipeline complete: Patient Records → Parse → Extract → Temporal KG → Ontology → Triplet Store → Query → Export → Visualize\")\n"
]
}
],
+3 -3
View File
@@ -32,7 +32,7 @@ from semantica import Semantica
core = Semantica(
llm_provider="openai",
embedding_model="text-embedding-3-large",
vector_store="pinecone",
vector_store="weaviate",
graph_db="neo4j"
)
@@ -279,7 +279,7 @@ owl_ontology = ontology.to_owl()
rdf_ontology = ontology.to_rdf()
turtle_ontology = ontology.to_turtle()
# Save to triple store
# Save to triplet store
ontology.save_to_triple_store("http://localhost:9999/blazegraph/sparql")
```
@@ -357,7 +357,7 @@ semantic_chunks = embedder.semantic_chunk(documents)
embeddings = embedder.generate_embeddings(semantic_chunks)
# Store in vector database
vector_store = core.get_vector_store("pinecone")
vector_store = core.get_vector_store("weaviate")
vector_store.store_embeddings(semantic_chunks, embeddings)
# Semantic search
+3 -3
View File
@@ -66,8 +66,8 @@ graph TB
### Knowledge Graphs
- **`semantica.kg`** - Knowledge graph construction
- **`semantica.vector_store`** - Vector storage (Pinecone, Weaviate, FAISS)
- **`semantica.triple_store`** - RDF triple storage (Jena, Blazegraph)
- **`semantica.vector_store`** - Vector storage (Weaviate, FAISS)
- **`semantica.triplet_store`** - RDF triplet storage (Jena, Blazegraph)
- **`semantica.graph_store`** - Property graphs (Neo4j, FalkorDB)
### Quality Assurance
@@ -85,7 +85,7 @@ graph TB
4. Semantic Extraction → Entities, relationships, events
5. Graph Construction → Entity resolution, conflict resolution
6. Quality Assurance → Deduplication, validation
7. Storage → Vector, triple, and graph stores
7. Storage → Vector, triplet, and graph stores
8. Application → GraphRAG, agents, analytics
```
-1
View File
@@ -25,7 +25,6 @@ Projects and integrations from the Semantica community.
## 🔌 Integrations
### Vector Databases
- Pinecone
- Weaviate
- Qdrant
- FAISS
+1 -1
View File
@@ -181,7 +181,7 @@ A comprehensive reference of terms and concepts used in Semantica.
**Triple**
: A basic unit of knowledge in RDF, consisting of a subject, predicate, and object (e.g., `<Apple_Inc> <founded_by> <Steve_Jobs>`).
**Triple Store**
**Triplet Store**
: A database designed specifically for storing and querying RDF triples.
---
+10 -11
View File
@@ -15,7 +15,7 @@ Semantica's modules are organized into six logical layers:
| :--- | :--- | :--- |
| **Input Layer** | [Ingest](#ingest-module), [Parse](#parse-module), [Split](#split-module), [Normalize](#normalize-module) | Data ingestion, parsing, chunking, and cleaning |
| **Core Processing** | [Semantic Extract](#semantic-extract-module), [Knowledge Graph](#knowledge-graph-kg-module), [Ontology](#ontology-module), [Reasoning](#reasoning-module) | Entity extraction, graph construction, inference |
| **Storage** | [Embeddings](#embeddings-module), [Vector Store](#vector-store-module), [Graph Store](#graph-store-module), [Triple Store](#triple-store-module) | Vector and graph persistence |
| **Storage** | [Embeddings](#embeddings-module), [Vector Store](#vector-store-module), [Graph Store](#graph-store-module), [Triplet Store](#triplet-store-module) | Vector, graph, and triplet persistence |
| **Quality Assurance** | [Deduplication](#deduplication-module), [Conflicts](#conflicts-module) | Data quality and consistency |
| **Context & Memory** | [Context](#context-module), [Seed](#seed-module) | Agent memory and foundation data |
| **Output & Orchestration** | [Export](#export-module), [Visualization](#visualization-module), [Pipeline](#pipeline-module) | Export, visualization, and workflow management |
@@ -468,7 +468,7 @@ print(f"Similarity: {similarity:.3f}")
**Key Features:**
- Multiple backend support (FAISS, Pinecone, Weaviate, Qdrant, Milvus)
- Multiple backend support (FAISS, Weaviate, Qdrant, Milvus)
- Hybrid search (vector + keyword)
- Metadata filtering
- Batch operations
@@ -480,7 +480,6 @@ print(f"Similarity: {similarity:.3f}")
- `VectorStore` — Main vector store interface
- `FAISSAdapter` — FAISS integration
- `PineconeAdapter` — Pinecone integration
- `WeaviateAdapter` — Weaviate integration
- `HybridSearch` — Combine vector and keyword search
- `VectorRetriever` — Retrieve relevant vectors
@@ -563,15 +562,15 @@ results = store.execute_query("MATCH (p:Person) RETURN p.name")
---
### Triple Store Module
### Triplet Store Module
!!! abstract "Purpose"
RDF triple store integration for semantic web applications. Supports SPARQL queries and multiple backends.
RDF triplet store integration for semantic web applications. Supports SPARQL queries and multiple backends.
**Key Features:**
- Multi-backend support (Blazegraph, Jena, RDF4J, Virtuoso)
- CRUD operations for RDF triples
- CRUD operations for RDF triplets
- SPARQL query execution and optimization
- Bulk data loading with progress tracking
- Query caching and optimization
@@ -580,7 +579,7 @@ results = store.execute_query("MATCH (p:Person) RETURN p.name")
**Components:**
- `TripleManager` — Main triple store management coordinator
- `TripletManager` — Main triplet store management coordinator
- `QueryEngine` — SPARQL query execution and optimization
- `BulkLoader` — High-volume data loading with progress tracking
- `BlazegraphAdapter` — Blazegraph integration
@@ -601,9 +600,9 @@ results = store.execute_query("MATCH (p:Person) RETURN p.name")
**Quick Example:**
```python
from semantica.triple_store import TripleManager, execute_query
from semantica.triplet_store import TripletManager, execute_query
manager = TripleManager()
manager = TripletManager()
store = manager.register_store("main", "blazegraph", "http://localhost:9999/blazegraph")
# Add triple
@@ -617,7 +616,7 @@ result = manager.add_triple({
query_result = execute_query("SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10", store)
```
**API Reference**: [Triple Store Module](reference/triple_store.md)
**API Reference**: [Triplet Store Module](reference/triplet_store.md)
---
@@ -1114,7 +1113,7 @@ new_facts = inference_engine.forward_chain(kg, rule_manager)
| **Embeddings** | `semantica.embeddings` | `EmbeddingGenerator` | Vector generation |
| **Vector Store** | `semantica.vector_store` | `VectorStore` | Vector storage |
| **Graph Store** | `semantica.graph_store` | `GraphStore` | Graph database |
| **Triple Store** | `semantica.triple_store` | `TripleManager` | RDF storage |
| **Triplet Store** | `semantica.triplet_store` | `TripletManager` | RDF storage |
| **Deduplication** | `semantica.deduplication` | `DuplicateDetector` | Duplicate removal |
| **Conflicts** | `semantica.conflicts` | `ConflictDetector` | Conflict resolution |
| **Context** | `semantica.context` | `AgentMemory` | Agent context |
+1 -1
View File
@@ -57,7 +57,7 @@ The **Context Module** provides agents with a persistent, searchable, and struct
The high-level facade that unifies all context operations. It routes data to the appropriate subsystems (Memory, Graph, Vector Store) and manages the lifecycle of context.
#### **Constructor Parameters**
* `vector_store` (Required): The backing vector database instance (e.g., FAISS, Pinecone).
* `vector_store` (Required): The backing vector database instance (e.g., FAISS, Weaviate).
* `knowledge_graph` (Optional): The graph store instance for structured knowledge.
* `token_limit` (Default: `2000`): The maximum number of tokens allowed in short-term memory before pruning occurs.
* `short_term_limit` (Default: `10`): The maximum number of distinct memory items in short-term memory.
+3 -3
View File
@@ -34,7 +34,7 @@ The **Embeddings Module** provides a unified interface for generating vector rep
---
Automatic formatting and validation for FAISS, Pinecone, Qdrant, and Weaviate.
Automatic formatting and validation for FAISS, Qdrant, and Weaviate.
</div>
@@ -122,13 +122,13 @@ print(f"Dimension: {embedder.get_embedding_dimension()}")
---
### VectorEmbeddingManager (The Bridge)
A utility class that prepares raw embeddings for insertion into specific vector databases. It handles formatting differences between backends like FAISS and Pinecone.
A utility class that prepares raw embeddings for insertion into specific vector databases. It handles formatting differences between backends like FAISS and Weaviate.
#### **Core Methods**
| Method | Description |
|--------|-------------|
| `prepare_for_vector_db(embeddings, backend, ...)` | Formats data for the target DB. |
| `prepare_for_vector_db(embeddings, metadata, backend)` | Formats data for the target DB. |
| `validate_dimensions(embeddings, expected_dim)` | Ensures vectors match the index configuration. |
| `batch_prepare(embeddings_list)` | Prepares a batch of embeddings for storage. |
+1 -1
View File
@@ -414,7 +414,7 @@ subgraph = graph_store.execute_query(query, parameters={"ids": node_ids})
## See Also
- [Knowledge Graph Module](kg.md) - Logical layer above Graph Store
- [Triple Store Module](triple_store.md) - RDF-based alternative
- [Triplet Store Module](triplet_store.md) - RDF-based alternative
- [Visualization Module](visualization.md) - Visualizing query results
## Cookbook
+1 -1
View File
@@ -245,7 +245,7 @@ kg.add_triples(inferred_triples)
## See Also
- [Ontology Module](ontology.md) - Source of schema-based rules
- [Triple Store Module](triple_store.md) - Backend for SPARQL reasoning
- [Triplet Store Module](triplet_store.md) - Backend for SPARQL reasoning
- [Modules Guide](../modules.md#quality-assurance) - Consistency checking overview
## Cookbook
+152 -3
View File
@@ -44,6 +44,12 @@
Use LLMs to improve extraction quality and handle complex schemas
- :material-graph:{ .lg .middle } **Semantic Networks**
---
Build structured networks with nodes and edges from text
</div>
!!! tip "When to Use"
@@ -119,6 +125,49 @@ ner = NamedEntityRecognizer(
entities = ner.extract_entities("Apple Inc. was founded in 1976.")
```
### NERExtractor
Core entity extraction implementation used by notebooks and lower-level integrations.
**Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `method` | str or list | `"ml"` | Method(s): "ml", "llm", "pattern", "regex", "huggingface" |
| `**config` | dict | `{}` | Method-specific config (e.g., `model`, `provider`) |
**Methods:**
| Method | Description |
|--------|-------------|
| `extract(text)` | Alias for `extract_entities`. Get list of entities. |
| `extract_entities(text)` | Get list of entities |
**Example:**
```python
from semantica.semantic_extract import NERExtractor
# 1. ML (spaCy) - Default
extractor = NERExtractor(method="ml", model="en_core_web_trf")
entities = extractor.extract("Elon Musk leads SpaceX.")
# 2. LLM (OpenAI/Gemini/etc)
extractor = NERExtractor(
method="llm",
provider="openai",
model="gpt-4",
temperature=0.0
)
# 3. Regex with custom patterns
patterns = {"CODE": r"[A-Z]{3}-\d{3}"}
extractor = NERExtractor(method="regex", patterns=patterns)
# 4. Ensemble (Multiple methods)
extractor = NERExtractor(method=["ml", "llm"], ensemble_voting=True)
```
### RelationExtractor
Extracts relationships between entities.
@@ -136,6 +185,7 @@ Extracts relationships between entities.
| Method | Description |
|--------|-------------|
| `extract(text, entities)` | Alias for `extract_relations`. Find links. |
| `extract_relations(text, entities)` | Find links |
**Example:**
@@ -150,7 +200,7 @@ entities = ner.extract_entities(text)
# Basic relation extraction
rel_extractor = RelationExtractor()
relations = rel_extractor.extract_relations(text, entities=entities)
relations = rel_extractor.extract(text, entities=entities)
# [Relation(source="Elon Musk", target="SpaceX", type="founded")]
# With configuration
@@ -159,7 +209,39 @@ rel_extractor = RelationExtractor(
confidence_threshold=0.7,
bidirectional=False
)
relations = rel_extractor.extract_relations(text, entities=entities)
relations = rel_extractor.extract(text, entities=entities)
```
### CoreferenceResolver
Resolves pronoun references and entity coreferences.
**Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `method` | str or list | `None` | Underlying NER method(s) |
| `**config` | dict | `{}` | Configuration for NER method |
**Methods:**
| Method | Description |
|--------|-------------|
| `resolve(text)` | Alias for `resolve_coreferences`. Get coreference chains. |
| `resolve_coreferences(text)` | Get coreference chains |
| `resolve_pronouns(text)` | Resolve pronouns to entities |
**Example:**
```python
from semantica.semantic_extract import CoreferenceResolver
resolver = CoreferenceResolver()
text = "Steve Jobs founded Apple. He was the CEO."
# Resolve references
chains = resolver.resolve(text)
# [CoreferenceChain(mentions=["Steve Jobs", "He"], representative="Steve Jobs")]
```
### EventDetector
@@ -204,6 +286,7 @@ Extracts RDF triples (Subject-Predicate-Object).
|-----------|------|---------|-------------|
| `include_temporal` | bool | `False` | Include time information |
| `include_provenance` | bool | `False` | Track source sentences |
| `method` | str | `"pattern"` | Extraction method ("pattern", "rules", "huggingface", "llm") |
**Methods:**
@@ -224,6 +307,66 @@ triples = extractor.extract_triples("Steve Jobs founded Apple in 1976.")
# [Triple(subject="Steve Jobs", predicate="founded", object="Apple", temporal="1976")]
```
### SemanticNetworkExtractor
Extracts structured semantic networks with nodes and edges.
**Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `ner_method` | str | `None` | Method for node extraction |
| `relation_method` | str | `None` | Method for edge extraction |
| `**config` | dict | `{}` | Configuration for underlying extractors |
**Methods:**
| Method | Description |
|--------|-------------|
| `extract_network(text)` | Build network from text |
| `extract(text)` | Alias for `extract_network` |
| `export_to_yaml(network, path)` | Save network to YAML |
**Example:**
```python
from semantica.semantic_extract import SemanticNetworkExtractor
extractor = SemanticNetworkExtractor()
network = extractor.extract("Apple Inc. is located in Cupertino.")
# Analyze network
print(f"Nodes: {len(network.nodes)}")
print(f"Edges: {len(network.edges)}")
```
### LLMEnhancer
Enhances extraction results using Large Language Models.
**Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `provider` | str | `"openai"` | LLM provider ("openai", "gemini", "anthropic", etc.) |
| `**config` | dict | `{}` | Model config (model name, api_key, etc.) |
**Methods:**
| Method | Description |
|--------|-------------|
| `enhance_entities(text, entities)` | Improve entity accuracy and details |
| `enhance_relations(text, relations)` | Improve relation detection |
**Example:**
```python
from semantica.semantic_extract import LLMEnhancer
enhancer = LLMEnhancer(provider="openai", model="gpt-4")
enhanced_entities = enhancer.enhance_entities(text, entities)
```
---
## Usage Examples
@@ -234,7 +377,8 @@ from semantica.semantic_extract import (
RelationExtractor,
TripleExtractor,
EventDetector,
CoreferenceResolver
CoreferenceResolver,
SemanticNetworkExtractor
)
text = "Apple released the iPhone in 2007. Steve Jobs announced it at Macworld."
@@ -259,10 +403,15 @@ triples = triple_extractor.extract_triples(text)
event_detector = EventDetector(extract_time=True)
events = event_detector.detect_events(text)
# Extract semantic network
network_extractor = SemanticNetworkExtractor()
network = network_extractor.extract(text)
print(f"Entities: {len(entities)}")
print(f"Relations: {len(relations)}")
print(f"Triples: {len(triples)}")
print(f"Events: {len(events)}")
print(f"Network Nodes: {len(network.nodes)}")
```
---
+40 -60
View File
@@ -150,7 +150,7 @@ TextSplitter(
similarity_threshold=0.7, # Semantic boundary threshold
# Entity-aware options
ner_method="spacy", # NER method (spacy, llm, transformers)
ner_method="ml", # NER method (ml/spacy, llm, pattern)
preserve_entities=True, # Don't split entities
# LLM options
@@ -183,7 +183,7 @@ for i, chunk in enumerate(chunks):
# Entity-aware for GraphRAG
splitter = TextSplitter(
method="entity_aware",
ner_method="llm",
ner_method="ml",
chunk_size=1000,
preserve_entities=True
)
@@ -250,8 +250,6 @@ Preserve entity boundaries during chunking for GraphRAG.
| Method | Description | Algorithm |
|--------|-------------|-----------|
| `chunk(text, entities)` | Chunk preserving entities | Entity boundary detection |
| `extract_entities(text)` | Extract entities | NER extraction |
| `find_safe_split_points(text, entities)` | Find split points | Entity span checking |
**Example:**
@@ -260,14 +258,14 @@ from semantica.split import EntityAwareChunker
from semantica.semantic_extract import NERExtractor
# Extract entities first
ner = NERExtractor(method="llm")
ner = NERExtractor(method="ml")
entities = ner.extract(text)
# Chunk preserving entities
chunker = EntityAwareChunker(
chunk_size=1000,
chunk_overlap=200,
ner_method="llm"
ner_method="ml"
)
chunks = chunker.chunk(text, entities=entities)
@@ -360,8 +358,7 @@ Structure-aware chunking respecting document hierarchy.
| Method | Description | Algorithm |
|--------|-------------|-----------|
| `chunk(text)` | Chunk by structure | Heading/section detection |
| `detect_structure(text)` | Detect document structure | Markdown/HTML parsing |
| `build_hierarchy(sections)` | Build section hierarchy | Tree construction |
| `_extract_structure(text)` | Extract structural elements | Markdown/HTML parsing |
**Example:**
@@ -369,17 +366,16 @@ Structure-aware chunking respecting document hierarchy.
from semantica.split import StructuralChunker
chunker = StructuralChunker(
respect_headings=True,
respect_paragraphs=True,
respect_lists=True,
respect_headers=True,
respect_sections=True,
max_chunk_size=2000
)
chunks = chunker.chunk(markdown_text)
for chunk in chunks:
print(f"Section: {chunk.metadata.get('section_title')}")
print(f"Level: {chunk.metadata.get('heading_level')}")
print(f"Structure preserved: {chunk.metadata.get('structure_preserved')}")
print(f"Elements: {chunk.metadata.get('element_types')}")
```
---
@@ -393,7 +389,6 @@ Multi-level hierarchical chunking.
| Method | Description | Algorithm |
|--------|-------------|-----------|
| `chunk(text)` | Multi-level chunking | Recursive hierarchical split |
| `create_hierarchy(chunks)` | Create chunk hierarchy | Tree structure |
**Example:**
@@ -470,16 +465,15 @@ Fixed-size sliding window chunking with configurable step size.
| Method | Description | Algorithm |
|--------|-------------|-----------|
| `chunk(text)` | Sliding window chunking | Fixed-size window with step |
| `calculate_windows(text_length)` | Calculate window positions | Window position calculation |
| `chunk_with_overlap(text)` | Chunk with specific overlap | Window position calculation |
**Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `window_size` | int | 1000 | Size of sliding window |
| `step_size` | int | 800 | Step size (window_size - overlap) |
| `min_chunk_size` | int | 100 | Minimum chunk size |
| `preserve_sentences` | bool | False | Preserve sentence boundaries |
| `chunk_size` | int | 1000 | Size of sliding window |
| `overlap` | int | 0 | Overlap size |
| `stride` | int | chunk_size - overlap | Step size |
**Example:**
@@ -488,25 +482,18 @@ from semantica.split import SlidingWindowChunker
# Basic sliding window
chunker = SlidingWindowChunker(
window_size=1000,
step_size=800, # 200 overlap
min_chunk_size=100
chunk_size=1000,
overlap=200
)
chunks = chunker.chunk(long_text)
for i, chunk in enumerate(chunks):
print(f"Window {i}: chars {chunk.start}-{chunk.end}")
print(f"Overlap with previous: {chunk.metadata.get('overlap_chars')}")
print(f"Window {i}: chars {chunk.start_index}-{chunk.end_index}")
print(f"Has overlap: {chunk.metadata.get('has_overlap')}")
# Sentence-preserving sliding window
chunker = SlidingWindowChunker(
window_size=1000,
step_size=750,
preserve_sentences=True
)
chunks = chunker.chunk(text)
# Boundary-preserving sliding window
chunks = chunker.chunk(text, preserve_boundaries=True)
```
---
@@ -519,18 +506,17 @@ Table-specific chunking preserving table structure.
| Method | Description | Algorithm |
|--------|-------------|-----------|
| `chunk(text)` | Chunk tables | Table detection and splitting |
| `detect_tables(text)` | Detect tables in text | Table boundary detection |
| `split_table(table, max_rows)` | Split large tables | Row-based table splitting |
| `chunk_table(table_data)` | Chunk tables | Row/Column-based splitting |
| `chunk_to_text_chunks(table_data)` | Convert table chunks to text | Table to text conversion |
| `extract_table_schema(table_data)` | Extract schema | Type inference and schema extraction |
**Parameters:**
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `max_rows` | int | 100 | Maximum rows per table chunk |
| `preserve_headers` | bool | True | Keep headers in each chunk |
| `max_rows_per_chunk` | int | 50 | Maximum rows per table chunk |
| `include_context` | bool | True | Include surrounding text context |
| `table_format` | str | "auto" | Table format (markdown, html, csv, auto) |
| `chunk_by_columns` | bool | False | Chunk by columns instead of rows |
**Example:**
@@ -538,31 +524,25 @@ Table-specific chunking preserving table structure.
from semantica.split import TableChunker
chunker = TableChunker(
max_rows=50,
preserve_headers=True,
max_rows_per_chunk=50,
include_context=True,
table_format="markdown"
chunk_by_columns=False
)
text_with_tables = \"\"\"
Document with tables...
table_data = {
"headers": ["Col1", "Col2", "Col3"],
"rows": [["Val1", "Val2", "Val3"], ...]
}
| Column 1 | Column 2 | Column 3 |
|----------|----------|----------|
| Value 1 | Value 2 | Value 3 |
| ... | ... | ... |
\"\"\"
# Get structured table chunks
table_chunks = chunker.chunk_table(table_data)
chunks = chunker.chunk(text_with_tables)
# Get text chunks for RAG
text_chunks = chunker.chunk_to_text_chunks(table_data)
for chunk in chunks:
if chunk.metadata.get('is_table'):
print(f"Table chunk:")
print(f" Rows: {chunk.metadata.get('row_count')}")
print(f" Columns: {chunk.metadata.get('column_count')}")
print(f" Headers: {chunk.metadata.get('headers')}")
else:
print(f"Text chunk: {len(chunk.text)} chars")
for chunk in text_chunks:
print(f"Table chunk {chunk.metadata.get('chunk_index')}")
print(f"Rows: {chunk.metadata.get('row_count')}")
```
---
@@ -663,7 +643,7 @@ print(f"Available methods: {methods}")
# Quick splitting
chunks = split_recursive(text, chunk_size=1000, chunk_overlap=200)
chunks = split_by_sentences(text, sentences_per_chunk=5)
chunks = split_entity_aware(text, ner_method="llm")
chunks = split_entity_aware(text, ner_method="ml")
```
---
@@ -683,7 +663,7 @@ export SPLIT_EMBEDDING_MODEL=all-MiniLM-L6-v2
export SPLIT_SIMILARITY_THRESHOLD=0.7
# Entity-aware
export SPLIT_NER_METHOD=spacy
export SPLIT_NER_METHOD=ml # or spacy
export SPLIT_PRESERVE_ENTITIES=true
# LLM-based
@@ -712,7 +692,7 @@ split:
max_chunk_size: 2000
entity_aware:
ner_method: spacy
ner_method: ml # or spacy
preserve_entities: true
min_entity_gap: 50
@@ -1,6 +1,6 @@
# Triple Store
# Triplet Store
> **Store and query RDF triples with SPARQL support and semantic reasoning using industry-standard triple stores.**
> **Store and query RDF triplets with SPARQL support and semantic reasoning using industry-standard triplet stores.**
---
@@ -12,7 +12,7 @@
---
Store subject-predicate-object triples in W3C-compliant RDF format
Store subject-predicate-object triplets in W3C-compliant RDF format
- :material-code-braces:{ .lg .middle } **SPARQL Queries**
@@ -36,7 +36,7 @@
---
Query across multiple triple stores with SPARQL federation
Query across multiple triplet stores with SPARQL federation
- :material-upload-multiple:{ .lg .middle } **Bulk Loading**
@@ -89,29 +89,29 @@
## Main Classes
### TripleManager
### TripletManager
Main coordinator for triple store operations across multiple backends.
Main coordinator for triplet store operations across multiple backends.
**Methods:**
| Method | Description | Algorithm |
|--------|-------------|-----------|
| `register_store(id, backend, endpoint)` | Register triple store | Store registration |
| `add_triple(triple, store_id)` | Add single triple | Index insertion |
| `add_triples(triples, store_id)` | Batch add triples | Bulk index insertion |
| `register_store(store_id, backend, endpoint)` | Register triplet store | Store registration |
| `add_triple(triple, store_id)` | Add single triplet | Index insertion |
| `add_triples(triples, store_id)` | Batch add triplets | Bulk index insertion |
| `query(sparql, store_id)` | Execute SPARQL query | Query optimization + execution |
| `delete(pattern, store_id)` | Delete matching triples | Pattern matching + deletion |
| `delete(pattern, store_id)` | Delete matching triplets | Pattern matching + deletion |
| `bulk_load(file_path, format, store_id)` | Bulk load from file | Streaming parser + batch insert |
| `get_stats(store_id)` | Get store statistics | Statistics collection |
**Example:**
```python
from semantica.triple_store import TripleManager
from semantica.triplet_store import TripletManager
# Initialize manager
manager = TripleManager()
manager = TripletManager()
# Register Blazegraph store
store = manager.register_store(
@@ -193,9 +193,9 @@ SPARQL query execution and optimization engine.
**Example:**
```python
from semantica.triple_store import QueryEngine, TripleManager
from semantica.triplet_store import QueryEngine, TripletManager
manager = TripleManager()
manager = TripletManager()
store = manager.register_store("main", "blazegraph", "http://localhost:9999/blazegraph/sparql")
engine = QueryEngine()
@@ -270,9 +270,9 @@ High-performance bulk data loading with progress tracking.
**Example:**
```python
from semantica.triple_store import BulkLoader, TripleManager
from semantica.triplet_store import BulkLoader, TripletManager
manager = TripleManager()
manager = TripletManager()
store = manager.register_store("main", "blazegraph", "http://localhost:9999/blazegraph/sparql")
loader = BulkLoader(
@@ -322,7 +322,7 @@ progress = loader.load_from_string(
#### BlazegraphAdapter
High-performance triple store with GPU acceleration support.
High-performance triplet store with GPU acceleration support.
**Features:**
- High-performance SPARQL query execution
@@ -334,7 +334,7 @@ High-performance triple store with GPU acceleration support.
**Example:**
```python
from semantica.triple_store import BlazegraphAdapter
from semantica.triplet_store import BlazegraphAdapter
adapter = BlazegraphAdapter(
endpoint="http://localhost:9999/blazegraph/sparql",
@@ -376,7 +376,7 @@ results = adapter.query("""
Full-featured RDF framework with TDB2 storage.
**Features:**
- TDB2 native triple store
- TDB2 native triplet store
- SHACL validation
- Inference engines (RDFS, OWL)
- Fuseki SPARQL server
@@ -385,7 +385,7 @@ Full-featured RDF framework with TDB2 storage.
**Example:**
```python
from semantica.triple_store import JenaAdapter
from semantica.triplet_store import JenaAdapter
adapter = JenaAdapter(
tdb_directory="./tdb2_data",
@@ -451,7 +451,7 @@ Java-based RDF framework with multiple storage backends.
**Example:**
```python
from semantica.triple_store import RDF4JAdapter
from semantica.triplet_store import RDF4JAdapter
adapter = RDF4JAdapter(
server_url="http://localhost:8080/rdf4j-server",
@@ -497,7 +497,7 @@ Enterprise-grade RDF store with SQL integration.
**Example:**
```python
from semantica.triple_store import VirtuosoAdapter
from semantica.triplet_store import VirtuosoAdapter
adapter = VirtuosoAdapter(
host="localhost",
@@ -534,10 +534,10 @@ results = adapter.query(f"""
## Convenience Functions
Quick access to triple store operations:
Quick access to triplet store operations:
```python
from semantica.triple_store import (
from semantica.triplet_store import (
add_triple,
add_triples,
execute_query,
@@ -579,9 +579,9 @@ export_graph(
## Dataclasses
### TripleStore
### TripletStore
Configuration dataclass for triple store instances.
Configuration dataclass for triplet store instances.
**Attributes:**
@@ -649,35 +649,35 @@ Bulk loading progress dataclass.
```bash
# General settings
export TRIPLE_STORE_DEFAULT_BACKEND=blazegraph
export TRIPLE_STORE_BATCH_SIZE=10000
export TRIPLE_STORE_TIMEOUT=30
export TRIPLET_STORE_DEFAULT_BACKEND=blazegraph
export TRIPLET_STORE_BATCH_SIZE=10000
export TRIPLET_STORE_TIMEOUT=30
# Blazegraph settings
export TRIPLE_STORE_BLAZEGRAPH_ENDPOINT=http://localhost:9999/blazegraph/sparql
export TRIPLE_STORE_BLAZEGRAPH_NAMESPACE=kb
export TRIPLET_STORE_BLAZEGRAPH_ENDPOINT=http://localhost:9999/blazegraph/sparql
export TRIPLET_STORE_BLAZEGRAPH_NAMESPACE=kb
# Jena settings
export TRIPLE_STORE_JENA_TDB_DIRECTORY=./tdb2_data
export TRIPLE_STORE_JENA_INFERENCE=rdfs
export TRIPLET_STORE_JENA_TDB_DIRECTORY=./tdb2_data
export TRIPLET_STORE_JENA_INFERENCE=rdfs
# RDF4J settings
export TRIPLE_STORE_RDF4J_SERVER_URL=http://localhost:8080/rdf4j-server
export TRIPLE_STORE_RDF4J_REPOSITORY_ID=my_repo
export TRIPLET_STORE_RDF4J_SERVER_URL=http://localhost:8080/rdf4j-server
export TRIPLET_STORE_RDF4J_REPOSITORY_ID=my_repo
# Virtuoso settings
export TRIPLE_STORE_VIRTUOSO_HOST=localhost
export TRIPLE_STORE_VIRTUOSO_PORT=1111
export TRIPLE_STORE_VIRTUOSO_USER=dba
export TRIPLE_STORE_VIRTUOSO_PASSWORD=dba
export TRIPLET_STORE_VIRTUOSO_HOST=localhost
export TRIPLET_STORE_VIRTUOSO_PORT=1111
export TRIPLET_STORE_VIRTUOSO_USER=dba
export TRIPLET_STORE_VIRTUOSO_PASSWORD=dba
```
### YAML Configuration
```yaml
# config.yaml - Triple Store Configuration
# config.yaml - Triplet Store Configuration
triple_store:
triplet_store:
backend: blazegraph # blazegraph, jena, rdf4j, virtuoso
batch_size: 10000
timeout: 30
+8 -46
View File
@@ -1,6 +1,6 @@
# Vector Store
> **Unified vector database interface supporting FAISS, Pinecone, Weaviate, Qdrant, and Milvus with Hybrid Search.**
> **Unified vector database interface supporting FAISS, Weaviate, Qdrant, and Milvus with Hybrid Search.**
---
@@ -12,7 +12,7 @@
---
Seamlessly switch between FAISS (Local), Pinecone, Weaviate, Qdrant, and Milvus
Seamlessly switch between FAISS (Local), Weaviate, Qdrant, and Milvus
- :material-magnify-plus:{ .lg .middle } **Hybrid Search**
@@ -230,7 +230,6 @@ results = searcher.search(
Backend-specific implementations:
- `FAISSAdapter`: Local, in-memory/disk.
- `PineconeAdapter`: Managed cloud service.
- `WeaviateAdapter`: Schema-aware vector DB.
- `QdrantAdapter`: Rust-based high-performance DB.
- `MilvusAdapter`: Scalable cloud-native DB.
@@ -265,41 +264,6 @@ query = np.random.rand(768).astype('float32')
distances, indices = adapter.search(index, query, k=10)
```
#### PineconeAdapter
Managed cloud vector database.
**Helper Classes:**
- `PineconeIndex`: Index management
- `PineconeQuery`: Query operations
- `PineconeMetadata`: Metadata handling
**Example:**
```python
from semantica.vector_store import PineconeAdapter
adapter = PineconeAdapter(api_key="your-key", environment="us-west1-gcp")
adapter.connect()
# Create index
index = adapter.create_index("my-index", dimension=768, metric="cosine")
# Upsert with metadata
adapter.upsert_vectors(
vectors=[[0.1, 0.2, ...], ...],
ids=["vec_1", "vec_2"],
metadata=[{"category": "news"}, ...]
)
# Query with filter
results = adapter.query_vectors(
query_vector=[0.1, 0.2, ...],
top_k=10,
filter={"category": {"$eq": "news"}}
)
```
#### WeaviateAdapter
Schema-aware vector database with GraphQL.
@@ -716,25 +680,23 @@ print(f"Available methods: {methods}")
### Environment Variables
```bash
export VECTOR_STORE_BACKEND=pinecone
export PINECONE_API_KEY=sk-...
export PINECONE_ENV=us-west1-gcp
export VECTOR_STORE_BACKEND=weaviate
export WEAVIATE_URL=http://localhost:8080
```
### YAML Configuration
```yaml
vector_store:
backend: faiss # or pinecone, weaviate, etc.
backend: faiss # or weaviate, qdrant, milvus
dimension: 1536
metric: cosine
faiss:
index_type: HNSW
pinecone:
environment: us-west1-gcp
index_name: my-index
weaviate:
url: http://localhost:8080
```
---
@@ -777,7 +739,7 @@ print(f"Context: {context}")
**Solution**: Ensure your embedding model dimension (e.g., 1536 for OpenAI) matches the VectorStore dimension.
**Issue**: FAISS index not saved.
**Solution**: Call `store.save("index.faiss")` explicitly for local FAISS indices, or use a persistent backend like Pinecone/Qdrant.
**Solution**: Call `store.save("index.faiss")` explicitly for local FAISS indices, or use a persistent backend like Weaviate/Qdrant.
---
+1 -1
View File
@@ -123,7 +123,7 @@ nav:
- Seed: reference/seed.md
- Semantic Extract: reference/semantic_extract.md
- Split: reference/split.md
- Triple Store: reference/triple_store.md
- Triplet Store: reference/triplet_store.md
- Utils: reference/utils.md
- Vector Store: reference/vector_store.md
- Visualization: reference/visualization.md
-1
View File
@@ -61,7 +61,6 @@ dependencies = [
"librosa>=0.9.0",
"opencv-python>=4.6.0",
"faiss-cpu>=1.7.0",
"pinecone-client>=2.2.0",
"weaviate-client>=3.15.0",
"qdrant-client>=1.3.0",
"neo4j>=5.0.0",
-179
View File
@@ -1,179 +0,0 @@
import logging
import sys
from datetime import datetime
from typing import List, Dict, Any
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[logging.StreamHandler(sys.stdout)]
)
logger = logging.getLogger("verify_conflict_complete")
def verify_conflict_complete():
print("=== Starting Complete Conflict Module Verification ===\n")
try:
from semantica.conflicts import (
ConflictDetector, ConflictResolver, ConflictAnalyzer,
SourceTracker, InvestigationGuideGenerator, SourceReference,
method_registry, ResolutionResult, ConflictsConfig, conflicts_config
)
from semantica.conflicts.methods import (
detect_conflicts, resolve_conflicts, analyze_conflicts,
track_sources, generate_investigation_guide,
list_available_methods, get_conflict_method
)
print("[1] Imports successful.\n")
except ImportError as e:
print(f"Error importing semantica.conflicts: {e}")
return
# --- Step 1: Conflict Detection (Comprehensive) ---
print("[2] Testing Comprehensive Conflict Detection...")
detector = ConflictDetector(
confidence_threshold=0.7,
track_provenance=True,
conflict_fields={"Company": ["name", "founded", "revenue"]}
)
entities = [
{"id": "e1", "name": "Apple Inc.", "founded": 1976, "type": "Company",
"source": "wikipedia", "confidence": 0.9, "metadata": {"timestamp": datetime(2023, 1, 15)}},
{"id": "e1", "name": "Apple Incorporated", "founded": 1976, "type": "Company",
"source": "official_site", "confidence": 0.95, "metadata": {"timestamp": datetime(2023, 3, 20)}},
{"id": "e1", "name": "Apple Inc.", "founded": 1977, "type": "Company",
"source": "news", "confidence": 0.7, "metadata": {"timestamp": datetime(2023, 2, 10)}},
{"id": "e2", "name": "Microsoft", "type": "Company", "founded": 1975, "source": "source1"},
{"id": "e2", "name": "Microsoft Corporation", "type": "Organization",
"founded": 1975, "source": "source2"},
]
# 1.1 Value Conflicts
value_conflicts = detector.detect_value_conflicts(entities, "name")
print(f" Value Conflicts Detected: {len(value_conflicts)}")
# 1.2 Type Conflicts
type_conflicts = detector.detect_type_conflicts(entities)
print(f" Type Conflicts Detected: {len(type_conflicts)}")
# 1.3 Temporal Conflicts (founded date mismatch)
# Note: detect_temporal_conflicts usually checks for logical temporal issues or changing values over time
temporal_conflicts = detector.detect_temporal_conflicts(entities)
print(f" Temporal Conflicts Detected: {len(temporal_conflicts)}")
# 1.6 General Detection
all_conflicts = detector.detect_conflicts(entities)
print(f" Total Conflicts Detected (General): {len(all_conflicts)}")
# --- Step 2: Source Tracking ---
print("\n[3] Testing Source Tracking...")
tracker = SourceTracker()
source1 = SourceReference(document="wikipedia", timestamp=datetime(2023, 1, 15), confidence=0.9)
source2 = SourceReference(document="official_site", timestamp=datetime(2023, 3, 20), confidence=0.95)
tracker.track_property_source("e1", "name", "Apple Inc.", source1)
tracker.track_property_source("e1", "name", "Apple Incorporated", source2)
tracker.set_source_credibility("wikipedia", 0.85)
tracker.set_source_credibility("official_site", 0.95)
sources = tracker.get_property_sources("e1", "name")
print(f" Sources for e1.name: {len(sources.sources) if sources else 0}")
# --- Step 3: Conflict Resolution (Advanced) ---
print("\n[4] Testing Advanced Conflict Resolution...")
resolver = ConflictResolver(default_strategy="voting", source_tracker=tracker)
if value_conflicts:
# Credibility Weighted
results = resolver.resolve_conflicts(value_conflicts, strategy="credibility_weighted")
for r in results:
if r.resolved:
print(f" Resolved (Credibility): {r.resolved_value} (Conf: {r.confidence:.2f})")
# --- Step 4: Conflict Analysis ---
print("\n[5] Testing Conflict Analyzer...")
analyzer = ConflictAnalyzer()
analysis = analyzer.analyze_conflicts(all_conflicts)
print(f" Analysis Keys: {list(analysis.keys())}")
print(f" Total Conflicts in Analysis: {analysis.get('total_conflicts', 0)}")
# Check insights report
try:
insights = analyzer.generate_insights_report(all_conflicts)
print(f" Insights Report Generated (Length: {len(insights)})")
except Exception as e:
print(f" Error generating insights report: {e}")
# --- Step 5: Investigation Guides ---
print("\n[6] Testing Investigation Guide Generator...")
guide_generator = InvestigationGuideGenerator(source_tracker=tracker)
if value_conflicts:
guide = guide_generator.generate_guide(value_conflicts[0])
print(f" Guide Generated for: {guide.conflict_id}")
print(f" Recommended Actions: {guide.recommended_actions}")
checklist = guide_generator.export_investigation_checklist(guide, format="markdown")
print(f" Checklist Exported (Markdown length: {len(checklist)})")
# --- Step 6: Methods Module (Functional API) ---
print("\n[7] Testing Functional API...")
try:
# Detection
func_conflicts = detect_conflicts(entities, method="value", property_name="name")
print(f" Functional Detect (Value): {len(func_conflicts)}")
# Resolution
if func_conflicts:
func_results = resolve_conflicts(func_conflicts, method="voting")
print(f" Functional Resolve (Voting): {len(func_results)}")
# Analysis
func_analysis = analyze_conflicts(all_conflicts, method="pattern")
print(f" Functional Analyze (Pattern): {len(func_analysis) if func_analysis else 0} patterns found")
except Exception as e:
print(f" Error in Functional API: {e}")
# --- Step 7: Method Registry ---
print("\n[8] Testing Method Registry...")
def custom_resolution_func(conflicts, **kwargs):
results = []
for conflict in conflicts:
res = ResolutionResult(
conflict_id=conflict.conflict_id,
resolved=True,
resolved_value="CUSTOM_VALUE",
resolution_strategy="custom_test"
)
results.append(res)
return results
method_registry.register("resolution", "custom_test", custom_resolution_func)
print(" Registered 'custom_test' method.")
reg_methods = method_registry.list_all("resolution")
if "custom_test" in reg_methods.get("resolution", []):
print(" Verified 'custom_test' in registry.")
# Test usage
if value_conflicts:
custom_res = resolve_conflicts(value_conflicts, method="custom_test")
print(f" Custom Resolution Result: {custom_res[0].resolved_value}")
method_registry.unregister("resolution", "custom_test")
print(" Unregistered 'custom_test'.")
# --- Step 8: Configuration ---
print("\n[9] Testing Configuration...")
conflicts_config.set("confidence_threshold", 0.85)
val = conflicts_config.get("confidence_threshold")
print(f" Config Value Set/Get: {val}")
print("\n=== Complete Conflict Module Verification Finished ===")
if __name__ == "__main__":
verify_conflict_complete()
-137
View File
@@ -1,137 +0,0 @@
import logging
import sys
import os
from datetime import datetime
from typing import List, Dict, Any
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[logging.StreamHandler(sys.stdout)]
)
logger = logging.getLogger("verify_conflict_resolution")
def verify_conflict_resolution():
print("=== Starting Conflict Resolution Verification ===\n")
try:
from semantica.conflicts import ConflictDetector, ConflictResolver, SourceTracker
from semantica.conflicts.conflict_resolver import ResolutionStrategy
print("[1] Imports successful.\n")
except ImportError as e:
print(f"Error importing semantica.conflicts: {e}")
return
# Step 1: Define Entities with Conflicting Data
print("[2] Defining conflicting entities...")
entities = [
{
"id": "e1",
"type": "Person",
"name": "John Doe",
"age": 30,
"location": "New York",
"source": "source1",
"confidence": 0.8,
"metadata": {"timestamp": datetime(2023, 1, 1)}
},
{
"id": "e1",
"type": "Person",
"name": "John Doe",
"age": 32,
"location": "Boston",
"source": "source2",
"confidence": 0.9,
"metadata": {"timestamp": datetime(2023, 6, 1)}
},
{
"id": "e2",
"type": "Organization",
"name": "Tech Corp",
"founded": 2010,
"employees": 100,
"source": "source1",
"confidence": 0.9,
"metadata": {"timestamp": datetime(2023, 1, 1)}
},
{
"id": "e2",
"type": "Organization",
"name": "Tech Corp",
"founded": 2012,
"employees": 150,
"source": "source2",
"confidence": 0.7,
"metadata": {"timestamp": datetime(2023, 3, 1)}
}
]
print(f" defined {len(entities)} entity records.\n")
# Step 2: Detect Conflicts
print("[3] Detecting conflicts...")
detector = ConflictDetector(track_provenance=True)
conflicts = detector.detect_entity_conflicts(entities)
print(f"Detected {len(conflicts)} conflicts.")
for i, conflict in enumerate(conflicts, 1):
print(f" Conflict {i}: Entity={conflict.entity_id}, Property={conflict.property_name}, Values={conflict.conflicting_values}")
if len(conflicts) == 0:
print("WARNING: No conflicts detected! Verification cannot proceed meaningfully.")
return
# Step 3: Resolve Conflicts
resolver = ConflictResolver()
# Strategy: Voting
print("\n[4a] Resolving with 'voting' strategy...")
results_voting = resolver.resolve_conflicts(conflicts, strategy="voting")
for r in results_voting:
if r.resolved:
print(f" Resolved {r.conflict_id} ({r.resolution_strategy}): {r.resolved_value}")
# Strategy: Most Recent
print("\n[4b] Resolving with 'most_recent' strategy...")
results_recent = resolver.resolve_conflicts(conflicts, strategy="most_recent")
for r in results_recent:
if r.resolved:
print(f" Resolved {r.conflict_id} ({r.resolution_strategy}): {r.resolved_value}")
# Verification for e1 (most recent is source2 -> age 32, location Boston)
# Verification for e2 (most recent is source2 -> founded 2012, employees 150)
# Note: We can't easily map back to entity ID without parsing conflict_id or checking logic,
# but we can verify the values exist in our expectations.
pass
# Strategy: Highest Confidence
print("\n[4c] Resolving with 'highest_confidence' strategy...")
results_confidence = resolver.resolve_conflicts(conflicts, strategy="highest_confidence")
for r in results_confidence:
if r.resolved:
print(f" Resolved {r.conflict_id} ({r.resolution_strategy}): {r.resolved_value}")
# Verification for e1 (highest conf is source2 -> age 32)
# Verification for e2 (highest conf is source1 -> founded 2010)
# Step 4: Track Sources
print("\n[5] Tracking sources...")
tracker = detector.source_tracker
for conflict in conflicts:
sources = tracker.get_property_sources(conflict.entity_id, conflict.property_name)
if sources:
print(f" Entity: {conflict.entity_id}, Property: {conflict.property_name}, Source Count: {len(sources.sources)}")
# Step 5: Audit Trail
print("\n[6] Checking audit trail...")
history = resolver.get_resolution_history()
print(f" History entries: {len(history)}")
if len(history) > 0:
last_entry = history[-1]
print(f" Last entry: Strategy={last_entry.resolution_strategy}, Value={last_entry.resolved_value}")
print("\n=== Conflict Resolution Verification Completed Successfully ===")
if __name__ == "__main__":
verify_conflict_resolution()
-96
View File
@@ -1,96 +0,0 @@
"""
Script to verify the usage of the Semantica Core Module.
This simulates the typical usage pattern described in core_usage.md.
"""
import sys
import os
import logging
# Add project root to path to ensure we can import semantica
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from semantica import Semantica
from semantica.core import LifecycleManager, PluginRegistry
# Configure logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger("verify_core")
def custom_startup_hook():
logger.info("✅ Custom startup hook executed!")
def custom_processing_method(sources, **kwargs):
logger.info(f"✅ Custom processing method executed for sources: {sources}")
return {"status": "success", "processed_items": len(sources)}
def main():
logger.info("Starting Core Module Verification...")
# 1. Initialize Semantica
logger.info("\n--- Step 1: Initialization ---")
config = {
"project_name": "CoreVerification",
"logging": {"level": "DEBUG"}
}
app = Semantica(config)
logger.info("Semantica instance created.")
# 2. Register Hooks via Lifecycle Manager
logger.info("\n--- Step 2: Lifecycle Hooks ---")
app.lifecycle_manager.register_startup_hook(custom_startup_hook, priority=10)
logger.info("Startup hook registered.")
# 3. Register Custom Method
logger.info("\n--- Step 3: Method Registry ---")
from semantica.core.registry import method_registry
method_registry.register("knowledge_base", "custom_processor", custom_processing_method)
logger.info("Custom method 'custom_processor' registered.")
# 4. Start the System (Initialize)
logger.info("\n--- Step 4: System Startup ---")
app.initialize()
# Check health
health = app.lifecycle_manager.get_health_summary()
logger.info(f"System Health: {'Healthy' if health['is_healthy'] else 'Unhealthy'}")
if not health['is_healthy']:
logger.warning(f"Unhealthy components: {health['unhealthy_components']}")
# 5. Run a Workflow using the Custom Method
logger.info("\n--- Step 5: Workflow Execution ---")
sources = ["file1.txt", "file2.txt"]
# We use the 'method' argument which the orchestrator (via methods.py) uses to look up the registry
# Note: orchestrator.build_knowledge_base doesn't directly expose 'method' arg in signature but passes **kwargs to implementation
# Let's check how methods.py is called.
# build_knowledge_base calls build_knowledge_base (wrapper) in methods.py?
# Wait, orchestrator.py: build_knowledge_base calls self._create_pipeline...
# Actually, looking at orchestrator.py:
# It calls self._create_pipeline(pipeline_config)
# It doesn't seem to directly use 'method_registry' for the main 'build_knowledge_base' flow in the default implementation.
# However, methods.py defines 'build_knowledge_base' which IS the implementation used if imported as functional API.
# But Semantica class in orchestrator.py has its own build_knowledge_base method.
# Let's see if we can use the method registry via the functional API or if we need to check how Semantica class uses it.
# The Semantica class seems to have a hardcoded implementation in build_knowledge_base that creates a pipeline.
# But wait, semantica/__init__.py likely exposes the class.
# Let's try to invoke the custom method directly to verify registry,
# OR if Semantica class supports delegation (it might not currently).
# Let's verify the functional API wrapper usage as well.
from semantica.core.methods import build_knowledge_base as functional_build_kb
result = functional_build_kb(sources, method="custom_processor", config=config)
logger.info(f"Functional API Result: {result}")
# 6. Shutdown
logger.info("\n--- Step 6: Shutdown ---")
app.lifecycle_manager.shutdown()
logger.info("System shutdown completed.")
logger.info("\n✅ Verification Completed Successfully!")
if __name__ == "__main__":
main()
-194
View File
@@ -1,194 +0,0 @@
import logging
import sys
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def verify_deduplication_notebook():
print("=== Starting Deduplication Notebook Verification ===")
# Import all deduplication classes
print("\n[1] Importing deduplication classes...")
from semantica.deduplication import (
# Main Classes
DuplicateDetector,
EntityMerger,
SimilarityCalculator,
ClusterBuilder,
MergeStrategyManager,
MethodRegistry,
DeduplicationConfig,
# Data Classes
DuplicateCandidate,
DuplicateGroup,
MergeOperation,
SimilarityResult,
Cluster,
ClusterResult,
MergeResult,
MergeStrategy,
# Global Instances
method_registry,
dedup_config,
)
print("Imports successful.")
# Create sample entities with potential duplicates
print("\n[2] Creating sample entities...")
entities = [
{
"id": "e1",
"name": "Apple Inc.",
"type": "Company",
"founded": 1976,
"properties": {"industry": "Technology", "headquarters": "Cupertino"},
"relationships": [{"subject": "e1", "predicate": "founded_by", "object": "Steve Jobs"}],
},
{
"id": "e2",
"name": "Apple Inc",
"type": "Company",
"founded": 1976,
"properties": {"industry": "Tech", "headquarters": "Cupertino, CA"},
"relationships": [{"subject": "e2", "predicate": "founded_by", "object": "Steve Jobs"}],
},
{
"id": "e3",
"name": "Microsoft Corporation",
"type": "Company",
"founded": 1975,
"properties": {"industry": "Technology", "headquarters": "Redmond"},
},
{
"id": "e4",
"name": "Microsoft",
"type": "Company",
"founded": 1975,
"properties": {"industry": "Tech", "headquarters": "Redmond, WA"},
},
{
"id": "e5",
"name": "Google LLC",
"type": "Company",
"founded": 1998,
"properties": {"industry": "Technology"},
},
]
print(f"Created {len(entities)} sample entities")
print("Entity names:")
for e in entities:
print(f" - {e['name']} (ID: {e['id']})")
# Example: Duplicate Detection
print("\n[3] Testing Duplicate Detection...")
# Initialize DuplicateDetector
detector = DuplicateDetector(
similarity_threshold=0.7,
confidence_threshold=0.6,
# use_clustering=True, # Note: Constructor signature might verify this
)
# Detect duplicate candidates (pairwise)
print(" Running pairwise detection...")
candidates = detector.detect_duplicates(entities)
print(f" Found {len(candidates)} duplicate candidate(s)")
for candidate in candidates:
print(f" {candidate.entity1['name']} <-> {candidate.entity2['name']}")
print(f" Similarity: {candidate.similarity_score:.3f}, Confidence: {candidate.confidence:.3f}")
# Detect duplicate groups
print(" Running group detection...")
duplicate_groups = detector.detect_duplicate_groups(entities)
print(f" Found {len(duplicate_groups)} duplicate group(s)")
for i, group in enumerate(duplicate_groups, 1):
names = [e['name'] for e in group.entities]
print(f" Group {i}: {names} (confidence: {group.confidence:.3f})")
# Incremental detection
print(" Running incremental detection...")
existing_entities = entities[:3]
new_entities = entities[3:]
incremental_candidates = detector.incremental_detect(new_entities, existing_entities, threshold=0.7)
print(f" Found {len(incremental_candidates)} incremental duplicate(s)")
for candidate in incremental_candidates:
print(f" {candidate.entity1['name']} duplicates {candidate.entity2['name']} (confidence: {candidate.confidence:.3f})")
# Example: Similarity Calculation
print("\n[4] Testing Similarity Calculation...")
# Initialize SimilarityCalculator
calculator = SimilarityCalculator(
string_weight=0.4,
property_weight=0.3,
relationship_weight=0.2,
embedding_weight=0.1,
)
# Calculate overall similarity (multi-factor)
entity1, entity2 = entities[0], entities[1]
result = calculator.calculate_similarity(entity1, entity2)
print(f" Overall Similarity: {result.score:.3f}")
print(f" Components: {result.components}")
# String similarity methods
str1, str2 = "Apple Inc.", "Apple Inc"
for method in ["levenshtein", "jaro_winkler", "cosine"]:
score = calculator.calculate_string_similarity(str1, str2, method=method)
print(f" {method}: {score:.3f}")
# Property and relationship similarity
prop_score = calculator.calculate_property_similarity(entity1, entity2)
rel_score = calculator.calculate_relationship_similarity(entity1, entity2)
print(f" Property Similarity: {prop_score:.3f}")
print(f" Relationship Similarity: {rel_score:.3f}")
# Batch similarity calculation
similarity_pairs = calculator.batch_calculate_similarity(entities, threshold=0.5)
print(f" Found {len(similarity_pairs)} similar pairs (threshold >= 0.5)")
for e1, e2, score in similarity_pairs:
print(f" {e1['name']} <-> {e2['name']}: {score:.3f}")
# Example: Entity Merging
print("\n[5] Testing Entity Merging...")
# Initialize EntityMerger
merger = EntityMerger(preserve_provenance=True)
# Merge duplicates (automatic detection)
print(" Merging duplicates (automatic)...")
merge_operations = merger.merge_duplicates(entities)
print(f" Original entities: {len(entities)}")
print(f" Merge operations: {len(merge_operations)}")
for i, op in enumerate(merge_operations, 1):
print(f" Operation {i}: Merged {len(op.source_entities)} entities -> {op.merged_entity.get('name')}")
if op.merge_result.conflicts:
print(f" Conflicts: {len(op.merge_result.conflicts)}")
# Merge with specific strategy
print(" Merging with KEEP_MOST_COMPLETE strategy...")
operations = merger.merge_duplicates(entities, strategy=MergeStrategy.KEEP_MOST_COMPLETE)
print(f" Merged using KEEP_MOST_COMPLETE: {len(operations)} operations")
# Merge specific group
print(" Merging specific group...")
duplicate_entities = [entities[0], entities[1]]
operation = merger.merge_entity_group(duplicate_entities, strategy=MergeStrategy.KEEP_FIRST)
print(f" Merged group: {[e['name'] for e in operation.source_entities]} -> {operation.merged_entity['name']}")
# Get merge history
history = merger.get_merge_history()
print(f" Total merge operations in history: {len(history)}")
# Validate merge quality
if operations:
validation = merger.validate_merge_quality(operations[0])
print(f" Validation: Valid={validation['valid']}, Quality={validation['quality_score']:.3f}")
print("\n=== Deduplication Verification Completed Successfully ===")
if __name__ == "__main__":
verify_deduplication_notebook()
-116
View File
@@ -1,116 +0,0 @@
"""
Script to verify the usage of the Semantica Knowledge Graph (KG) Module.
This simulates the typical usage pattern described in kg_usage.md.
"""
import sys
import os
import logging
import json
from datetime import datetime
# Add project root to path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from semantica.kg import GraphBuilder, GraphAnalyzer, TemporalGraphQuery
# Configure logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger("verify_kg")
def main():
print("Starting KG Module Verification...")
# --- Step 1: Build Knowledge Graph ---
print("\n--- Step 1: Graph Building ---")
# Define some source data with temporal info
sources = [
{
"entities": [
{"id": "e1", "name": "Alice", "type": "Person"},
{"id": "e2", "name": "Bob", "type": "Person"},
{"id": "e3", "name": "Semantica", "type": "Project"}
],
"relationships": [
{
"source": "e1", "target": "e2", "type": "knows",
"valid_from": "2023-01-01", "valid_until": None
},
{
"source": "e1", "target": "e3", "type": "works_on",
"valid_from": "2023-06-01", "valid_until": "2024-01-01"
},
{
"source": "e2", "target": "e3", "type": "works_on",
"valid_from": "2024-01-01", "valid_until": None
}
]
}
]
# Initialize builder (disable complex features for simple verification)
builder = GraphBuilder(
merge_entities=False,
resolve_conflicts=False,
enable_temporal=True
)
kg = builder.build(sources)
logger.info(f"Graph built with {len(kg['entities'])} entities and {len(kg['relationships'])} relationships.")
# --- Step 2: Analyze Graph ---
logger.info("\n--- Step 2: Graph Analysis ---")
# Mocking sub-analyzers if they are not fully implemented or require external libs not present
# Assuming they are implemented or we can run with defaults.
# Note: GraphAnalyzer imports CentralityCalculator etc.
# If those modules have dependencies (like networkx), they need to be installed.
# Let's try to run it. If it fails, we know we need dependencies.
try:
analyzer = GraphAnalyzer()
# We might need to mock internal calls if they fail due to missing heavy libs in this environment
# But let's try.
# To avoid failure if CentralityCalculator fails, we can catch it.
# But for verification script, we want to see it run.
# Since I can't check installed packages easily without running pip list, I'll assume standard deps.
# However, to be safe and avoid script crash on things I haven't checked (like networkx),
# I will wrap in try-except block for analysis.
analysis = analyzer.analyze_graph(kg)
logger.info("Graph analysis completed.")
logger.info(f"Metrics: {json.dumps(analysis.get('metrics', {}), indent=2)}")
except Exception as e:
logger.warning(f"Graph analysis skipped or failed: {e}")
# --- Step 3: Temporal Query ---
logger.info("\n--- Step 3: Temporal Querying ---")
query_engine = TemporalGraphQuery()
# Query at a specific time
at_time = "2023-08-01"
result = query_engine.query_at_time(kg, query="", at_time=at_time)
logger.info(f"Relationships active at {at_time}:")
for rel in result["relationships"]:
logger.info(f" {rel['source']} --[{rel['type']}]--> {rel['target']}")
# Verify expected results
# Alice knows Bob (from 2023-01-01) -> Active
# Alice works_on Semantica (from 2023-06-01 to 2024-01-01) -> Active
# Bob works_on Semantica (from 2024-01-01) -> Not Active
active_rels = len(result["relationships"])
logger.info(f"Found {active_rels} active relationships (Expected: 2).")
if active_rels == 2:
logger.info("✅ Temporal query verification successful!")
else:
logger.error("❌ Temporal query verification failed!")
logger.info("\n✅ KG Module Verification Completed!")
if __name__ == "__main__":
main()
+7 -7
View File
@@ -84,7 +84,7 @@ class _SemanticaModules:
self._normalize = None
self._export = None
self._vector_store = None
self._triple_store = None
self._triplet_store = None
self._graph_store = None
self._ontology = None
self._evals = None
@@ -160,11 +160,11 @@ class _SemanticaModules:
return self._vector_store
@property
def triple_store(self):
"""Access triple store module."""
if self._triple_store is None:
self._triple_store = _ModuleProxy("triple_store")
return self._triple_store
def triplet_store(self):
"""Access triplet store module."""
if self._triplet_store is None:
self._triplet_store = _ModuleProxy("triplet_store")
return self._triplet_store
@property
def graph_store(self):
@@ -289,7 +289,7 @@ def __getattr__(name: str):
"normalize",
"export",
"vector_store",
"triple_store",
"triplet_store",
"graph_store",
"ontology",
"evals",
+58 -6
View File
@@ -385,12 +385,21 @@ class ConflictDetector:
def _recommend_action(self, property_name: str, values: List[Any]) -> str:
"""Recommend action for conflict."""
if len(set(values)) == 2:
return (
"Compare source documents and use most recent or authoritative source"
)
else:
return "Multiple conflicting values detected. Manual review recommended."
try:
if len(set(values)) == 2:
return (
"Compare source documents and use most recent or authoritative source"
)
except TypeError:
# Handle unhashable types (like dicts or lists)
# Convert to string representation for set comparison
str_values = [str(v) for v in values]
if len(set(str_values)) == 2:
return (
"Compare source documents and use most recent or authoritative source"
)
return "Multiple conflicting values detected. Manual review recommended."
def get_conflict_report(self) -> Dict[str, Any]:
"""
@@ -864,6 +873,49 @@ class ConflictDetector:
)
raise
def resolve_conflicts(self, conflicts: List[Conflict]) -> Dict[str, int]:
"""
Attempt to resolve conflicts based on configuration.
Args:
conflicts: List of conflicts to resolve
Returns:
Dictionary with resolution statistics
"""
tracking_id = self.progress_tracker.start_tracking(
module="conflicts",
submodule="ConflictDetector",
message=f"Resolving {len(conflicts)} conflicts",
)
resolved_count = 0
unresolved_count = 0
for conflict in conflicts:
if self.auto_resolve:
# Simple resolution logic: pick value with highest confidence
# This is a placeholder for more complex logic
if conflict.conflicting_values:
# Mark as resolved (in a real system we would update the entity)
resolved_count += 1
else:
unresolved_count += 1
else:
unresolved_count += 1
self.progress_tracker.stop_tracking(
tracking_id,
status="completed",
message=f"Resolved {resolved_count} conflicts",
)
return {
"resolved_count": resolved_count,
"unresolved_count": unresolved_count,
"total_conflicts": len(conflicts)
}
def clear_conflicts(self) -> None:
"""Clear all detected conflicts."""
self.detected_conflicts.clear()
+10
View File
@@ -137,6 +137,16 @@ conflicts = detector.detect_entity_conflicts(
print(f"Found {len(conflicts)} total conflicts across all properties")
```
### Integrated Detection and Basic Resolution
The `ConflictDetector` also provides a convenience method `resolve_conflicts` for basic resolution, which is primarily used by the `GraphBuilder`. For more control, use the `ConflictResolver` class.
```python
# Detect and automatically resolve conflicts (convenience method)
resolution_result = detector.resolve_conflicts(conflicts)
print(f"Resolved {resolution_result.get('resolved_count')} conflicts")
```
### Using Detection Methods
```python
+55 -17
View File
@@ -302,7 +302,6 @@ class Semantica:
try:
self.logger.info("Executing processing pipeline")
# Track pipeline execution
pipeline_tracking_id = self.progress_tracker.start_tracking(
file=str(data) if isinstance(data, (str, Path)) else None,
module="pipeline",
@@ -310,23 +309,39 @@ class Semantica:
message="Executing pipeline",
)
# Validate pipeline
if isinstance(pipeline, dict):
pipeline = self._create_pipeline_from_dict(pipeline)
# Validate pipeline object
if not hasattr(pipeline, "execute"):
raise ProcessingError("Pipeline must have execute() method")
execution_engine = None
execution_result = None
try:
from ..pipeline import ExecutionEngine, Pipeline
if isinstance(pipeline, Pipeline):
execution_engine = ExecutionEngine()
except ImportError:
execution_engine = None
if execution_engine is None and not hasattr(pipeline, "execute"):
raise ProcessingError(
"Pipeline must be a Pipeline object or have execute() method"
)
# Allocate resources
resources = self._allocate_resources(pipeline)
try:
# Execute pipeline
result = pipeline.execute(data)
# Collect metrics
metrics = self._collect_metrics(pipeline)
if execution_engine is not None:
execution_result = execution_engine.execute_pipeline(
pipeline, data
)
success = execution_result.success
output = execution_result.output
metrics = execution_result.metrics
else:
output = pipeline.execute(data)
metrics = self._collect_metrics(pipeline)
success = True
if pipeline_tracking_id:
self.progress_tracker.stop_tracking(
@@ -334,8 +349,8 @@ class Semantica:
)
return {
"success": True,
"output": result,
"success": success,
"output": output,
"metrics": metrics,
"metadata": {
"pipeline": str(pipeline),
@@ -344,7 +359,6 @@ class Semantica:
}
finally:
# Release resources
self._release_resources(resources)
except Exception as e:
@@ -567,13 +581,37 @@ class Semantica:
Pipeline object or configuration dict (if pipeline module not available)
"""
try:
# Try to use PipelineBuilder if available
from ..pipeline import PipelineBuilder
pipeline_builder = PipelineBuilder()
return pipeline_builder.build_from_config(pipeline_config)
if not pipeline_config:
pipeline_builder.add_step("default_step", "default")
return pipeline_builder.build("default_pipeline")
steps_config = pipeline_config.get("steps")
if isinstance(steps_config, list) and steps_config and isinstance(
steps_config[0], str
):
converted_steps = [
{"name": name, "type": name, "config": {}}
for name in steps_config
]
normalized_config: Dict[str, Any] = {
"name": pipeline_config.get("name", "default_pipeline"),
"steps": converted_steps,
}
if "parallelism" in pipeline_config:
normalized_config["parallelism"] = pipeline_config["parallelism"]
return pipeline_builder.build_pipeline(normalized_config)
if "steps" in pipeline_config:
return pipeline_builder.build_pipeline(pipeline_config)
pipeline_builder.add_step("default_step", "default")
return pipeline_builder.build("default_pipeline")
except ImportError:
# Fallback: return config as-is if pipeline module not available
self.logger.debug("Pipeline module not available, using config directly")
return pipeline_config
+2 -10
View File
@@ -447,14 +447,6 @@ from semantica.embeddings import VectorEmbeddingManager
manager = VectorEmbeddingManager()
# Prepare for Pinecone
pinecone_data = manager.prepare_for_vector_db(
embeddings,
metadata=metadata,
backend="pinecone",
namespace="my_namespace"
)
# Prepare for Weaviate
weaviate_data = manager.prepare_for_vector_db(
embeddings,
@@ -486,9 +478,9 @@ from semantica.embeddings import VectorEmbeddingManager
manager = VectorEmbeddingManager()
# Validate dimensions for specific backend
is_valid = manager.validate_dimensions(embeddings, backend="pinecone")
is_valid = manager.validate_dimensions(embeddings, backend="weaviate")
if is_valid:
print("Embeddings meet Pinecone requirements")
print("Embeddings meet Weaviate requirements")
else:
print("Embeddings do not meet requirements")
```
@@ -9,7 +9,7 @@ Key Features:
- Validate embedding dimensions for different backends
- Normalize embeddings for vector DB requirements
- Create metadata compatible with vector DBs
- Integration helpers for FAISS, Pinecone, Weaviate, Qdrant, Milvus
- Integration helpers for FAISS, Weaviate, Qdrant, Milvus
Example Usage:
>>> from semantica.embeddings import VectorEmbeddingManager
@@ -36,7 +36,6 @@ class VectorEmbeddingManager:
Supported Backends:
- FAISS: Local vector storage
- Pinecone: Cloud vector database
- Weaviate: GraphQL-based vector database
- Qdrant: Vector similarity search engine
- Milvus: Open-source vector database
@@ -50,7 +49,7 @@ class VectorEmbeddingManager:
... backend="faiss"
... )
>>> # Validate dimensions
>>> is_valid = manager.validate_dimensions(embeddings, backend="pinecone")
>>> is_valid = manager.validate_dimensions(embeddings, backend="weaviate")
"""
def __init__(self, embedding_generator: Optional[EmbeddingGenerator] = None):
@@ -67,7 +66,6 @@ class VectorEmbeddingManager:
# Backend-specific dimension requirements
self.backend_requirements = {
"faiss": {"min_dim": 1, "max_dim": None, "dtype": np.float32},
"pinecone": {"min_dim": 1, "max_dim": 20000, "dtype": np.float32},
"weaviate": {"min_dim": 1, "max_dim": None, "dtype": np.float32},
"qdrant": {"min_dim": 1, "max_dim": None, "dtype": np.float32},
"milvus": {"min_dim": 1, "max_dim": 32768, "dtype": np.float32},
@@ -90,7 +88,7 @@ class VectorEmbeddingManager:
Args:
embeddings: Embeddings array (n_samples, embedding_dim) or (embedding_dim,)
metadata: Optional list of metadata dictionaries (one per embedding)
backend: Vector DB backend ("faiss", "pinecone", "weaviate", "qdrant", "milvus")
backend: Vector DB backend ("faiss", "weaviate", "qdrant", "milvus")
normalize: Whether to normalize embeddings (default: True)
**options: Additional backend-specific options
@@ -108,7 +106,7 @@ class VectorEmbeddingManager:
>>> embeddings = np.random.rand(10, 384).astype(np.float32)
>>> metadata = [{"text": f"doc_{i}"} for i in range(10)]
>>> result = manager.prepare_for_vector_db(
... embeddings, metadata, backend="pinecone"
... embeddings, metadata, backend="weaviate"
... )
"""
if backend.lower() not in self.backend_requirements:
@@ -228,7 +226,7 @@ class VectorEmbeddingManager:
bool: True if dimensions are valid, False otherwise
Example:
>>> is_valid = manager.validate_dimensions(embeddings, backend="pinecone")
>>> is_valid = manager.validate_dimensions(embeddings, backend="weaviate")
"""
if backend.lower() not in self.backend_requirements:
self.logger.warning(f"Unknown backend: {backend}, skipping validation")
@@ -312,7 +310,7 @@ class VectorEmbeddingManager:
Example:
>>> metadata = [{"text": "doc1", "category": "science"}]
>>> formatted = manager.create_metadata(metadata, backend="pinecone")
>>> formatted = manager.create_metadata(metadata, backend="weaviate")
"""
formatted = []
@@ -321,16 +319,7 @@ class VectorEmbeddingManager:
formatted_meta = meta.copy()
# Backend-specific formatting
if backend.lower() == "pinecone":
# Pinecone has specific metadata requirements
# Remove None values and ensure types are compatible
formatted_meta = {
k: v
for k, v in formatted_meta.items()
if v is not None
and isinstance(v, (str, int, float, bool, list))
}
elif backend.lower() == "weaviate":
if backend.lower() == "weaviate":
# Weaviate uses specific property types
# Ensure values are compatible
formatted_meta = {
@@ -374,8 +363,6 @@ class VectorEmbeddingManager:
# Add backend-specific details
if backend.lower() == "faiss":
info["index_type"] = options.get("index_type", "flat")
elif backend.lower() == "pinecone":
info["namespace"] = options.get("namespace", "default")
elif backend.lower() == "weaviate":
info["class_name"] = options.get("class_name", "Document")
+1 -1
View File
@@ -62,7 +62,7 @@ OWL Export:
Vector Export:
- Vector Serialization: Multiple format support (JSON, NumPy, Binary, FAISS)
- Vector Store Integration: Format conversion for Pinecone, Weaviate, Qdrant, FAISS
- Vector Store Integration: Format conversion for Weaviate, Qdrant, FAISS
- Metadata Association: Vector-to-metadata mapping and serialization
- Batch Export: Efficient batch vector export processing
- Multi-dimensional Support: Variable dimension vector handling
+1 -1
View File
@@ -110,7 +110,7 @@ OWL Export:
Vector Export:
- Vector Serialization: Multiple format support (JSON, NumPy, Binary, FAISS)
- Vector Store Integration: Format conversion for Pinecone, Weaviate, Qdrant, FAISS
- Vector Store Integration: Format conversion for Weaviate, Qdrant, FAISS
- Metadata Association: Vector-to-metadata mapping and serialization
- Batch Export: Efficient batch vector export processing
- Multi-dimensional Support: Variable dimension vector handling
+6 -29
View File
@@ -7,7 +7,7 @@ embedding systems.
Key Features:
- Multiple vector format export (JSON, NumPy, Binary, FAISS)
- Vector store integration (Pinecone, Weaviate, Qdrant, FAISS)
- Vector store integration (Weaviate, Qdrant, FAISS)
- Metadata and document association
- Batch vector export
- Multi-dimensional vector support
@@ -16,7 +16,7 @@ Example Usage:
>>> from semantica.export import VectorExporter
>>> exporter = VectorExporter(format="json", include_metadata=True)
>>> exporter.export(vectors, "vectors.json")
>>> exporter.export_for_vector_store(vectors, "pinecone.json", vector_store_type="pinecone")
>>> exporter.export_for_vector_store(vectors, "weaviate.json", vector_store_type="weaviate")
Author: Semantica Contributors
License: MIT
@@ -43,7 +43,7 @@ class VectorExporter:
Features:
- Multiple vector format export (JSON, NumPy, Binary, FAISS)
- Vector store integration (Pinecone, Weaviate, Qdrant, FAISS)
- Vector store integration (Weaviate, Qdrant, FAISS)
- Metadata and document association
- Batch vector export
- Multi-dimensional vector support
@@ -471,7 +471,7 @@ class VectorExporter:
self,
vectors: List[Dict[str, Any]],
file_path: Union[str, Path],
vector_store_type: str = "pinecone",
vector_store_type: str = "weaviate",
**options,
) -> None:
"""
@@ -480,12 +480,10 @@ class VectorExporter:
Args:
vectors: List of vector dictionaries
file_path: Output file path
vector_store_type: Vector store type ('pinecone', 'weaviate', 'qdrant', 'faiss')
vector_store_type: Vector store type ('weaviate', 'qdrant', 'faiss')
**options: Additional options
"""
if vector_store_type == "pinecone":
self._export_pinecone_format(vectors, file_path, **options)
elif vector_store_type == "weaviate":
if vector_store_type == "weaviate":
self._export_weaviate_format(vectors, file_path, **options)
elif vector_store_type == "qdrant":
self._export_qdrant_format(vectors, file_path, **options)
@@ -495,27 +493,6 @@ class VectorExporter:
# Default to JSON
self._export_json(vectors, Path(file_path), {}, **options)
def _export_pinecone_format(
self, vectors: List[Dict[str, Any]], file_path: Path, **options
) -> None:
"""Export in Pinecone format."""
pinecone_data = []
for vec_data in vectors:
vector_id = vec_data.get("id") or vec_data.get("vector_id", "")
vector = vec_data.get("vector") or vec_data.get("embedding", [])
metadata = vec_data.get("metadata", {})
if "text" in vec_data and self.include_text:
metadata["text"] = vec_data["text"]
pinecone_data.append(
{"id": vector_id, "values": vector, "metadata": metadata}
)
export_data = {"vectors": pinecone_data}
write_json_file(export_data, file_path, indent=2)
def _export_weaviate_format(
self, vectors: List[Dict[str, Any]], file_path: Path, **options
) -> None:
+18 -19
View File
@@ -289,9 +289,10 @@ class MCPIngestor:
try:
# Get tracking ID
tracking_id = self.progress_tracker.start_task(
task_type="mcp_ingest_resources",
description=f"Ingesting resources from {server_name}",
tracking_id = self.progress_tracker.start_tracking(
module="ingest",
submodule="MCPIngestor",
message=f"Ingesting resources from {server_name}",
)
# List available resources
@@ -307,7 +308,7 @@ class MCPIngestor:
if not resources:
self.logger.warning(f"No resources found for server {server_name}")
self.progress_tracker.update_task(
self.progress_tracker.update_tracking(
tracking_id, status="completed", message="No resources found"
)
return []
@@ -318,11 +319,10 @@ class MCPIngestor:
for idx, resource in enumerate(resources):
try:
self.progress_tracker.update_task(
self.progress_tracker.update_tracking(
tracking_id,
status="in_progress",
progress=(idx / total) * 100,
message=f"Reading resource: {resource.uri}",
status="running",
message=f"Reading resource: {resource.uri} ({idx + 1}/{total})",
)
# Read resource
@@ -347,17 +347,16 @@ class MCPIngestor:
except Exception as e:
self.logger.error(f"Failed to ingest resource {resource.uri}: {e}")
self.progress_tracker.update_task(
self.progress_tracker.update_tracking(
tracking_id,
status="warning",
status="running",
message=f"Failed to ingest resource {resource.uri}: {e}",
)
continue
self.progress_tracker.update_task(
self.progress_tracker.update_tracking(
tracking_id,
status="completed",
progress=100,
message=f"Successfully ingested {len(ingested_data)} resources",
)
@@ -393,13 +392,14 @@ class MCPIngestor:
try:
# Get tracking ID
tracking_id = self.progress_tracker.start_task(
task_type="mcp_ingest_tool",
description=f"Calling tool {tool_name} on {server_name}",
tracking_id = self.progress_tracker.start_tracking(
module="ingest",
submodule="MCPIngestor",
message=f"Calling tool {tool_name} on {server_name}",
)
self.progress_tracker.update_task(
tracking_id, status="in_progress", message=f"Calling tool: {tool_name}"
self.progress_tracker.update_tracking(
tracking_id, status="running", message=f"Calling tool: {tool_name}"
)
# Call tool
@@ -415,10 +415,9 @@ class MCPIngestor:
tool_name=tool_name,
)
self.progress_tracker.update_task(
self.progress_tracker.update_tracking(
tracking_id,
status="completed",
progress=100,
message=f"Successfully called tool {tool_name}",
)
+8 -8
View File
@@ -184,7 +184,7 @@ def ingest_file(
"""
# Check for custom method in registry
custom_method = method_registry.get("file", method)
if custom_method:
if custom_method and custom_method != ingest_file:
try:
return custom_method(source, **kwargs)
except Exception as e:
@@ -249,7 +249,7 @@ def ingest_web(
"""
# Check for custom method in registry
custom_method = method_registry.get("web", method)
if custom_method:
if custom_method and custom_method != ingest_web:
try:
return custom_method(source, **kwargs)
except Exception as e:
@@ -308,7 +308,7 @@ def ingest_feed(
"""
# Check for custom method in registry
custom_method = method_registry.get("feed", method)
if custom_method:
if custom_method and custom_method != ingest_feed:
try:
return custom_method(source, **kwargs)
except Exception as e:
@@ -365,7 +365,7 @@ def ingest_stream(
"""
# Check for custom method in registry
custom_method = method_registry.get("stream", method)
if custom_method:
if custom_method and custom_method != ingest_stream:
try:
return custom_method(source, **kwargs)
except Exception as e:
@@ -437,7 +437,7 @@ def ingest_repository(
"""
# Check for custom method in registry
custom_method = method_registry.get("repo", method)
if custom_method:
if custom_method and custom_method != ingest_repository:
try:
return custom_method(source, **kwargs)
except Exception as e:
@@ -495,7 +495,7 @@ def ingest_email(
"""
# Check for custom method in registry
custom_method = method_registry.get("email", method)
if custom_method:
if custom_method and custom_method != ingest_email:
try:
return custom_method(source, **kwargs)
except Exception as e:
@@ -566,7 +566,7 @@ def ingest_database(
# Check for custom method in registry
if method:
custom_method = method_registry.get("db", method)
if custom_method:
if custom_method and custom_method != ingest_database:
try:
return custom_method(source, **kwargs)
except Exception as e:
@@ -658,7 +658,7 @@ def ingest_mcp(
"""
# Check for custom method in registry
custom_method = method_registry.get("mcp", method)
if custom_method:
if custom_method and custom_method != ingest_mcp:
try:
return custom_method(source, **kwargs)
except Exception as e:
+7 -3
View File
@@ -42,6 +42,7 @@ import git
from ..utils.exceptions import ProcessingError, ValidationError
from ..utils.logging import get_logger
from ..utils.progress_tracker import get_progress_tracker
@dataclass
@@ -500,6 +501,9 @@ class RepoIngestor:
# Initialize analyzer
self.analyzer = GitAnalyzer(**self.config)
# Initialize progress tracker
self.progress_tracker = get_progress_tracker()
# Temporary directory for cloning
self.temp_dir = None
@@ -532,7 +536,7 @@ class RepoIngestor:
try:
parsed = git.Repo.clone_from(repo_url, self._get_temp_dir(), **options)
except Exception as e:
self.progress_tracker.stop_tracking(
self.progress_tracker.update_tracking(
tracking_id, status="failed", message=str(e)
)
raise ProcessingError(f"Failed to clone repository: {e}") from e
@@ -581,7 +585,7 @@ class RepoIngestor:
structure = self.analyzer.analyze_structure(repo_path)
metrics = self.analyzer.calculate_metrics(repo_path)
self.progress_tracker.stop_tracking(
self.progress_tracker.update_tracking(
tracking_id,
status="completed",
message=f"Processed {len(code_files)} files, {len(commits)} commits",
@@ -596,7 +600,7 @@ class RepoIngestor:
}
except Exception as e:
self.progress_tracker.stop_tracking(
self.progress_tracker.update_tracking(
tracking_id, status="failed", message=str(e)
)
raise
+3
View File
@@ -44,6 +44,7 @@ analyzer = GraphAnalyzer()
analysis = analyzer.analyze_graph(kg)
```
## Knowledge Graph Building
### Basic Graph Building
@@ -52,6 +53,8 @@ analysis = analyzer.analyze_graph(kg)
from semantica.kg import GraphBuilder
# Create graph builder
# Note: resolve_conflicts=True uses the basic resolution capabilities of ConflictDetector.
# For advanced conflict resolution, consider using the semantica.conflicts module directly.
builder = GraphBuilder(
merge_entities=True,
entity_resolution_strategy="fuzzy",
+3 -1
View File
@@ -161,7 +161,7 @@ class DataCleaner:
if handle_missing:
strategy = options.get("missing_strategy", "remove")
cleaned = self.missing_value_handler.handle_missing_values(
cleaned, strategy=strategy
cleaned, strategy=strategy, **options
)
# Validate data
@@ -688,6 +688,8 @@ class DataValidator:
"""
if isinstance(expected_types, type):
expected_types = [expected_types]
elif isinstance(expected_types, str):
expected_types = [expected_types]
actual_type = type(data)
+3 -1
View File
@@ -520,7 +520,9 @@ class NameVariantHandler:
# Remove titles
name = entity_name
for title in self.titles:
name = name.replace(title + " ", "").replace(title, "")
# Case-insensitive removal of titles from the beginning of the name
pattern = re.compile(r"^" + re.escape(title) + r"\s*", re.IGNORECASE)
name = pattern.sub("", name)
name = name.strip()
+4 -7
View File
@@ -802,10 +802,7 @@ def list_available_methods(task: Optional[str] = None) -> Dict[str, List[str]]:
# Register default methods
method_registry.register("text", "default", normalize_text)
method_registry.register("clean", "default", clean_text)
method_registry.register("entity", "default", normalize_entity)
method_registry.register("date", "default", normalize_date)
method_registry.register("number", "default", normalize_number)
method_registry.register("language", "default", detect_language)
method_registry.register("encoding", "default", handle_encoding)
# Note: We do not register the convenience functions as defaults to avoid recursion.
# The convenience functions have built-in fallback to the default implementations
# (using the classes directly) when no custom method is found in the registry.
+22
View File
@@ -443,15 +443,37 @@ class UnitConverter:
# Map to standard unit
unit_map = {
"m": "meter",
"meter": "meter",
"meters": "meter",
"km": "kilometer",
"kilometer": "kilometer",
"kilometers": "kilometer",
"cm": "centimeter",
"centimeter": "centimeter",
"centimeters": "centimeter",
"mm": "millimeter",
"millimeter": "millimeter",
"millimeters": "millimeter",
"kg": "kilogram",
"kilogram": "kilogram",
"kilograms": "kilogram",
"kgs": "kilogram",
"g": "gram",
"gram": "gram",
"grams": "gram",
"lb": "pound",
"pound": "pound",
"pounds": "pound",
"lbs": "pound",
"oz": "ounce",
"ounce": "ounce",
"ounces": "ounce",
"l": "liter",
"liter": "liter",
"liters": "liter",
"ml": "milliliter",
"milliliter": "milliliter",
"milliliters": "milliliter",
}
return unit_map.get(unit_lower, unit_lower)
+1 -1
View File
@@ -31,7 +31,7 @@ class LLMOntologyGenerator:
)
base_uri = options.get("base_uri")
name = options.get("name") or "GeneratedOntology"
name = options.get("name")
version = options.get("version") or "1.0"
prompt = self._build_prompt(text=text, name=name, base_uri=base_uri)
+4
View File
@@ -216,6 +216,10 @@ class NamespaceManager:
def _to_camel_case(self, name: str) -> str:
"""Convert name to camelCase."""
# Check if already likely camelCase (starts with lower, has upper, single word)
if name and name[0].islower() and any(c.isupper() for c in name) and ' ' not in name and '_' not in name:
return name
# Remove special characters and split
words = re.findall(r"[a-zA-Z0-9]+", name)
if not words:
+8 -4
View File
@@ -262,8 +262,8 @@ class NamingConventions:
# camelCase for object properties
suggested = self._to_camel_case(name)
else:
# lowercase for data properties
suggested = name.lower()
# camelCase for data properties as well (standard practice)
suggested = self._to_camel_case(name)
return suggested
@@ -364,6 +364,10 @@ class NamingConventions:
def _to_camel_case(self, name: str) -> str:
"""Convert to camelCase."""
# Check if already likely camelCase (starts with lower, has upper, single word)
if name and name[0].islower() and any(c.isupper() for c in name) and ' ' not in name and '_' not in name:
return name
words = re.findall(r"[a-zA-Z0-9]+", name)
if not words:
return "hasProperty"
@@ -381,8 +385,8 @@ class NamingConventions:
# Basic singularization rules
if name.lower().endswith("ies"):
return name[:-3] + "y"
elif name.lower().endswith("es"):
elif name.lower().endswith("es") and not name.lower().endswith("ss"):
return name[:-2]
elif name.lower().endswith("s") and len(name) > 1:
elif name.lower().endswith("s") and len(name) > 1 and not name.lower().endswith("ss") and name.lower() not in ["class", "process", "analysis"]:
return name[:-1]
return name
+13 -2
View File
@@ -170,7 +170,13 @@ class OntologyGenerator:
self.progress_tracker.update_tracking(
tracking_id, message="Stage 3: Mapping to OWL types..."
)
typed_definitions = self._stage3_definition_to_types(definitions, **options)
# Ensure entities and relationships are available for property inference
stage3_options = options.copy()
stage3_options["entities"] = data.get("entities", [])
stage3_options["relationships"] = data.get("relationships", [])
typed_definitions = self._stage3_definition_to_types(definitions, **stage3_options)
# Stage 4: Hierarchy Generation
self.progress_tracker.update_tracking(
@@ -266,9 +272,14 @@ class OntologyGenerator:
relationships = options.get("relationships", [])
entities = options.get("entities", [])
# Clean options for infer_properties to avoid multiple values for arguments
prop_options = options.copy()
prop_options.pop("entities", None)
prop_options.pop("relationships", None)
# Infer properties
properties = self.property_generator.infer_properties(
entities=entities, relationships=relationships, classes=classes, **options
entities=entities, relationships=relationships, classes=classes, **prop_options
)
# Add types to classes
+5
View File
@@ -89,6 +89,11 @@ class PropertyGenerator:
submodule="PropertyGenerator",
message=f"Inferring properties from {len(entities)} entities and {len(relationships)} relationships",
)
# Merge config into options
for key, value in self.config.items():
if key not in options:
options[key] = value
try:
properties = []
+49 -14
View File
@@ -37,6 +37,7 @@ from bs4 import BeautifulSoup
from ..utils.exceptions import ProcessingError, ValidationError
from ..utils.logging import get_logger
from ..utils.progress_tracker import get_progress_tracker
@dataclass
@@ -65,6 +66,20 @@ class HTMLElement:
children: List["HTMLElement"] = field(default_factory=list)
@dataclass
class HTMLData:
"""HTML document representation."""
metadata: Dict[str, Any]
text: str
html: str
links: List[Dict[str, Any]] = field(default_factory=list)
images: List[Dict[str, Any]] = field(default_factory=list)
forms: List[Dict[str, Any]] = field(default_factory=list)
tables: List[Dict[str, Any]] = field(default_factory=list)
structure: List[Dict[str, Any]] = field(default_factory=list)
class HTMLParser:
"""HTML document parser."""
@@ -81,7 +96,7 @@ class HTMLParser:
def parse(
self, html_content: Union[str, Path], base_url: Optional[str] = None, **options
) -> Dict[str, Any]:
) -> HTMLData:
"""
Parse HTML content.
@@ -96,7 +111,7 @@ class HTMLParser:
- clean_text: Whether to clean extracted text (default: True)
Returns:
dict: Parsed HTML data
HTMLData: Parsed HTML data
"""
# Track HTML parsing
file_path = None
@@ -160,16 +175,16 @@ class HTMLParser:
status="completed",
message=f"Parsed HTML: {len(links)} links, {len(images)} images",
)
return {
"metadata": metadata.__dict__,
"text": text,
"html": html_string,
"links": links,
"images": images,
"forms": forms,
"tables": tables,
"structure": structure,
}
return HTMLData(
metadata=metadata.__dict__,
text=text,
html=html_string,
links=links,
images=images,
forms=forms,
tables=tables,
structure=structure,
)
except Exception as e:
self.progress_tracker.stop_tracking(
@@ -184,6 +199,26 @@ class HTMLParser:
)
raise
def extract_metadata(self, html_content: Union[str, Path]) -> Dict[str, Any]:
"""
Extract metadata from HTML.
Args:
html_content: HTML content or file path
Returns:
dict: Extracted metadata
"""
result = self.parse(
html_content,
extract_links=False,
extract_images=False,
extract_forms=False,
extract_tables=False,
clean_text=False,
)
return result.metadata
def extract_text(self, html_content: Union[str, Path], clean: bool = True) -> str:
"""
Extract text from HTML.
@@ -203,7 +238,7 @@ class HTMLParser:
extract_tables=False,
clean_text=clean,
)
return result["text"]
return result.text
def extract_links(
self, html_content: Union[str, Path], base_url: Optional[str] = None
@@ -225,7 +260,7 @@ class HTMLParser:
extract_forms=False,
extract_tables=False,
)
return result["links"]
return result.links
def _extract_metadata(self, soup: BeautifulSoup) -> HTMLMetadata:
"""Extract metadata from HTML."""
@@ -58,6 +58,9 @@ class StructuredDataParser:
self.config = config or {}
self.config.update(kwargs)
# Initialize progress tracker
self.progress_tracker = get_progress_tracker()
# Initialize parsers
self.json_parser = JSONParser(**self.config.get("json", {}))
self.csv_parser = CSVParser(**self.config.get("csv", {}))
+1 -1
View File
@@ -148,7 +148,7 @@ class PipelineTemplateManager:
{
"name": "store_vectors",
"type": "store_vectors",
"config": {"store": "pinecone"},
"config": {"store": "weaviate"},
"dependencies": ["embed"],
},
],
+3 -2
View File
@@ -632,7 +632,7 @@ builder = template_manager.create_pipeline_from_template(
"rag_pipeline",
chunk={"chunk_size": 512},
embed={"model": "text-embedding-3-large"},
store_vectors={"store": "pinecone"}
store_vectors={"store": "weaviate"}
)
pipeline = builder.build()
@@ -1124,7 +1124,8 @@ builder = template_manager.create_pipeline_from_template(
ingest={"source": "./documents"},
chunk={"chunk_size": 512, "overlap": 50},
embed={"model": "text-embedding-3-large", "batch_size": 32},
store_vectors={"store": "pinecone", "index_name": "documents"}
# Step-specific overrides
store_vectors={"store": "weaviate", "index_name": "documents"}
)
pipeline = builder.build()
+53 -3
View File
@@ -34,6 +34,7 @@ License: MIT
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Dict, List, Optional
import re
from ..utils.exceptions import ProcessingError, ValidationError
from ..utils.logging import get_logger
@@ -203,9 +204,58 @@ class AbductiveReasoner:
def _rule_explains_observation(self, rule: Rule, observation: Observation) -> bool:
"""Check if rule can explain observation."""
# Simple check: rule conclusion matches observation
# Can be enhanced with more sophisticated matching
return True
# Check if rule conclusion matches observation description
# Try exact match first
if rule.conclusion == observation.description:
return True
# Try unification if variables are involved
if "?" in rule.conclusion:
bindings = self._unify(rule.conclusion, observation.description, {})
if bindings is not None:
return True
return False
def _parse_predicate(self, text: str) -> tuple[str, List[str]]:
"""Parse 'Predicate(arg1, arg2)' into ('Predicate', ['arg1', 'arg2'])."""
if not isinstance(text, str):
return text, []
match = re.match(r"(\w+)\((.+)\)", text)
if not match:
return text, []
predicate = match.group(1)
args = [arg.strip() for arg in match.group(2).split(",")]
return predicate, args
def _unify(self, condition: str, fact: str, bindings: Dict[str, str]) -> Optional[Dict[str, str]]:
"""
Try to unify a condition (with vars) against a fact.
Returns new bindings if successful, None otherwise.
"""
if condition == fact:
return bindings
cond_pred, cond_args = self._parse_predicate(condition)
fact_pred, fact_args = self._parse_predicate(fact)
if cond_pred != fact_pred:
return None
if len(cond_args) != len(fact_args):
return None
new_bindings = bindings.copy()
for c_arg, f_arg in zip(cond_args, fact_args):
if c_arg.startswith("?"):
if c_arg in new_bindings:
if new_bindings[c_arg] != f_arg:
return None # Conflict
else:
new_bindings[c_arg] = f_arg
else:
if c_arg != f_arg:
return None # Constant mismatch
return new_bindings
def _calculate_coverage(self, rule: Rule, observation: Observation) -> float:
"""Calculate how well rule covers observation."""
+158 -34
View File
@@ -32,6 +32,7 @@ License: MIT
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional, Set
import re
from ..utils.exceptions import ProcessingError, ValidationError
from ..utils.logging import get_logger
@@ -148,12 +149,16 @@ class DeductiveReasoner:
rules = self.rule_manager.get_all_rules()
for rule in rules:
# Check if rule can be applied
if self._can_apply_rule(rule, premises):
conclusion = self._apply_rule_to_premises(rule, premises)
# Find all matches (bindings) for the rule
matches = self._find_matches(rule.conditions, {})
for bindings in matches:
conclusion = self._apply_rule_to_premises(rule, premises, bindings)
if conclusion:
conclusions.append(conclusion)
self.known_facts.add(conclusion.statement)
# Check if conclusion is new (not in known facts)
if conclusion.statement not in self.known_facts:
conclusions.append(conclusion)
self.known_facts.add(conclusion.statement)
self.progress_tracker.stop_tracking(
tracking_id,
@@ -168,39 +173,127 @@ class DeductiveReasoner:
)
raise
def _can_apply_rule(self, rule: Rule, premises: List[Premise]) -> bool:
"""Check if rule can be applied to premises."""
# Check if all rule conditions match premises
premise_statements = {p.statement for p in premises}
def _parse_predicate(self, text: str) -> tuple[str, List[str]]:
"""Parse 'Predicate(arg1, arg2)' into ('Predicate', ['arg1', 'arg2'])."""
if not isinstance(text, str):
return text, []
match = re.match(r"(\w+)\((.+)\)", text)
if not match:
return text, []
predicate = match.group(1)
args = [arg.strip() for arg in match.group(2).split(",")]
return predicate, args
for condition in rule.conditions:
if (
condition not in premise_statements
and condition not in self.known_facts
):
return False
def _unify(self, condition: str, fact: str, bindings: Dict[str, str]) -> Optional[Dict[str, str]]:
"""
Try to unify a condition (with vars) against a fact.
Returns new bindings if successful, None otherwise.
"""
if condition == fact:
return bindings
cond_pred, cond_args = self._parse_predicate(condition)
fact_pred, fact_args = self._parse_predicate(fact)
if cond_pred != fact_pred:
return None
if len(cond_args) != len(fact_args):
return None
new_bindings = bindings.copy()
for c_arg, f_arg in zip(cond_args, fact_args):
if c_arg.startswith("?"):
if c_arg in new_bindings:
if new_bindings[c_arg] != f_arg:
return None # Conflict
else:
new_bindings[c_arg] = f_arg
else:
if c_arg != f_arg:
return None # Constant mismatch
return new_bindings
return True
def _substitute_bindings(self, text: str, bindings: Dict[str, str]) -> str:
"""Substitute variables in text with bindings."""
if not isinstance(text, str):
return text
pred, args = self._parse_predicate(text)
if not args:
return text
new_args = []
for arg in args:
if arg in bindings:
new_args.append(bindings[arg])
else:
new_args.append(arg)
return f"{pred}({', '.join(new_args)})"
def _find_matches(self, conditions: List[str], bindings: Dict[str, str]) -> List[Dict[str, str]]:
"""
Recursively find all bindings that satisfy the conditions.
"""
if not conditions:
return [bindings]
first = conditions[0]
# Substitute current bindings into first condition before matching
first_substituted = self._substitute_bindings(first, bindings)
rest = conditions[1:]
valid_bindings = []
# Try to match 'first' against all known facts
for fact in self.known_facts:
# Skip if fact is not a string (unhashable/objects) for now
if not isinstance(fact, str):
continue
unified = self._unify(first_substituted, fact, bindings)
if unified is not None:
# Recursive step
results = self._find_matches(rest, unified)
valid_bindings.extend(results)
return valid_bindings
def _apply_rule_to_premises(
self, rule: Rule, premises: List[Premise]
self, rule: Rule, premises: List[Premise], bindings: Dict[str, str]
) -> Optional[Conclusion]:
"""Apply rule to premises and generate conclusion."""
# Find matching premises
matching_premises = [
p
for p in premises
if p.statement in rule.conditions or p.statement in self.known_facts
]
# Find matching premises (those that support the bindings)
# This is a bit approximate, ideally we track which premise supported which condition
matching_premises = []
# Instantiate conclusion
conclusion_stmt = rule.conclusion
if bindings:
conclusion_stmt = self._substitute_bindings(conclusion_stmt, bindings)
# Find premises that match the conditions (instantiated)
for cond in rule.conditions:
instantiated = self._substitute_bindings(cond, bindings)
for p in premises:
if p.statement == instantiated:
matching_premises.append(p)
break
# Note: some conditions might be matched by self.known_facts which are not in 'premises' arg
# but are in self.known_facts.
# If a premise is not in the passed list but in known_facts, we can't add it to matching_premises list
# unless we find the Premise object.
# But known_facts stores strings.
# So matching_premises might be incomplete if we rely on known_facts.
# However, for this method signature, we return a Conclusion with premises.
conclusion = Conclusion(
conclusion_id=f"conc_{len(matching_premises)}",
statement=rule.conclusion,
conclusion_id=f"conc_{rule.name}_{len(matching_premises)}",
statement=conclusion_stmt,
premises=matching_premises,
rule_applied=rule,
confidence=rule.confidence,
proof_steps=[f"Applied rule: {rule.name}"],
metadata={"rule_id": rule.rule_id},
proof_steps=[f"Applied rule: {rule.name} with bindings {bindings}"],
metadata={"rule_id": rule.rule_id, "bindings": bindings},
)
return conclusion
@@ -272,6 +365,7 @@ class DeductiveReasoner:
return None
# Check if goal is already known
# Try direct match
if goal in self.known_facts:
return Conclusion(
conclusion_id=f"known_{goal}",
@@ -279,35 +373,65 @@ class DeductiveReasoner:
confidence=1.0,
proof_steps=["Known fact"],
)
# Try unification with known facts
if isinstance(goal, str) and "?" in goal:
for fact in self.known_facts:
if isinstance(fact, str):
if self._unify(goal, fact, {}) is not None:
return Conclusion(
conclusion_id=f"known_{fact}",
statement=fact,
confidence=1.0,
proof_steps=[f"Known fact (matched pattern {goal})"],
)
# Find rules that can prove goal
rules = self.rule_manager.get_all_rules()
applicable_rules = [r for r in rules if r.conclusion == goal]
# Use unified matching for finding applicable rules
applicable_rules_and_bindings = []
for r in rules:
bindings = self._unify(r.conclusion, goal, {})
if bindings is not None:
applicable_rules_and_bindings.append((r, bindings))
for rule in applicable_rules:
for rule, initial_bindings in applicable_rules_and_bindings:
# Try to prove all premises
premise_conclusions = []
all_proven = True
current_bindings = initial_bindings.copy()
for condition in rule.conditions:
# Instantiate condition with current bindings
instantiated_cond = self._substitute_bindings(condition, current_bindings)
premise_conclusion = self._prove_backward(
condition, proof, depth + 1, max_depth, **options
instantiated_cond, proof, depth + 1, max_depth, **options
)
if premise_conclusion:
premise_conclusions.append(premise_conclusion)
# Update bindings if we proved something more specific
new_bindings = self._unify(instantiated_cond, premise_conclusion.statement, current_bindings)
if new_bindings:
current_bindings = new_bindings
else:
all_proven = False
break
if all_proven:
# All premises proven, rule can fire
# Instantiate conclusion with final bindings
final_conclusion = self._substitute_bindings(rule.conclusion, current_bindings)
conclusion = Conclusion(
conclusion_id=f"conc_{goal}",
statement=goal,
premises=[Premise(p, p) for p in rule.conditions],
statement=final_conclusion,
premises=[p for p in premise_conclusions], # Use actual premises found
rule_applied=rule,
confidence=rule.confidence,
proof_steps=[f"Proved using rule: {rule.name}"],
proof_steps=[f"Proved using rule: {rule.name} with bindings {current_bindings}"],
metadata={"rule_id": rule.rule_id, "bindings": current_bindings}
)
return conclusion
+184 -39
View File
@@ -29,6 +29,7 @@ Author: Semantica Contributors
License: MIT
"""
import re
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Callable, Dict, List, Optional, Set
@@ -92,6 +93,7 @@ class InferenceEngine:
self.max_iterations = self.config.get("max_iterations", 100)
self.facts: Set[Any] = set()
self.unhashable_facts: List[Any] = []
self.inferred_facts: List[InferenceResult] = []
def add_rule(self, rule_definition: str, **options) -> Rule:
@@ -115,15 +117,28 @@ class InferenceEngine:
return rule
def add_fact(self, fact: Any) -> None:
def add_fact(self, fact: Any) -> bool:
"""
Add fact to knowledge base.
Args:
fact: Fact to add
Returns:
True if fact was newly added, False if it already existed
"""
self.facts.add(fact)
self.logger.debug(f"Added fact: {fact}")
try:
if fact in self.facts:
return False
self.facts.add(fact)
self.logger.debug(f"Added fact: {fact}")
return True
except TypeError:
if fact not in self.unhashable_facts:
self.unhashable_facts.append(fact)
self.logger.debug(f"Added unhashable fact: {fact}")
return True
return False
def add_facts(self, facts: List[Any]) -> None:
"""
@@ -180,15 +195,18 @@ class InferenceEngine:
)
for rule in rules:
# Check if rule can fire
if self._can_rule_fire(rule):
# Apply rule
result = self._apply_rule(rule)
# Find all matches for the rule
matches = self._find_matches(rule.conditions, {})
for bindings in matches:
# Apply rule with bindings
result = self._apply_rule(rule, bindings=bindings)
if result:
results.append(result)
self.inferred_facts.append(result)
self.add_fact(result.conclusion)
new_facts = True
# Only consider it a new inference if the fact wasn't already known
if self.add_fact(result.conclusion):
results.append(result)
self.inferred_facts.append(result)
new_facts = True
self.logger.info(
f"Forward chaining completed: {len(results)} inferences in {iterations} iterations"
@@ -228,39 +246,84 @@ class InferenceEngine:
self.progress_tracker.update_tracking(
tracking_id, message="Checking if goal is already a fact..."
)
if goal in self.facts:
# Check for direct match or unification with facts
found_fact = None
# First try direct match (fastest)
try:
if goal in self.facts:
found_fact = goal
except TypeError:
if goal in self.unhashable_facts:
found_fact = goal
# If not found and goal looks like a pattern (string with ?), try unification
if found_fact is None and isinstance(goal, str) and "?" in goal:
for fact in self.facts:
if isinstance(fact, str):
# Try to unify to see if it matches
if self._unify(goal, fact, {}) is not None:
found_fact = fact
break
if found_fact:
self.progress_tracker.stop_tracking(
tracking_id, status="completed", message="Goal is already a fact"
tracking_id, status="completed", message=f"Goal proven by fact: {found_fact}"
)
return InferenceResult(conclusion=goal, confidence=1.0)
return InferenceResult(conclusion=found_fact, confidence=1.0)
# Find rules that can prove the goal
self.progress_tracker.update_tracking(
tracking_id, message="Finding rules that can prove the goal..."
)
rules = self.rule_manager.get_all_rules()
applicable_rules = [r for r in rules if self._rule_concludes(r, goal)]
# Use unified matching for finding applicable rules
applicable_rules_and_bindings = []
for r in rules:
bindings = self._unify(r.conclusion, goal, {})
if bindings is not None:
applicable_rules_and_bindings.append((r, bindings))
self.progress_tracker.update_tracking(
tracking_id,
message=f"Found {len(applicable_rules)} applicable rules, trying to prove premises...",
message=f"Found {len(applicable_rules_and_bindings)} applicable rules, trying to prove premises...",
)
for rule in applicable_rules:
# Try to prove premises
premises = []
for rule, initial_bindings in applicable_rules_and_bindings:
# Try to prove premises with bindings, propagating bindings between premises
current_bindings = initial_bindings.copy()
premises_results = []
all_premises_proven = True
for premise in rule.conditions:
premise_result = self.backward_chain(premise, **options)
for cond in rule.conditions:
# Instantiate condition with current bindings
instantiated_cond = self._substitute_bindings(cond, current_bindings)
# Recursively prove this condition
premise_result = self.backward_chain(instantiated_cond, **options)
if premise_result:
premises.append(premise_result.conclusion)
premises_results.append(premise_result.conclusion)
# If the premise had variables, update bindings based on the proven fact
# We unify the instantiated condition (which might still have vars) with the proven conclusion
new_bindings = self._unify(instantiated_cond, premise_result.conclusion, current_bindings)
if new_bindings is not None:
current_bindings = new_bindings
else:
# This implies a conflict, which shouldn't happen if backward_chain returned success
# on instantiated_cond, but good to be safe
all_premises_proven = False
break
else:
all_premises_proven = False
break
if all_premises_proven:
# All premises proven, rule can fire
result = self._apply_rule(rule, premises)
result = self._apply_rule(rule, premises=premises_results, bindings=current_bindings)
if result:
self.progress_tracker.stop_tracking(
tracking_id,
@@ -280,34 +343,115 @@ class InferenceEngine:
)
raise
def _can_rule_fire(self, rule: Rule) -> bool:
"""Check if rule can fire (all conditions met)."""
for condition in rule.conditions:
if condition not in self.facts:
return False
return True
def _parse_predicate(self, text: str) -> tuple[str, List[str]]:
"""Parse 'Predicate(arg1, arg2)' into ('Predicate', ['arg1', 'arg2'])."""
if not isinstance(text, str):
return text, []
match = re.match(r"(\w+)\((.+)\)", text)
if not match:
return text, []
predicate = match.group(1)
args = [arg.strip() for arg in match.group(2).split(",")]
return predicate, args
def _rule_concludes(self, rule: Rule, goal: Any) -> bool:
"""Check if rule concludes the goal."""
return rule.conclusion == goal
def _unify(self, condition: str, fact: str, bindings: Dict[str, str]) -> Optional[Dict[str, str]]:
"""
Try to unify a condition (with vars) against a fact.
Returns new bindings if successful, None otherwise.
"""
# Handle exact string match shortcut
if condition == fact:
return bindings
cond_pred, cond_args = self._parse_predicate(condition)
fact_pred, fact_args = self._parse_predicate(fact)
if cond_pred != fact_pred:
return None
if len(cond_args) != len(fact_args):
return None
new_bindings = bindings.copy()
for c_arg, f_arg in zip(cond_args, fact_args):
if c_arg.startswith("?"):
if c_arg in new_bindings:
if new_bindings[c_arg] != f_arg:
return None # Conflict
else:
new_bindings[c_arg] = f_arg
else:
if c_arg != f_arg:
return None # Constant mismatch
return new_bindings
def _find_matches(self, conditions: List[str], bindings: Dict[str, str]) -> List[Dict[str, str]]:
"""
Recursively find all bindings that satisfy the conditions.
"""
if not conditions:
return [bindings]
first = conditions[0]
# Substitute current bindings into first condition before matching
first_substituted = self._substitute_bindings(first, bindings)
rest = conditions[1:]
valid_bindings = []
# Try to match 'first' against all facts
for fact in self.facts:
# Skip if fact is not a string (unhashable/objects) for now, or handle str()
if not isinstance(fact, str):
continue
unified = self._unify(first_substituted, fact, bindings)
if unified is not None:
# Recursive step
results = self._find_matches(rest, unified)
valid_bindings.extend(results)
return valid_bindings
def _substitute_bindings(self, text: str, bindings: Dict[str, str]) -> str:
"""Substitute variables in text with bindings."""
if not isinstance(text, str):
return text
pred, args = self._parse_predicate(text)
if not args:
return text
new_args = []
for arg in args:
if arg in bindings:
new_args.append(bindings[arg])
else:
new_args.append(arg)
return f"{pred}({', '.join(new_args)})"
def _apply_rule(
self, rule: Rule, premises: Optional[List[Any]] = None
self, rule: Rule, premises: Optional[List[Any]] = None, bindings: Optional[Dict[str, str]] = None
) -> Optional[InferenceResult]:
"""Apply rule and return inference result."""
conclusion = rule.conclusion
if bindings:
conclusion = self._substitute_bindings(conclusion, bindings)
if premises is None:
premises = list(rule.conditions)
# Reconstruct premises from bindings if not provided (approximate)
premises = [self._substitute_bindings(c, bindings or {}) for c in rule.conditions]
result = InferenceResult(
conclusion=rule.conclusion,
conclusion=conclusion,
premises=premises,
rule_used=rule,
confidence=rule.confidence,
metadata={"rule_name": rule.name, "rule_id": rule.rule_id},
metadata={"rule_name": rule.name, "rule_id": rule.rule_id, "bindings": bindings},
)
return result
def infer(self, query: Any, **options) -> List[InferenceResult]:
"""
Perform inference based on strategy.
@@ -365,9 +509,9 @@ class InferenceEngine:
)
raise
def get_facts(self) -> Set[Any]:
def get_facts(self) -> List[Any]:
"""Get all facts."""
return set(self.facts)
return list(self.facts) + self.unhashable_facts
def get_inferred_facts(self) -> List[InferenceResult]:
"""Get all inferred facts."""
@@ -376,6 +520,7 @@ class InferenceEngine:
def clear_facts(self) -> None:
"""Clear all facts."""
self.facts.clear()
self.unhashable_facts.clear()
self.inferred_facts.clear()
def reset(self) -> None:
+7 -7
View File
@@ -45,7 +45,7 @@ print(f"Inferred {len(results)} new facts")
from semantica.reasoning import SPARQLReasoner
# Create SPARQL reasoner
reasoner = SPARQLReasoner(triple_store=kg)
reasoner = SPARQLReasoner(triplet_store=kg)
# Execute query
query = "SELECT ?s ?p ?o WHERE { ?s ?p ?o }"
@@ -190,7 +190,7 @@ results = engine.forward_chain()
from semantica.reasoning import SPARQLReasoner
# Create reasoner with knowledge graph
reasoner = SPARQLReasoner(triple_store=kg)
reasoner = SPARQLReasoner(triplet_store=kg)
# Execute SPARQL query
query = """
@@ -212,7 +212,7 @@ for binding in result.bindings:
```python
from semantica.reasoning import SPARQLReasoner
reasoner = SPARQLReasoner(triple_store=kg, enable_inference=True)
reasoner = SPARQLReasoner(triplet_store=kg, enable_inference=True)
# Add inference rule
reasoner.add_inference_rule("IF ?x :type :Company THEN ?x :type :Organization")
@@ -234,7 +234,7 @@ result = reasoner.execute_query(query)
from semantica.reasoning import SPARQLReasoner
reasoner = SPARQLReasoner(
triple_store=kg,
triplet_store=kg,
enable_inference=True,
inference_rules=["rdfs:subClassOf", "rdfs:subPropertyOf"]
)
@@ -1165,7 +1165,7 @@ engine = InferenceEngine(
# Configure SPARQL reasoner
reasoner = SPARQLReasoner(
triple_store=kg,
triplet_store=kg,
enable_inference=True,
query_cache_size=1000
)
@@ -1234,7 +1234,7 @@ for result in results:
print(f"Explanation: {explanation.natural_language}")
# 6. Query with SPARQL reasoning
sparql_reasoner = SPARQLReasoner(triple_store=kg, enable_inference=True)
sparql_reasoner = SPARQLReasoner(triplet_store=kg, enable_inference=True)
query_result = sparql_reasoner.execute_query("SELECT ?x WHERE { ?x :type :Employee }")
```
@@ -1332,7 +1332,7 @@ from semantica.kg import build
kg = build(sources=[...])
# Create SPARQL reasoner with KG
reasoner = SPARQLReasoner(triple_store=kg, enable_inference=True)
reasoner = SPARQLReasoner(triplet_store=kg, enable_inference=True)
# Add inference rules
reasoner.add_inference_rule("IF ?x :type :Company THEN ?x :type :Organization")
+6 -6
View File
@@ -12,7 +12,7 @@ Key Features:
- Query expansion
- Performance optimization
- Error handling and recovery
- Triple store integration
- Triplet store integration
Main Classes:
- SPARQLReasoner: SPARQL-based reasoning engine
@@ -67,7 +67,7 @@ class SPARQLReasoner:
Args:
config: Configuration dictionary
**kwargs: Additional configuration options:
- triple_store: Triple store connection
- triplet_store: Triplet store connection
- enable_inference: Enable inference rules
"""
self.logger = get_logger("sparql_reasoner")
@@ -78,7 +78,7 @@ class SPARQLReasoner:
self.progress_tracker = get_progress_tracker()
self.rule_manager = RuleManager(**self.config)
self.triple_store = self.config.get("triple_store")
self.triplet_store = self.config.get("triplet_store")
self.enable_inference = self.config.get("enable_inference", True)
self.query_cache: Dict[str, Any] = {}
@@ -356,12 +356,12 @@ class SPARQLReasoner:
)
expanded_query = self.expand_query(query, **options)
# Execute query (if triple store available)
# Execute query (if triplet store available)
self.progress_tracker.update_tracking(
tracking_id, message="Executing query..."
)
if self.triple_store:
# This would call the triple store's query method
if self.triplet_store:
# This would call the triplet store's query method
# For now, return empty result
result = SPARQLQueryResult(bindings=[], variables=[])
else:
+24 -2
View File
@@ -194,18 +194,21 @@ class SeedDataManager:
entity_type: Optional[str] = None,
relationship_type: Optional[str] = None,
source_name: Optional[str] = None,
delimiter: Optional[str] = None,
) -> List[Dict[str, Any]]:
"""
Load seed data from CSV file.
Reads a CSV file and converts rows to dictionaries. Automatically
adds entity_type, relationship_type, and source metadata if provided.
Supports automatic delimiter detection if not provided.
Args:
file_path: Path to CSV file
entity_type: Optional entity type to add to all records
relationship_type: Optional relationship type to add to all records
source_name: Optional source name for tracking
delimiter: Optional CSV delimiter. If None, attempts to detect it.
Returns:
List of loaded data records as dictionaries
@@ -215,7 +218,7 @@ class SeedDataManager:
Example:
>>> records = manager.load_from_csv("data/entities.csv", entity_type="Person")
>>> print(f"Loaded {len(records)} records")
>>> records = manager.load_from_csv("data/data.csv", delimiter=";")
"""
tracking_id = self.progress_tracker.start_tracking(
module="seed",
@@ -239,7 +242,21 @@ class SeedDataManager:
tracking_id, message="Reading CSV file..."
)
with open(file_path, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
# Detect delimiter if not provided
if delimiter is None:
try:
sample = f.read(1024)
f.seek(0)
dialect = csv.Sniffer().sniff(sample)
delimiter = dialect.delimiter
self.logger.debug(f"Detected CSV delimiter: '{delimiter}'")
except csv.Error:
# Fallback to comma if sniffing fails
f.seek(0)
delimiter = ","
self.logger.debug("Could not detect delimiter, defaulting to ','")
reader = csv.DictReader(f, delimiter=delimiter)
for row in reader:
# Clean up row data
record = {k: v for k, v in row.items() if v}
@@ -316,6 +333,11 @@ class SeedDataManager:
elif "records" in data:
records = data["records"]
else:
self.logger.warning(
f"JSON file {file_path} is a dictionary but contains none of the "
"expected keys: 'entities', 'data', 'records'. "
"Treating entire object as a single record."
)
records = [data]
else:
records = []
+24 -5
View File
@@ -48,6 +48,17 @@ records = manager.load_from_csv(
entity_type="Person"
)
# Load from CSV with custom delimiter
records_pipe = manager.load_from_csv(
"data/entities_pipe.csv",
delimiter="|"
)
# Load from CSV with auto-detection (supported for common delimiters like ;, \t, etc.)
records_auto = manager.load_from_csv(
"data/entities_semicolon.csv"
)
print(f"Loaded {len(records)} records from CSV")
# CSV should have columns like: id, name, type, etc.
@@ -74,6 +85,10 @@ print(f"Loaded {len(records)} records from JSON")
# - List: [{"id": "1", "name": "John"}, ...]
# - Dict with 'entities': {"entities": [...]}
# - Dict with 'data': {"data": [...]}
# - Dict with 'records': {"records": [...]}
#
# Note: Ensure JSON seed files follow these supported top-level structures.
# Unsupported structures will trigger a warning and may be loaded as a single record.
```
### Loading from Database
@@ -553,11 +568,15 @@ manager.export_seed_data("output/custom_seed.json", format="json")
**Algorithm**: Row-by-row CSV processing with metadata injection
1. **File Reading**: Open CSV file with UTF-8 encoding
2. **Header Detection**: Use csv.DictReader() for automatic header detection
3. **Row Processing**: Iterate through rows, convert to dictionaries
4. **Data Cleaning**: Remove empty values, clean whitespace
5. **Metadata Injection**: Add entity_type, relationship_type, source metadata
6. **Type Conversion**: Convert string values to appropriate types
2. **Delimiter Detection**:
- Use provided delimiter if specified
- If not, attempt to auto-detect delimiter using `csv.Sniffer`
- Fallback to comma (`,`) if detection fails
3. **Header Detection**: Use csv.DictReader() for automatic header detection
4. **Row Processing**: Iterate through rows, convert to dictionaries
5. **Data Cleaning**: Remove empty values, clean whitespace
6. **Metadata Injection**: Add entity_type, relationship_type, source metadata
7. **Type Conversion**: Convert string values to appropriate types
**Time Complexity**: O(n) where n = number of rows
**Space Complexity**: O(n) for records storage
@@ -177,7 +177,6 @@ class CoreferenceResolver:
)
raise
<<<<<<< HEAD
def resolve(self, text: str, **options) -> List[CoreferenceChain]:
"""
Resolve coreferences in text (alias for resolve_coreferences).
@@ -190,9 +189,6 @@ class CoreferenceResolver:
list: List of coreference chains
"""
return self.resolve_coreferences(text, **options)
=======
>>>>>>> origin/main
def _extract_mentions(self, text: str) -> List[Mention]:
"""Extract all mentions from text."""
mentions = []
@@ -85,7 +85,6 @@ class Event:
class EventDetector:
"""Event detection and extraction handler."""
<<<<<<< HEAD
def __init__(
self,
event_types: Optional[List[str]] = None,
@@ -96,9 +95,6 @@ class EventDetector:
config=None,
**kwargs
):
=======
def __init__(self, method: Union[str, List[str]] = None, config=None, **kwargs):
>>>>>>> origin/main
"""
Initialize event detector.
@@ -120,15 +116,12 @@ class EventDetector:
self.config.update(kwargs)
self.progress_tracker = get_progress_tracker()
<<<<<<< HEAD
# Store parameters
self.event_types_filter = event_types
self.extract_participants = extract_participants
self.extract_location = extract_location
self.extract_time = extract_time
=======
>>>>>>> origin/main
# Store method for passing to extractors if needed
if method is not None:
self.config["ner_method"] = method
@@ -171,7 +164,6 @@ class EventDetector:
try:
events = []
<<<<<<< HEAD
# Determine which event types to detect
event_patterns_to_use = self.event_patterns
if self.event_types_filter:
@@ -180,24 +172,17 @@ class EventDetector:
if k in self.event_types_filter
}
=======
>>>>>>> origin/main
# Detect events using patterns
self.progress_tracker.update_tracking(
tracking_id, message="Scanning text for event patterns..."
)
<<<<<<< HEAD
for event_type, pattern in event_patterns_to_use.items():
=======
for event_type, pattern in self.event_patterns.items():
>>>>>>> origin/main
for match in re.finditer(pattern, text, re.IGNORECASE):
# Extract surrounding context
start = max(0, match.start() - 50)
end = min(len(text), match.end() + 50)
context = text[start:end]
<<<<<<< HEAD
# Extract participants if enabled
participants = []
if self.extract_participants:
@@ -212,10 +197,6 @@ class EventDetector:
time_info = None
if self.extract_time:
time_info = self._extract_time(context)
=======
# Extract participants (simplified)
participants = self._extract_participants(context)
>>>>>>> origin/main
event = Event(
text=match.group(0),
+7
View File
@@ -311,6 +311,10 @@ def extract_entities_llm(
text: str, provider: str = "openai", model: Optional[str] = None, **kwargs
) -> List[Entity]:
"""LLM-based entity extraction."""
# Support llm_model parameter to disambiguate from ML model
if "llm_model" in kwargs:
model = kwargs.pop("llm_model")
llm = create_provider(provider, model=model, **kwargs)
if not llm.is_available():
@@ -818,6 +822,7 @@ def get_entity_method(method_name: str):
"regex": extract_entities_regex,
"rules": extract_entities_rules,
"ml": extract_entities_ml,
"spacy": extract_entities_ml, # Alias for ml
"huggingface": extract_entities_huggingface,
"llm": extract_entities_llm,
}
@@ -844,6 +849,8 @@ def get_relation_method(method_name: str):
"regex": extract_relations_regex,
"cooccurrence": extract_relations_cooccurrence,
"dependency": extract_relations_dependency,
"ml": extract_relations_dependency, # Alias for dependency
"spacy": extract_relations_dependency, # Alias for dependency
"huggingface": extract_relations_huggingface,
"llm": extract_relations_llm,
}
@@ -101,6 +101,7 @@ class NamedEntityRecognizer:
# Use NERExtractor for actual extraction
ner_config = self.config.get("ner", {})
ner_config["confidence_threshold"] = confidence_threshold
ner_config["min_confidence"] = confidence_threshold
ner_config["merge_overlapping"] = merge_overlapping
if method is not None:
ner_config["method"] = method
+14 -1
View File
@@ -70,7 +70,6 @@ from typing import Any, Dict, List, Optional, Tuple, Union
from ..utils.exceptions import ProcessingError
from ..utils.logging import get_logger
from ..utils.progress_tracker import get_progress_tracker
from .methods import get_entity_method
try:
import spacy
@@ -143,6 +142,19 @@ class NERExtractor:
f"spaCy model {self.model_name} not found. ML method will fallback."
)
def extract(self, text: str, **kwargs) -> List[Entity]:
"""
Alias for extract_entities.
Args:
text: Input text
**kwargs: Extraction options
Returns:
list: List of extracted entities
"""
return self.extract_entities(text, **kwargs)
def extract_entities(self, text: str, **options) -> List[Entity]:
"""
Extract named entities from text.
@@ -164,6 +176,7 @@ class NERExtractor:
)
try:
from .methods import get_entity_method
if not text:
self.progress_tracker.stop_tracking(
tracking_id, status="completed", message="No text provided"
@@ -69,7 +69,6 @@ from typing import Any, Dict, List, Optional, Tuple, Union
from ..utils.exceptions import ProcessingError
from ..utils.logging import get_logger
from ..utils.progress_tracker import get_progress_tracker
from .methods import get_relation_method
from .ner_extractor import Entity
@@ -156,6 +155,20 @@ class RelationExtractor:
}
def extract(self, text: str, entities: List[Entity], **kwargs) -> List[Relation]:
"""
Alias for extract_relations.
Args:
text: Input text
entities: List of entities in the text
**kwargs: Extraction options
Returns:
list: List of extracted relations
"""
return self.extract_relations(text, entities, **kwargs)
def extract_relations(
self, text: str, entities: List[Entity], **options
) -> List[Relation]:
@@ -173,6 +186,8 @@ class RelationExtractor:
Returns:
list: List of extracted relations
"""
from .methods import get_relation_method
tracking_id = self.progress_tracker.start_tracking(
module="semantic_extract",
submodule="RelationExtractor",
@@ -12,10 +12,9 @@ This comprehensive guide demonstrates how to use the semantic extraction module
6. [Coreference Resolution](#coreference-resolution)
7. [Semantic Analysis](#semantic-analysis)
8. [Semantic Networks](#semantic-networks)
9. [Using Methods](#using-methods)
10. [Using Registry](#using-registry)
11. [Configuration](#configuration)
12. [Advanced Examples](#advanced-examples)
9. [Using Registry](#using-registry)
10. [Configuration](#configuration)
11. [Advanced Examples](#advanced-examples)
## Basic Usage
@@ -31,7 +30,7 @@ print(f"Entities: {entities}")
# Extract relations
rel_extractor = RelationExtractor()
relations = rel_extractor.extract_relations(text, entities=entities)
relations = rel_extractor.extract(text, entities=entities)
print(f"Relations: {relations}")
print(f"Extracted {len(entities)} entities and {len(relations)} relations")
@@ -55,33 +54,33 @@ for entity in entities:
### Different Entity Extraction Methods
```python
from semantica.semantic_extract.methods import get_entity_method
from semantica.semantic_extract import NERExtractor
text = "Apple Inc. was founded by Steve Jobs in 1976."
# Pattern-based extraction
pattern_method = get_entity_method("pattern")
entities = pattern_method(text)
extractor = NERExtractor(method="pattern")
entities = extractor.extract(text)
print(f"Pattern method: {len(entities)} entities")
# Regex-based extraction
regex_method = get_entity_method("regex")
entities = regex_method(text)
extractor = NERExtractor(method="regex")
entities = extractor.extract(text)
print(f"Regex method: {len(entities)} entities")
# ML-based extraction (spaCy)
ml_method = get_entity_method("ml")
entities = ml_method(text)
extractor = NERExtractor(method="ml")
entities = extractor.extract(text)
print(f"ML method: {len(entities)} entities")
# HuggingFace model extraction
hf_method = get_entity_method("huggingface")
entities = hf_method(text, model="dslim/bert-base-NER")
extractor = NERExtractor(method="huggingface")
entities = extractor.extract(text, model="dslim/bert-base-NER")
print(f"HuggingFace method: {len(entities)} entities")
# LLM-based extraction
llm_method = get_entity_method("llm")
entities = llm_method(text, provider="openai", model="gpt-4")
extractor = NERExtractor(method="llm")
entities = extractor.extract(text, provider="openai", model="gpt-4")
print(f"LLM method: {len(entities)} entities")
```
@@ -90,13 +89,29 @@ print(f"LLM method: {len(entities)} entities")
```python
from semantica.semantic_extract import NERExtractor
extractor = NERExtractor(method="ml")
# 1. Standard ML (spaCy)
extractor = NERExtractor(method="ml", model="en_core_web_trf")
entities = extractor.extract(text)
# 2. LLM-based extraction
extractor = NERExtractor(
method="llm",
provider="openai",
model="gpt-4",
temperature=0.0
)
entities = extractor.extract(text)
# 3. Regex with custom patterns
extractor = NERExtractor(
method="regex",
patterns={"CODE": r"[A-Z]{3}-\d{3}"}
)
entities = extractor.extract(text)
for entity in entities:
print(f"Entity: {entity.text}")
print(f" Type: {entity.type}")
print(f" Start: {entity.start}, End: {entity.end}")
print(f" Type: {entity.label}")
print(f" Confidence: {entity.confidence}")
```
@@ -129,7 +144,7 @@ from semantica.semantic_extract import RelationExtractor
extractor = RelationExtractor()
text = "Steve Jobs founded Apple Inc. in 1976."
relations = extractor.extract_relations(text, entities=entities)
relations = extractor.extract(text, entities=entities)
for relation in relations:
print(f"{relation.subject} --[{relation.predicate}]--> {relation.object}")
@@ -139,29 +154,29 @@ for relation in relations:
### Different Relation Extraction Methods
```python
from semantica.semantic_extract.methods import get_relation_method
from semantica.semantic_extract import RelationExtractor
text = "Steve Jobs founded Apple Inc."
# Pattern-based extraction
pattern_method = get_relation_method("pattern")
relations = pattern_method(text, entities=entities)
extractor = RelationExtractor(method="pattern")
relations = extractor.extract(text, entities=entities)
# Dependency parsing-based
dependency_method = get_relation_method("dependency")
relations = dependency_method(text, entities=entities)
extractor = RelationExtractor(method="dependency")
relations = extractor.extract(text, entities=entities)
# Co-occurrence based
cooccurrence_method = get_relation_method("cooccurrence")
relations = cooccurrence_method(text, entities=entities)
extractor = RelationExtractor(method="cooccurrence")
relations = extractor.extract(text, entities=entities)
# HuggingFace model
hf_method = get_relation_method("huggingface")
relations = hf_method(text, entities=entities, model="microsoft/DialoGPT-medium")
extractor = RelationExtractor(method="huggingface")
relations = extractor.extract(text, entities=entities, model="microsoft/DialoGPT-medium")
# LLM-based
llm_method = get_relation_method("llm")
relations = llm_method(text, entities=entities, provider="openai")
extractor = RelationExtractor(method="llm")
relations = extractor.extract(text, entities=entities, provider="openai")
```
### Relation Types
@@ -201,25 +216,25 @@ for triple in triples:
### Different Triple Extraction Methods
```python
from semantica.semantic_extract.methods import get_triple_method
from semantica.semantic_extract import TripleExtractor
text = "Apple Inc. was founded by Steve Jobs in 1976."
# Pattern-based
pattern_method = get_triple_method("pattern")
triples = pattern_method(text)
extractor = TripleExtractor(method="pattern")
triples = extractor.extract_triples(text)
# Rules-based
rules_method = get_triple_method("rules")
triples = rules_method(text)
extractor = TripleExtractor(method="rules")
triples = extractor.extract_triples(text)
# HuggingFace model
hf_method = get_triple_method("huggingface")
triples = hf_method(text, model="t5-base")
extractor = TripleExtractor(method="huggingface")
triples = extractor.extract_triples(text, model="t5-base")
# LLM-based
llm_method = get_triple_method("llm")
triples = llm_method(text, provider="openai", model="gpt-4")
extractor = TripleExtractor(method="llm")
triples = extractor.extract_triples(text, provider="openai", model="gpt-4")
```
### RDF Serialization
@@ -462,29 +477,6 @@ print(f"Node: {node.label}")
print(f"Edge: {edge.source} --[{edge.relation}]--> {edge.target}")
```
## Using Methods
### Getting Available Methods
```python
from semantica.semantic_extract.methods import (
get_entity_method,
get_relation_method,
get_triple_method
)
# Get entity extraction method
entity_method = get_entity_method("llm")
entities = entity_method(text, provider="openai")
# Get relation extraction method
relation_method = get_relation_method("dependency")
relations = relation_method(text, entities=entities)
# Get triple extraction method
triple_method = get_triple_method("pattern")
triples = triple_method(text)
```
## Using Registry
@@ -504,9 +496,9 @@ def custom_entity_extraction(text, **kwargs):
method_registry.register("entity", "custom_method", custom_entity_extraction)
# Use custom method
from semantica.semantic_extract.methods import get_entity_method
custom_method = get_entity_method("custom_method")
entities = custom_method(text)
from semantica.semantic_extract import NERExtractor
extractor = NERExtractor(method="custom_method")
entities = extractor.extract(text)
```
### Listing Registered Methods
@@ -70,7 +70,6 @@ from urllib.parse import quote
from ..utils.exceptions import ProcessingError, ValidationError
from ..utils.logging import get_logger
from ..utils.progress_tracker import get_progress_tracker
from .methods import get_triple_method
from .ner_extractor import Entity
from .relation_extractor import Relation
@@ -158,6 +157,8 @@ class TripleExtractor:
Returns:
list: List of extracted triples
"""
from .methods import get_triple_method
tracking_id = self.progress_tracker.start_tracking(
module="semantic_extract",
submodule="TripleExtractor",
+115 -3
View File
@@ -160,6 +160,15 @@ try:
except ImportError:
SEMANTIC_EXTRACT_AVAILABLE = False
# Import specialized chunkers
try:
from .structural_chunker import StructuralChunker
from .sliding_window_chunker import SlidingWindowChunker
SPECIALIZED_CHUNKERS_AVAILABLE = True
except ImportError:
SPECIALIZED_CHUNKERS_AVAILABLE = False
# ============================================================================
# Standard Splitting Methods
@@ -1012,9 +1021,14 @@ def split_relation_aware(
return split_recursive(text, chunk_size=chunk_size, **kwargs)
try:
# Extract entities first (required for relation extraction)
ner_method = kwargs.get("ner_method", "ml")
ner_extractor = NERExtractor(method=ner_method, **kwargs)
entities = ner_extractor.extract(text)
# Extract relations/triples
relation_extractor = RelationExtractor(method=relation_method, **kwargs)
relations = relation_extractor.extract(text)
relations = relation_extractor.extract(text, entities)
# Create triple boundaries (subject, relation, object must be in same chunk)
triple_boundaries = []
@@ -1412,13 +1426,23 @@ def split_hierarchical(
# Fall back to paragraph level
if "paragraph" in levels:
# Remove chunk_size from kwargs to avoid multiple values error
para_kwargs = kwargs.copy()
if "chunk_size" in para_kwargs:
del para_kwargs["chunk_size"]
return split_by_paragraphs(
text, chunk_size=chunk_sizes[0] if chunk_sizes else 1000, **kwargs
text, chunk_size=chunk_sizes[0] if chunk_sizes else 1000, **para_kwargs
)
# Fall back to sentence level
# Remove chunk_size from kwargs to avoid multiple values error
sent_kwargs = kwargs.copy()
if "chunk_size" in sent_kwargs:
del sent_kwargs["chunk_size"]
return split_by_sentences(
text, chunk_size=chunk_sizes[0] if chunk_sizes else 1000, **kwargs
text, chunk_size=chunk_sizes[0] if chunk_sizes else 1000, **sent_kwargs
)
@@ -1515,6 +1539,91 @@ def split_topic_based(
return split_semantic_transformer(text, chunk_size=chunk_size, **kwargs)
def split_structural(
text: str,
max_chunk_size: int = 2000,
respect_headers: bool = True,
respect_sections: bool = True,
**kwargs,
) -> List[Chunk]:
"""
Structure-aware chunking respecting document hierarchy.
Args:
text: Input text
max_chunk_size: Maximum chunk size
respect_headers: Whether to respect heading hierarchy
respect_sections: Whether to respect section boundaries
**kwargs: Additional options
Returns:
List of chunks
"""
if not SPECIALIZED_CHUNKERS_AVAILABLE:
logger.warning(
"StructuralChunker not available, falling back to recursive splitting"
)
return split_recursive(text, chunk_size=max_chunk_size, **kwargs)
try:
chunker = StructuralChunker(
max_chunk_size=max_chunk_size,
respect_headers=respect_headers,
respect_sections=respect_sections,
**kwargs,
)
return chunker.chunk(text, **kwargs)
except Exception as e:
logger.warning(
f"Error in structural splitting: {e}, falling back to recursive splitting"
)
return split_recursive(text, chunk_size=max_chunk_size, **kwargs)
def split_sliding_window(
text: str,
chunk_size: int = 1000,
overlap: int = 200,
stride: Optional[int] = None,
preserve_boundaries: bool = True,
**kwargs,
) -> List[Chunk]:
"""
Sliding window chunking with optional boundary preservation.
Args:
text: Input text
chunk_size: Chunk size in characters
overlap: Overlap size in characters
stride: Stride size (default: chunk_size - overlap)
preserve_boundaries: Whether to preserve word/sentence boundaries
**kwargs: Additional options
Returns:
List of chunks
"""
if not SPECIALIZED_CHUNKERS_AVAILABLE:
logger.warning(
"SlidingWindowChunker not available, falling back to recursive splitting"
)
return split_recursive(
text, chunk_size=chunk_size, chunk_overlap=overlap, **kwargs
)
try:
chunker = SlidingWindowChunker(
chunk_size=chunk_size, overlap=overlap, stride=stride, **kwargs
)
return chunker.chunk(text, preserve_boundaries=preserve_boundaries, **kwargs)
except Exception as e:
logger.warning(
f"Error in sliding window splitting: {e}, falling back to recursive splitting"
)
return split_recursive(
text, chunk_size=chunk_size, chunk_overlap=overlap, **kwargs
)
# ============================================================================
# Method Dispatcher
# ============================================================================
@@ -1542,6 +1651,9 @@ _SPLIT_METHODS = {
"centrality_based": split_centrality_based,
"subgraph": split_subgraph,
"topic_based": split_topic_based,
# Specialized methods
"structural": split_structural,
"sliding_window": split_sliding_window,
}
+3 -3
View File
@@ -209,7 +209,7 @@ chunks = split_entity_aware(
text,
chunk_size=1000,
chunk_overlap=200,
ner_method="llm", # or "spacy", "huggingface"
ner_method="ml", # "ml" (spaCy), "llm", or "pattern"
preserve_entities=True
)
@@ -324,7 +324,7 @@ chunks = table_chunker.chunk(text_with_tables)
entity_chunker = EntityAwareChunker(
chunk_size=1000,
chunk_overlap=200,
ner_method="llm",
ner_method="ml",
preserve_entities=True
)
chunks = entity_chunker.chunk(text)
@@ -408,7 +408,7 @@ chunks6 = split_by_words(text, chunk_size=500, chunk_overlap=50)
# Advanced methods
chunks7 = split_semantic_transformer(text, chunk_size=1000, chunk_overlap=200)
chunks8 = split_llm(text, chunk_size=1000, provider="openai")
chunks9 = split_entity_aware(text, chunk_size=1000, ner_method="llm")
chunks9 = split_entity_aware(text, chunk_size=1000, ner_method="ml")
chunks10 = split_relation_aware(text, chunk_size=1000)
chunks11 = split_graph_based(text, chunk_size=1000)
chunks12 = split_ontology_aware(text, chunk_size=1000)
@@ -1,22 +1,22 @@
"""
Triple Store Module
Triplet Store Module
This module provides comprehensive triple store integration and management
for RDF data storage and querying, supporting multiple triple store backends
This module provides comprehensive triplet store integration and management
for RDF data storage and querying, supporting multiple triplet store backends
with unified interfaces.
Algorithms Used:
Triple Store Management:
Triplet Store Management:
- Store Registration: Store type detection, adapter factory pattern, configuration management, default store selection
- Adapter Pattern: Unified interface for multiple backends (Blazegraph, Jena, RDF4J, Virtuoso), adapter instantiation, backend-specific operation delegation
- Store Selection: Default store resolution, store ID lookup, store validation
CRUD Operations:
- Triple Addition: Single triple insertion, batch triple insertion, triple validation (subject/predicate/object checking, confidence validation), adapter delegation
- Triple Retrieval: Pattern matching (subject/predicate/object filtering), SPARQL query construction, result binding extraction, triple reconstruction
- Triple Deletion: Triple matching, deletion operation delegation, result verification
- Triple Update: Delete-then-add pattern, atomic update operations, conflict detection
- Triplet Addition: Single triplet insertion, batch triplet insertion, triplet validation (subject/predicate/object checking, confidence validation), adapter delegation
- Triplet Retrieval: Pattern matching (subject/predicate/object filtering), SPARQL query construction, result binding extraction, triplet reconstruction
- Triplet Deletion: Triplet matching, deletion operation delegation, result verification
- Triplet Update: Delete-then-add pattern, atomic update operations, conflict detection
Bulk Loading:
- Batch Processing: Chunking algorithm (fixed-size batch creation), batch size optimization, memory management for large datasets
@@ -46,7 +46,7 @@ Store Adapters:
Data Validation:
- Triple Validation: Required field checking (subject, predicate, object), confidence range validation (0-1), URI format validation
- Pre-load Validation: Empty component detection, URI format checking, confidence threshold checking, error/warning categorization
Performance Optimization:
- Batch Size Optimization: Configurable batch size, memory-aware batching, throughput-based optimization
- Connection Pooling: Adapter-level connection management, connection reuse, connection lifecycle management
@@ -55,7 +55,7 @@ Performance Optimization:
Key Features:
- Multi-backend support (Blazegraph, Jena, RDF4J, Virtuoso)
- CRUD operations for RDF triples
- CRUD operations for RDF triplets
- SPARQL query execution and optimization
- Bulk data loading with progress tracking
- Query caching and optimization
@@ -65,41 +65,41 @@ Key Features:
- Configuration management with environment variables and config files
Main Classes:
- TripleManager: Main triple store management coordinator
- TripletManager: Main triplet store management coordinator
- QueryEngine: SPARQL query execution and optimization
- BulkLoader: High-volume data loading
- BlazegraphAdapter: Blazegraph integration adapter
- JenaAdapter: Apache Jena integration adapter
- RDF4JAdapter: Eclipse RDF4J integration adapter
- VirtuosoAdapter: Virtuoso RDF store integration adapter
- TripleStore: Triple store configuration dataclass
- TripletStore: Triplet store configuration dataclass
- QueryResult: Query result representation dataclass
- QueryPlan: Query execution plan dataclass
- LoadProgress: Bulk loading progress dataclass
Convenience Functions:
- register_store: Register triple store wrapper
- add_triple: Add single triple wrapper
- add_triples: Add multiple triples wrapper
- get_triples: Get triples matching pattern wrapper
- delete_triple: Delete triple wrapper
- register_store: Register triplet store wrapper
- add_triple: Add single triplet wrapper
- add_triples: Add multiple triplets wrapper
- get_triples: Get triplets matching pattern wrapper
- delete_triple: Delete triplet wrapper
- execute_query: Execute SPARQL query wrapper
- optimize_query: Optimize SPARQL query wrapper
- bulk_load: Bulk load triples wrapper
- get_triple_store_method: Get triple store method by task and name
- list_available_methods: List registered triple store methods
- bulk_load: Bulk load triplets wrapper
- get_triplet_store_method: Get triplet store method by task and name
- list_available_methods: List registered triplet store methods
Example Usage:
>>> from semantica.triple_store import TripleManager, register_store, add_triple, execute_query
>>> from semantica.triplet_store import TripletManager, register_store, add_triple, execute_query
>>> # Using convenience functions
>>> store = register_store("main", "blazegraph", "http://localhost:9999/blazegraph")
>>> result = add_triple(triple, store_id="main")
>>> query_result = execute_query(sparql_query, store_adapter)
>>> # Using classes directly
>>> manager = TripleManager()
>>> manager = TripletManager()
>>> store = manager.register_store("main", "blazegraph", "http://localhost:9999/blazegraph")
>>> result = manager.add_triple(triple, store_id="main")
>>> from semantica.triple_store import QueryEngine
>>> from semantica.triplet_store import QueryEngine
>>> engine = QueryEngine()
>>> query_result = engine.execute_query(sparql_query, store_adapter)
@@ -109,7 +109,7 @@ License: MIT
from .blazegraph_adapter import BlazegraphAdapter
from .bulk_loader import BulkLoader, LoadProgress
from .config import TripleStoreConfig, triple_store_config
from .config import TripletStoreConfig, triplet_store_config
from .jena_adapter import JenaAdapter
from .methods import (
add_triple,
@@ -117,7 +117,7 @@ from .methods import (
bulk_load,
delete_triple,
execute_query,
get_triple_store_method,
get_triplet_store_method,
get_triples,
list_available_methods,
optimize_query,
@@ -129,13 +129,13 @@ from .methods import (
from .query_engine import QueryEngine, QueryPlan, QueryResult
from .rdf4j_adapter import RDF4JAdapter
from .registry import MethodRegistry, method_registry
from .triple_manager import TripleManager, TripleStore
from .triplet_manager import TripletManager, TripletStore
from .virtuoso_adapter import VirtuosoAdapter
__all__ = [
# Triple management
"TripleManager",
"TripleStore",
"TripletManager",
"TripletStore",
# Store adapters
"BlazegraphAdapter",
"JenaAdapter",
@@ -160,11 +160,11 @@ __all__ = [
"plan_query",
"bulk_load",
"validate_triples",
"get_triple_store_method",
"get_triplet_store_method",
"list_available_methods",
# Configuration and registry
"TripleStoreConfig",
"triple_store_config",
"TripletStoreConfig",
"triplet_store_config",
"MethodRegistry",
"method_registry",
]
@@ -17,7 +17,7 @@ Main Classes:
- BlazegraphAdapter: Main Blazegraph integration adapter
Example Usage:
>>> from semantica.triple_store import BlazegraphAdapter
>>> from semantica.triplet_store import BlazegraphAdapter
>>> adapter = BlazegraphAdapter(endpoint="http://localhost:9999/blazegraph", namespace="kb")
>>> result = adapter.execute_sparql(sparql_query)
>>> load_result = adapter.bulk_load(triples)
@@ -40,7 +40,7 @@ from ..utils.progress_tracker import get_progress_tracker
class BlazegraphAdapter:
"""
Blazegraph triple store adapter.
Blazegraph triplet store adapter.
Blazegraph connection and authentication
SPARQL query execution
@@ -119,7 +119,7 @@ class BlazegraphAdapter:
Query results
"""
tracking_id = self.progress_tracker.start_tracking(
module="triple_store",
module="triplet_store",
submodule="BlazegraphAdapter",
message="Executing SPARQL query on Blazegraph",
)
@@ -1,7 +1,7 @@
"""
Bulk Loader Module
This module provides high-volume data loading capabilities for triple stores,
This module provides high-volume data loading capabilities for triplet stores,
enabling efficient batch processing with progress tracking and error recovery.
Key Features:
@@ -18,7 +18,7 @@ Main Classes:
- LoadProgress: Bulk loading progress representation dataclass
Example Usage:
>>> from semantica.triple_store import BulkLoader
>>> from semantica.triplet_store import BulkLoader
>>> loader = BulkLoader(batch_size=1000, max_retries=3)
>>> progress = loader.load_triples(triples, store_adapter)
>>> print(f"Loaded {progress.loaded_triples}/{progress.total_triples} triples")
@@ -56,7 +56,7 @@ class LoadProgress:
class BulkLoader:
"""
High-volume data loading system for triple stores.
High-volume data loading system for triplet stores.
High-volume data loading strategies
Batch processing and chunking
@@ -104,7 +104,7 @@ class BulkLoader:
Load progress information
"""
tracking_id = self.progress_tracker.start_tracking(
module="triple_store",
module="triplet_store",
submodule="BulkLoader",
message=f"Loading {len(triples)} triples in bulk",
)
@@ -1,14 +1,14 @@
"""
Configuration Management Module for Triple Store
Configuration Management Module for Triplet Store
This module provides centralized configuration management for triple store operations,
This module provides centralized configuration management for triplet store operations,
supporting multiple configuration sources including environment variables, config files,
and programmatic configuration.
Supported Configuration Sources:
- Environment variables: TRIPLE_STORE_DEFAULT_STORE, TRIPLE_STORE_BATCH_SIZE, TRIPLE_STORE_ENABLE_CACHING, etc.
- Environment variables: TRIPLET_STORE_DEFAULT_STORE, TRIPLET_STORE_BATCH_SIZE, TRIPLET_STORE_ENABLE_CACHING, etc.
- Config files: YAML, JSON, TOML formats
- Programmatic: Python API for setting triple store configurations
- Programmatic: Python API for setting triplet store configurations
Algorithms Used:
- Environment Variable Parsing: OS-level environment variable access
@@ -19,7 +19,7 @@ Algorithms Used:
- Dictionary Merging: Deep merge algorithms for configuration updates
Key Features:
- Environment variable support for triple store parameters
- Environment variable support for triplet store parameters
- Config file support (YAML, JSON, TOML formats)
- Programmatic configuration via Python API
- Method-specific configuration management
@@ -27,13 +27,13 @@ Key Features:
- Global config instance for easy access
Main Classes:
- TripleStoreConfig: Main configuration manager class for triple store module
- TripletStoreConfig: Main configuration manager class for triplet store module
Example Usage:
>>> from semantica.triple_store.config import triple_store_config
>>> default_store = triple_store_config.get("default_store", default="main")
>>> triple_store_config.set("default_store", "main")
>>> method_config = triple_store_config.get_method_config("add_triple")
>>> from semantica.triplet_store.config import triplet_store_config
>>> default_store = triplet_store_config.get("default_store", default="main")
>>> triplet_store_config.set("default_store", "main")
>>> method_config = triplet_store_config.get_method_config("add_triple")
"""
import os
@@ -43,8 +43,8 @@ from typing import Any, Dict, Optional
from ..utils.logging import get_logger
class TripleStoreConfig:
"""Configuration manager for triple store module - supports .env files, environment variables, and programmatic config."""
class TripletStoreConfig:
"""Configuration manager for triplet store module - supports .env files, environment variables, and programmatic config."""
def __init__(self, config_file: Optional[str] = None):
"""
@@ -53,7 +53,7 @@ class TripleStoreConfig:
Args:
config_file: Optional path to configuration file (YAML, JSON, or TOML)
"""
self.logger = get_logger("triple_store_config")
self.logger = get_logger("triplet_store_config")
self.config_file = config_file
self._config: Dict[str, Any] = {}
self._method_configs: Dict[str, Dict[str, Any]] = {}
@@ -86,40 +86,40 @@ class TripleStoreConfig:
with open(file_path, "r") as f:
config_data = yaml.safe_load(f)
if config_data and "triple_store" in config_data:
self._config.update(config_data["triple_store"])
if config_data and "triplet_store" in config_data:
self._config.update(config_data["triplet_store"])
elif file_path.suffix == ".json":
import json
with open(file_path, "r") as f:
config_data = json.load(f)
if config_data and "triple_store" in config_data:
self._config.update(config_data["triple_store"])
if config_data and "triplet_store" in config_data:
self._config.update(config_data["triplet_store"])
elif file_path.suffix == ".toml":
import tomli
with open(file_path, "rb") as f:
config_data = tomli.load(f)
if config_data and "triple_store" in config_data:
self._config.update(config_data["triple_store"])
if config_data and "triplet_store" in config_data:
self._config.update(config_data["triplet_store"])
except Exception as e:
self.logger.error(f"Failed to load config file: {e}")
def _load_from_env(self) -> None:
"""Load configuration from environment variables."""
env_mappings = {
"TRIPLE_STORE_DEFAULT_STORE": "default_store",
"TRIPLE_STORE_BATCH_SIZE": "batch_size",
"TRIPLE_STORE_ENABLE_CACHING": "enable_caching",
"TRIPLE_STORE_CACHE_SIZE": "cache_size",
"TRIPLE_STORE_ENABLE_OPTIMIZATION": "enable_optimization",
"TRIPLE_STORE_MAX_RETRIES": "max_retries",
"TRIPLE_STORE_RETRY_DELAY": "retry_delay",
"TRIPLE_STORE_TIMEOUT": "timeout",
"TRIPLE_STORE_BLAZEGRAPH_ENDPOINT": "blazegraph_endpoint",
"TRIPLE_STORE_JENA_ENDPOINT": "jena_endpoint",
"TRIPLE_STORE_RDF4J_ENDPOINT": "rdf4j_endpoint",
"TRIPLE_STORE_VIRTUOSO_ENDPOINT": "virtuoso_endpoint",
"TRIPLET_STORE_DEFAULT_STORE": "default_store",
"TRIPLET_STORE_BATCH_SIZE": "batch_size",
"TRIPLET_STORE_ENABLE_CACHING": "enable_caching",
"TRIPLET_STORE_CACHE_SIZE": "cache_size",
"TRIPLET_STORE_ENABLE_OPTIMIZATION": "enable_optimization",
"TRIPLET_STORE_MAX_RETRIES": "max_retries",
"TRIPLET_STORE_RETRY_DELAY": "retry_delay",
"TRIPLET_STORE_TIMEOUT": "timeout",
"TRIPLET_STORE_BLAZEGRAPH_ENDPOINT": "blazegraph_endpoint",
"TRIPLET_STORE_JENA_ENDPOINT": "jena_endpoint",
"TRIPLET_STORE_RDF4J_ENDPOINT": "rdf4j_endpoint",
"TRIPLET_STORE_VIRTUOSO_ENDPOINT": "virtuoso_endpoint",
}
for env_var, config_key in env_mappings.items():
@@ -238,4 +238,4 @@ class TripleStoreConfig:
# Global configuration instance
triple_store_config = TripleStoreConfig()
triplet_store_config = TripletStoreConfig()
@@ -16,7 +16,7 @@ Main Classes:
- JenaAdapter: Main Jena integration adapter
Example Usage:
>>> from semantica.triple_store import JenaAdapter
>>> from semantica.triplet_store import JenaAdapter
>>> adapter = JenaAdapter(endpoint="http://localhost:3030/ds", dataset="default")
>>> result = adapter.add_triples(triples)
>>> query_result = adapter.execute_sparql(sparql_query)
@@ -47,7 +47,7 @@ except ImportError:
class JenaAdapter:
"""
Apache Jena adapter for triple store operations.
Apache Jena adapter for triplet store operations.
Jena connection and configuration
SPARQL query execution
@@ -129,7 +129,7 @@ class JenaAdapter:
Operation status
"""
tracking_id = self.progress_tracker.start_tracking(
module="triple_store",
module="triplet_store",
submodule="JenaAdapter",
message=f"Adding {len(triples)} triples to Jena model",
)
@@ -1,14 +1,14 @@
"""
Triple Store Methods Module
Triplet Store Methods Module
This module provides all triple store methods as simple, reusable functions for
registering stores, adding triples, querying, and managing triple stores. It supports
This module provides all triplet store methods as simple, reusable functions for
registering stores, adding triples, querying, and managing triplet stores. It supports
multiple approaches and integrates with the method registry for extensibility.
Supported Methods:
Store Registration:
- "default": Default store registration using TripleManager
- "default": Default store registration using TripletManager
- "blazegraph": Blazegraph-specific registration
- "jena": Jena-specific registration
- "rdf4j": RDF4J-specific registration
@@ -78,7 +78,7 @@ Bulk Loading:
- Stream Processing: Iterator-based processing, incremental batch collection
Key Features:
- Multiple triple store operation methods
- Multiple triplet store operation methods
- Store registration with method dispatch
- Method dispatchers with registry support
- Custom method registration capability
@@ -95,11 +95,11 @@ Main Functions:
- optimize_query: Query optimization wrapper
- bulk_load: Bulk loading wrapper
- validate_triples: Triple validation wrapper
- get_triple_store_method: Get triple store method by task and name
- get_triplet_store_method: Get triplet store method by task and name
- list_available_methods: List registered methods
Example Usage:
>>> from semantica.triple_store.methods import register_store, add_triple, execute_query
>>> from semantica.triplet_store.methods import register_store, add_triple, execute_query
>>> store = register_store("main", "blazegraph", "http://localhost:9999/blazegraph", method="default")
>>> result = add_triple(triple, store_id="main", method="default")
>>> query_result = execute_query(sparql_query, store_adapter, method="default")
@@ -109,23 +109,23 @@ from typing import Any, Dict, List, Optional, Union
from ..semantic_extract.triple_extractor import Triple
from .bulk_loader import BulkLoader, LoadProgress
from .config import triple_store_config
from .config import triplet_store_config
from .query_engine import QueryEngine, QueryPlan, QueryResult
from .registry import method_registry
from .triple_manager import TripleManager, TripleStore
from .triplet_manager import TripletManager, TripletStore
# Global manager instances
_global_manager: Optional[TripleManager] = None
_global_manager: Optional[TripletManager] = None
_global_query_engine: Optional[QueryEngine] = None
_global_bulk_loader: Optional[BulkLoader] = None
def _get_manager() -> TripleManager:
"""Get or create global TripleManager instance."""
def _get_manager() -> TripletManager:
"""Get or create global TripletManager instance."""
global _global_manager
if _global_manager is None:
config = triple_store_config.get_all()
_global_manager = TripleManager(config=config)
config = triplet_store_config.get_all()
_global_manager = TripletManager(config=config)
return _global_manager
@@ -133,7 +133,7 @@ def _get_query_engine() -> QueryEngine:
"""Get or create global QueryEngine instance."""
global _global_query_engine
if _global_query_engine is None:
config = triple_store_config.get_all()
config = triplet_store_config.get_all()
_global_query_engine = QueryEngine(config=config)
return _global_query_engine
@@ -142,16 +142,16 @@ def _get_bulk_loader() -> BulkLoader:
"""Get or create global BulkLoader instance."""
global _global_bulk_loader
if _global_bulk_loader is None:
config = triple_store_config.get_all()
config = triplet_store_config.get_all()
_global_bulk_loader = BulkLoader(config=config)
return _global_bulk_loader
def register_store(
store_id: str, store_type: str, endpoint: str, method: str = "default", **options
) -> TripleStore:
) -> TripletStore:
"""
Register a triple store.
Register a triplet store.
Args:
store_id: Store identifier
@@ -321,7 +321,7 @@ def execute_query(
Args:
query: SPARQL query string
store_adapter: Triple store adapter instance
store_adapter: Triplet store adapter instance
method: Query method name (default: "default")
**options: Additional options
@@ -383,7 +383,7 @@ def bulk_load(
Args:
triples: List of triples to load
store_adapter: Triple store adapter instance
store_adapter: Triplet store adapter instance
method: Loading method name (default: "default")
**options: Additional options
@@ -424,9 +424,9 @@ def validate_triples(
return loader.validate_before_load(triples, **options)
def get_triple_store_method(task: str, method_name: str) -> Optional[Any]:
def get_triplet_store_method(task: str, method_name: str) -> Optional[Any]:
"""
Get triple store method by task and name.
Get triplet store method by task and name.
Args:
task: Task type (register, add, get, delete, update, query, optimize, bulk_load, validate)
@@ -440,7 +440,7 @@ def get_triple_store_method(task: str, method_name: str) -> Optional[Any]:
def list_available_methods(task: Optional[str] = None) -> Dict[str, List[str]]:
"""
List all available triple store methods.
List all available triplet store methods.
Args:
task: Optional task type to filter by
@@ -2,7 +2,7 @@
Query Engine Module
This module provides comprehensive SPARQL query execution and optimization
for triple store operations, including query planning, caching, and performance
for triplet store operations, including query planning, caching, and performance
monitoring.
Key Features:
@@ -20,7 +20,7 @@ Main Classes:
- QueryPlan: Query execution plan representation dataclass
Example Usage:
>>> from semantica.triple_store import QueryEngine
>>> from semantica.triplet_store import QueryEngine
>>> engine = QueryEngine(enable_caching=True, enable_optimization=True)
>>> result = engine.execute_query(sparql_query, store_adapter)
>>> plan = engine.plan_query(sparql_query)
@@ -109,7 +109,7 @@ class QueryEngine:
Query result
"""
tracking_id = self.progress_tracker.start_tracking(
module="triple_store",
module="triplet_store",
submodule="QueryEngine",
message="Executing SPARQL query",
)
@@ -16,7 +16,7 @@ Main Classes:
- RDF4JAdapter: Main RDF4J integration adapter
Example Usage:
>>> from semantica.triple_store import RDF4JAdapter
>>> from semantica.triplet_store import RDF4JAdapter
>>> adapter = RDF4JAdapter(endpoint="http://localhost:8080/rdf4j-server", repository_id="repo1")
>>> result = adapter.execute_sparql(sparql_query)
>>> tx_id = adapter.begin_transaction()
@@ -38,7 +38,7 @@ from ..utils.progress_tracker import get_progress_tracker
class RDF4JAdapter:
"""
Eclipse RDF4J adapter for triple store operations.
Eclipse RDF4J adapter for triplet store operations.
RDF4J connection and repository management
SPARQL query execution
@@ -184,7 +184,7 @@ class RDF4JAdapter:
Query results
"""
tracking_id = self.progress_tracker.start_tracking(
module="triple_store",
module="triplet_store",
submodule="RDF4JAdapter",
message="Executing SPARQL query on RDF4J",
)
@@ -250,7 +250,7 @@ class RDF4JAdapter:
Operation status
"""
tracking_id = self.progress_tracker.start_tracking(
module="triple_store",
module="triplet_store",
submodule="RDF4JAdapter",
message=f"Adding {len(triples)} triples to RDF4J repository",
)
@@ -1,11 +1,11 @@
"""
Method Registry Module for Triple Store
Method Registry Module for Triplet Store
This module provides a method registry system for registering custom triple store methods,
enabling extensibility and community contributions to the triple store toolkit.
This module provides a method registry system for registering custom triplet store methods,
enabling extensibility and community contributions to the triplet store toolkit.
Supported Registration Types:
- Method Registry: Register custom triple store methods for:
- Method Registry: Register custom triplet store methods for:
* "register": Store registration methods
* "add": Triple addition methods
* "get": Triple retrieval methods
@@ -24,20 +24,20 @@ Algorithms Used:
- Task-based Organization: Hierarchical organization by task type
Key Features:
- Method registry for custom triple store methods
- Method registry for custom triplet store methods
- Task-based method organization (register, add, get, delete, update, query, optimize, bulk_load, validate)
- Dynamic registration and unregistration
- Easy discovery of available methods
- Support for community-contributed extensions
Main Classes:
- MethodRegistry: Registry for custom triple store methods
- MethodRegistry: Registry for custom triplet store methods
Global Instances:
- method_registry: Global method registry instance
Example Usage:
>>> from semantica.triple_store.registry import method_registry
>>> from semantica.triplet_store.registry import method_registry
>>> method_registry.register("add", "custom_method", custom_add_function)
>>> available = method_registry.list_all("add")
"""
@@ -46,7 +46,7 @@ from typing import Any, Callable, Dict, List, Optional
class MethodRegistry:
"""Registry for custom triple store methods."""
"""Registry for custom triplet store methods."""
def __init__(self):
"""Initialize method registry."""
@@ -1,25 +1,25 @@
"""
Triple Manager Module
Triplet Manager Module
This module provides comprehensive CRUD operations for RDF triples and triple
store management, enabling unified access to multiple triple store backends
This module provides comprehensive CRUD operations for RDF triplets and triplet
store management, enabling unified access to multiple triplet store backends
through a common interface.
Key Features:
- CRUD operations for RDF triples
- CRUD operations for RDF triplets
- Multi-store management and registration
- Batch operations and bulk loading
- Triple validation and consistency
- Triplet validation and consistency
- Store adapter pattern
- Error handling and recovery
Main Classes:
- TripleManager: Main triple store management coordinator
- TripleStore: Triple store configuration dataclass
- TripletManager: Main triplet store management coordinator
- TripletStore: Triplet store configuration dataclass
Example Usage:
>>> from semantica.triple_store import TripleManager
>>> manager = TripleManager()
>>> from semantica.triplet_store import TripletManager
>>> manager = TripletManager()
>>> store = manager.register_store("main", "blazegraph", "http://localhost:9999/blazegraph")
>>> result = manager.add_triple(triple, store_id="main")
>>> triples = manager.get_triple(subject="http://example.org/entity1")
@@ -39,8 +39,8 @@ from ..utils.progress_tracker import get_progress_tracker
@dataclass
class TripleStore:
"""Triple store configuration."""
class TripletStore:
"""Triplet store configuration."""
store_id: str
store_type: str # "blazegraph", "jena", "rdf4j", "virtuoso"
@@ -49,9 +49,9 @@ class TripleStore:
connected: bool = False
class TripleManager:
class TripletManager:
"""
Triple store management system.
Triplet store management system.
CRUD operations for RDF triples
Batch operations and bulk loading
@@ -63,26 +63,26 @@ class TripleManager:
def __init__(self, config: Optional[Dict[str, Any]] = None, **kwargs):
"""
Initialize triple manager.
Initialize triplet manager.
Args:
config: Configuration dictionary
**kwargs: Additional configuration options:
- default_store: Default triple store to use
- default_store: Default triplet store to use
"""
self.logger = get_logger("triple_manager")
self.logger = get_logger("triplet_manager")
self.config = config or {}
self.config.update(kwargs)
self.progress_tracker = get_progress_tracker()
self.stores: Dict[str, TripleStore] = {}
self.stores: Dict[str, TripletStore] = {}
self.default_store_id = self.config.get("default_store")
def register_store(
self, store_id: str, store_type: str, endpoint: str, **config
) -> TripleStore:
) -> TripletStore:
"""
Register a triple store.
Register a triplet store.
Args:
store_id: Store identifier
@@ -93,7 +93,7 @@ class TripleManager:
Returns:
Registered store
"""
store = TripleStore(
store = TripletStore(
store_id=store_id, store_type=store_type, endpoint=endpoint, config=config
)
@@ -102,7 +102,7 @@ class TripleManager:
if not self.default_store_id:
self.default_store_id = store_id
self.logger.info(f"Registered triple store: {store_id} ({store_type})")
self.logger.info(f"Registered triplet store: {store_id} ({store_type})")
return store
@@ -158,8 +158,8 @@ class TripleManager:
Operation status
"""
tracking_id = self.progress_tracker.start_tracking(
module="triple_store",
submodule="TripleManager",
module="triplet_store",
submodule="TripletManager",
message=f"Adding {len(triples)} triples to store",
)
@@ -301,7 +301,7 @@ class TripleManager:
return True
def _get_store(self, store_id: Optional[str] = None) -> TripleStore:
def _get_store(self, store_id: Optional[str] = None) -> TripletStore:
"""Get store by ID."""
store_id = store_id or self.default_store_id
@@ -313,7 +313,7 @@ class TripleManager:
return self.stores[store_id]
def _get_adapter(self, store: TripleStore) -> Any:
def _get_adapter(self, store: TripletStore) -> Any:
"""Get adapter for store type."""
store_type = store.store_type.lower()
@@ -336,7 +336,7 @@ class TripleManager:
else:
raise ValidationError(f"Unsupported store type: {store_type}")
def get_store(self, store_id: str) -> Optional[TripleStore]:
def get_store(self, store_id: str) -> Optional[TripletStore]:
"""Get store by ID."""
return self.stores.get(store_id)
@@ -1,6 +1,6 @@
# Triple Store Module Usage Guide
# Triplet Store Module Usage Guide
This comprehensive guide demonstrates how to use the triple store module for RDF data storage and querying, supporting multiple triple store backends (Blazegraph, Jena, RDF4J, Virtuoso) with unified interfaces, SPARQL query execution, bulk loading, and query optimization.
This comprehensive guide demonstrates how to use the triplet store module for RDF data storage and querying, supporting multiple triplet store backends (Blazegraph, Jena, RDF4J, Virtuoso) with unified interfaces, SPARQL query execution, bulk loading, and query optimization.
## Table of Contents
@@ -17,14 +17,14 @@ This comprehensive guide demonstrates how to use the triple store module for RDF
## Basic Usage
### Using TripleManager
### Using TripletManager
```python
from semantica.triple_store import TripleManager
from semantica.triplet_store import TripletManager
from semantica.semantic_extract.triple_extractor import Triple
# Create triple manager
manager = TripleManager()
# Create triplet manager
manager = TripletManager()
# Register a store
store = manager.register_store("main", "blazegraph", "http://localhost:9999/blazegraph")
@@ -44,7 +44,7 @@ print(f"Triple added: {result['success']}")
### Using Convenience Functions
```python
from semantica.triple_store import register_store, add_triple, get_triples, execute_query
from semantica.triplet_store import register_store, add_triple, get_triples, execute_query
from semantica.semantic_extract.triple_extractor import Triple
# Register store
@@ -66,7 +66,7 @@ print(f"Found {len(triples)} triples")
### Using QueryEngine
```python
from semantica.triple_store import QueryEngine, BlazegraphAdapter
from semantica.triplet_store import QueryEngine, BlazegraphAdapter
# Create query engine
engine = QueryEngine(enable_caching=True, enable_optimization=True)
@@ -87,9 +87,9 @@ print(f"Execution time: {result.execution_time:.2f}s")
### Registering a Store
```python
from semantica.triple_store import TripleManager
from semantica.triplet_store import TripletManager
manager = TripleManager()
manager = TripletManager()
# Register Blazegraph store
blazegraph_store = manager.register_store(
@@ -126,7 +126,7 @@ virtuoso_store = manager.register_store(
### Using Convenience Function
```python
from semantica.triple_store import register_store
from semantica.triplet_store import register_store
# Register store using convenience function
store = register_store(
@@ -143,9 +143,9 @@ print(f"Store type: {store.store_type}")
### Multiple Stores
```python
from semantica.triple_store import TripleManager
from semantica.triplet_store import TripletManager
manager = TripleManager()
manager = TripletManager()
# Register multiple stores
manager.register_store("primary", "blazegraph", "http://localhost:9999/blazegraph")
@@ -165,10 +165,10 @@ print(f"Store endpoint: {store.endpoint}")
### Adding Triples
```python
from semantica.triple_store import TripleManager
from semantica.triplet_store import TripletManager
from semantica.semantic_extract.triple_extractor import Triple
manager = TripleManager()
manager = TripletManager()
manager.register_store("main", "blazegraph", "http://localhost:9999/blazegraph")
# Add single triple
@@ -194,9 +194,9 @@ print(f"Added {result['total_triples']} triples in {result['batches']} batches")
### Retrieving Triples
```python
from semantica.triple_store import TripleManager
from semantica.triplet_store import TripletManager
manager = TripleManager()
manager = TripletManager()
manager.register_store("main", "blazegraph", "http://localhost:9999/blazegraph")
# Get all triples for a subject
@@ -225,10 +225,10 @@ triples = manager.get_triple(
### Deleting Triples
```python
from semantica.triple_store import TripleManager
from semantica.triplet_store import TripletManager
from semantica.semantic_extract.triple_extractor import Triple
manager = TripleManager()
manager = TripletManager()
manager.register_store("main", "blazegraph", "http://localhost:9999/blazegraph")
# Delete triple
@@ -244,10 +244,10 @@ print(f"Deleted: {result['success']}")
### Updating Triples
```python
from semantica.triple_store import TripleManager
from semantica.triplet_store import TripletManager
from semantica.semantic_extract.triple_extractor import Triple
manager = TripleManager()
manager = TripletManager()
manager.register_store("main", "blazegraph", "http://localhost:9999/blazegraph")
# Update triple (delete old, add new)
@@ -270,7 +270,7 @@ print(f"Updated: {result['success']}")
### Basic Query Execution
```python
from semantica.triple_store import QueryEngine, BlazegraphAdapter
from semantica.triplet_store import QueryEngine, BlazegraphAdapter
# Create query engine
engine = QueryEngine(enable_caching=True)
@@ -298,7 +298,7 @@ for binding in result.bindings[:5]:
### Using Convenience Function
```python
from semantica.triple_store import execute_query, BlazegraphAdapter
from semantica.triplet_store import execute_query, BlazegraphAdapter
adapter = BlazegraphAdapter(endpoint="http://localhost:9999/blazegraph")
@@ -311,7 +311,7 @@ print(f"Found {len(result.bindings)} results")
### Query Result Processing
```python
from semantica.triple_store import QueryEngine, BlazegraphAdapter
from semantica.triplet_store import QueryEngine, BlazegraphAdapter
engine = QueryEngine()
adapter = BlazegraphAdapter(endpoint="http://localhost:9999/blazegraph")
@@ -332,7 +332,7 @@ print(f"Metadata: {result.metadata}")
### Query Caching
```python
from semantica.triple_store import QueryEngine, BlazegraphAdapter
from semantica.triplet_store import QueryEngine, BlazegraphAdapter
# Enable caching
engine = QueryEngine(enable_caching=True, cache_size=1000)
@@ -357,7 +357,7 @@ engine.clear_cache()
### Basic Query Optimization
```python
from semantica.triple_store import QueryEngine
from semantica.triplet_store import QueryEngine
engine = QueryEngine(enable_optimization=True)
@@ -377,7 +377,7 @@ print(f"Optimized query:\n{optimized}")
### Query Planning
```python
from semantica.triple_store import QueryEngine
from semantica.triplet_store import QueryEngine
engine = QueryEngine(enable_optimization=True)
@@ -403,7 +403,7 @@ print(f"Execution steps: {plan.execution_steps}")
### Query Statistics
```python
from semantica.triple_store import QueryEngine, BlazegraphAdapter
from semantica.triplet_store import QueryEngine, BlazegraphAdapter
engine = QueryEngine(enable_caching=True)
adapter = BlazegraphAdapter(endpoint="http://localhost:9999/blazegraph")
@@ -427,7 +427,7 @@ print(f"Cache size: {stats['cache_size']}")
### Basic Bulk Loading
```python
from semantica.triple_store import BulkLoader, BlazegraphAdapter
from semantica.triplet_store import BulkLoader, BlazegraphAdapter
from semantica.semantic_extract.triple_extractor import Triple
# Create bulk loader
@@ -455,7 +455,7 @@ print(f"Throughput: {progress.metadata.get('throughput', 0):.0f} triples/sec")
### Progress Tracking
```python
from semantica.triple_store import BulkLoader, BlazegraphAdapter, LoadProgress
from semantica.triplet_store import BulkLoader, BlazegraphAdapter, LoadProgress
from semantica.semantic_extract.triple_extractor import Triple
loader = BulkLoader(batch_size=1000)
@@ -476,7 +476,7 @@ progress = loader.load_triples(triples, adapter, progress_callback=progress_call
### Pre-load Validation
```python
from semantica.triple_store import BulkLoader
from semantica.triplet_store import BulkLoader
from semantica.semantic_extract.triple_extractor import Triple
loader = BulkLoader()
@@ -501,7 +501,7 @@ print(f"Valid triples: {validation['valid_triples']}/{validation['total_triples'
### Stream-based Loading
```python
from semantica.triple_store import BulkLoader, BlazegraphAdapter
from semantica.triplet_store import BulkLoader, BlazegraphAdapter
from semantica.semantic_extract.triple_extractor import Triple
loader = BulkLoader(batch_size=1000)
@@ -522,7 +522,7 @@ print(f"Loaded {progress.loaded_triples} triples from stream")
### Blazegraph Adapter
```python
from semantica.triple_store import BlazegraphAdapter
from semantica.triplet_store import BlazegraphAdapter
from semantica.semantic_extract.triple_extractor import Triple
# Create Blazegraph adapter
@@ -548,7 +548,7 @@ print(f"Found {len(result['bindings'])} results")
### Jena Adapter
```python
from semantica.triple_store import JenaAdapter
from semantica.triplet_store import JenaAdapter
from semantica.semantic_extract.triple_extractor import Triple
# Create Jena adapter (in-memory)
@@ -575,7 +575,7 @@ print(turtle)
### RDF4J Adapter
```python
from semantica.triple_store import RDF4JAdapter
from semantica.triplet_store import RDF4JAdapter
from semantica.semantic_extract.triple_extractor import Triple
# Create RDF4J adapter
@@ -594,7 +594,7 @@ result = adapter.add_triples(triples)
### Virtuoso Adapter
```python
from semantica.triple_store import VirtuosoAdapter
from semantica.triplet_store import VirtuosoAdapter
from semantica.semantic_extract.triple_extractor import Triple
# Create Virtuoso adapter
@@ -613,7 +613,7 @@ result = adapter.add_triples(triples)
## Algorithms and Methods
### Triple Store Management Algorithms
### Triplet Store Management Algorithms
#### Store Registration
**Algorithm**: Store type detection and adapter factory pattern
@@ -783,9 +783,9 @@ cost = engine._estimate_query_cost(query)
### Methods
#### TripleManager Methods
#### TripletManager Methods
- `register_store(store_id, store_type, endpoint, **config)`: Register triple store
- `register_store(store_id, store_type, endpoint, **config)`: Register triplet store
- `add_triple(triple, store_id, **options)`: Add single triple
- `add_triples(triples, store_id, **options)`: Add multiple triples
- `get_triple(subject, predicate, object, store_id, **options)`: Get triples matching pattern
@@ -824,14 +824,14 @@ cost = engine._estimate_query_cost(query)
## Dataclasses
### TripleStore
### TripletStore
Configuration dataclass for triple store instances.
Configuration dataclass for triplet store instances.
```python
from semantica.triple_store import TripleStore
from semantica.triplet_store import TripletStore
store = TripleStore(
store = TripletStore(
store_id="main",
store_type="blazegraph",
endpoint="http://localhost:9999/blazegraph/sparql",
@@ -856,7 +856,7 @@ print(f"Type: {store.store_type}")
Query execution result dataclass.
```python
from semantica.triple_store import QueryEngine, QueryResult
from semantica.triplet_store import QueryEngine, QueryResult
engine = QueryEngine()
result: QueryResult = engine.execute_query(query, adapter)
@@ -877,7 +877,7 @@ print(f"Execution time: {result.execution_time:.2f}s")
Query execution plan dataclass.
```python
from semantica.triple_store import QueryEngine, QueryPlan
from semantica.triplet_store import QueryEngine, QueryPlan
engine = QueryEngine(enable_optimization=True)
plan: QueryPlan = engine.plan_query(query)
@@ -897,38 +897,38 @@ print(f"Execution steps: {plan.execution_steps}")
### Environment Variables
```bash
# Triple store configuration
export TRIPLE_STORE_DEFAULT_STORE=main
export TRIPLE_STORE_BATCH_SIZE=1000
export TRIPLE_STORE_ENABLE_CACHING=true
export TRIPLE_STORE_CACHE_SIZE=1000
export TRIPLE_STORE_ENABLE_OPTIMIZATION=true
export TRIPLE_STORE_MAX_RETRIES=3
export TRIPLE_STORE_RETRY_DELAY=1.0
export TRIPLE_STORE_TIMEOUT=30
# Triplet store configuration
export TRIPLET_STORE_DEFAULT_STORE=main
export TRIPLET_STORE_BATCH_SIZE=1000
export TRIPLET_STORE_ENABLE_CACHING=true
export TRIPLET_STORE_CACHE_SIZE=1000
export TRIPLET_STORE_ENABLE_OPTIMIZATION=true
export TRIPLET_STORE_MAX_RETRIES=3
export TRIPLET_STORE_RETRY_DELAY=1.0
export TRIPLET_STORE_TIMEOUT=30
# Store endpoints
export TRIPLE_STORE_BLAZEGRAPH_ENDPOINT=http://localhost:9999/blazegraph
export TRIPLE_STORE_JENA_ENDPOINT=http://localhost:3030/ds
export TRIPLE_STORE_RDF4J_ENDPOINT=http://localhost:8080/rdf4j-server
export TRIPLE_STORE_VIRTUOSO_ENDPOINT=http://localhost:8890/sparql
export TRIPLET_STORE_BLAZEGRAPH_ENDPOINT=http://localhost:9999/blazegraph
export TRIPLET_STORE_JENA_ENDPOINT=http://localhost:3030/ds
export TRIPLET_STORE_RDF4J_ENDPOINT=http://localhost:8080/rdf4j-server
export TRIPLET_STORE_VIRTUOSO_ENDPOINT=http://localhost:8890/sparql
```
### Programmatic Configuration
```python
from semantica.triple_store.config import triple_store_config
from semantica.triplet_store.config import triplet_store_config
# Get configuration
batch_size = triple_store_config.get("batch_size", default=1000)
enable_caching = triple_store_config.get("enable_caching", default=True)
batch_size = triplet_store_config.get("batch_size", default=1000)
enable_caching = triplet_store_config.get("enable_caching", default=True)
# Set configuration
triple_store_config.set("batch_size", 2000)
triple_store_config.set("enable_caching", False)
triplet_store_config.set("batch_size", 2000)
triplet_store_config.set("enable_caching", False)
# Update with dictionary
triple_store_config.update({
triplet_store_config.update({
"batch_size": 2000,
"enable_caching": True,
"cache_size": 2000
@@ -939,7 +939,7 @@ triple_store_config.update({
```yaml
# config.yaml
triple_store:
triplet_store:
default_store: main
batch_size: 1000
enable_caching: true
@@ -956,11 +956,11 @@ triple_store:
## Advanced Examples
### Complete Triple Store Pipeline
### Complete Triplet Store Pipeline
```python
from semantica.triple_store import (
TripleManager,
from semantica.triplet_store import (
TripletManager,
QueryEngine,
BulkLoader,
register_store,
@@ -980,7 +980,7 @@ triples = [
result = add_triples(triples, store_id="main", batch_size=100)
# 3. Execute queries
from semantica.triple_store import BlazegraphAdapter
from semantica.triplet_store import BlazegraphAdapter
adapter = BlazegraphAdapter(endpoint="http://localhost:9999/blazegraph")
query = "SELECT ?s ?p ?o WHERE { ?s ?p ?o } LIMIT 10"
query_result = execute_query(query, adapter)
@@ -992,10 +992,10 @@ print(f"Query returned {len(query_result.bindings)} results")
### Multi-Store Operations
```python
from semantica.triple_store import TripleManager
from semantica.triplet_store import TripletManager
from semantica.semantic_extract.triple_extractor import Triple
manager = TripleManager()
manager = TripletManager()
# Register multiple stores
manager.register_store("primary", "blazegraph", "http://localhost:9999/blazegraph")
@@ -1012,7 +1012,7 @@ manager.add_triple(triple, store_id="backup")
### Query Optimization Workflow
```python
from semantica.triple_store import QueryEngine, BlazegraphAdapter
from semantica.triplet_store import QueryEngine, BlazegraphAdapter
engine = QueryEngine(enable_optimization=True, enable_caching=True)
adapter = BlazegraphAdapter(endpoint="http://localhost:9999/blazegraph")
@@ -1040,7 +1040,7 @@ print(f"Optimized: {result.metadata.get('optimized', False)}")
### Bulk Loading with Validation
```python
from semantica.triple_store import BulkLoader, BlazegraphAdapter
from semantica.triplet_store import BulkLoader, BlazegraphAdapter
from semantica.semantic_extract.triple_extractor import Triple
loader = BulkLoader(batch_size=1000, max_retries=3)
@@ -1066,22 +1066,22 @@ else:
### Custom Method Registration
```python
from semantica.triple_store.registry import method_registry
from semantica.triple_store import add_triple
from semantica.triplet_store.registry import method_registry
from semantica.triplet_store import add_triple
# Register custom add method
def custom_add_triple(triple, store_id=None, **options):
# Custom logic
print(f"Custom add: {triple.subject}")
# Call default implementation
from semantica.triple_store.methods import _get_manager
from semantica.triplet_store.methods import _get_manager
manager = _get_manager()
return manager.add_triple(triple, store_id=store_id, **options)
method_registry.register("add", "custom", custom_add_triple)
# Use custom method
from semantica.triple_store.methods import add_triple
from semantica.triplet_store.methods import add_triple
result = add_triple(triple, store_id="main", method="custom")
```
@@ -16,7 +16,7 @@ Main Classes:
- VirtuosoAdapter: Main Virtuoso integration adapter
Example Usage:
>>> from semantica.triple_store import VirtuosoAdapter
>>> from semantica.triplet_store import VirtuosoAdapter
>>> adapter = VirtuosoAdapter(endpoint="http://localhost:8890/sparql", username="dba", password="dba")
>>> result = adapter.execute_sparql(sparql_query)
>>> load_result = adapter.bulk_load(triples, graph="http://example.org/graph")
@@ -147,7 +147,7 @@ class VirtuosoAdapter:
Query results
"""
tracking_id = self.progress_tracker.start_tracking(
module="triple_store",
module="triplet_store",
submodule="VirtuosoAdapter",
message="Executing SPARQL query on Virtuoso",
)
@@ -240,7 +240,7 @@ class VirtuosoAdapter:
Load status
"""
tracking_id = self.progress_tracker.start_tracking(
module="triple_store",
module="triplet_store",
submodule="VirtuosoAdapter",
message=f"Bulk loading {len(triples)} triples to Virtuoso",
)
-1
View File
@@ -71,7 +71,6 @@ SUPPORTED_RDF_FORMATS = ["turtle", "rdfxml", "jsonld", "n3", "ntriples"]
# Supported Vector Store Backends
SUPPORTED_VECTOR_STORES = [
"faiss",
"pinecone",
"weaviate",
"qdrant",
"milvus",
+5 -5
View File
@@ -121,7 +121,7 @@ class ConsoleProgressDisplay(ProgressDisplay):
"semantic_extract": "🎯",
"seed": "🌱",
"split": "✂️",
"triple_store": "🗄️",
"triplet_store": "🗄️",
"vector_store": "📊",
"export": "💾",
"reasoning": "🤔",
@@ -176,7 +176,7 @@ class ConsoleProgressDisplay(ProgressDisplay):
"semantic_extract": "is extracting",
"seed": "is seeding",
"split": "is splitting",
"triple_store": "is storing",
"triplet_store": "is storing",
"vector_store": "is indexing",
"export": "is exporting",
"reasoning": "is reasoning",
@@ -352,7 +352,7 @@ class JupyterProgressDisplay(ProgressDisplay):
"semantic_extract": "🎯",
"seed": "🌱",
"split": "✂️",
"triple_store": "🗄️",
"triplet_store": "🗄️",
"vector_store": "📊",
"export": "💾",
"reasoning": "🤔",
@@ -405,7 +405,7 @@ class JupyterProgressDisplay(ProgressDisplay):
"semantic_extract": "is extracting",
"seed": "is seeding",
"split": "is splitting",
"triple_store": "is storing",
"triplet_store": "is storing",
"vector_store": "is indexing",
"export": "is exporting",
"reasoning": "is reasoning",
@@ -901,7 +901,7 @@ class ProgressTracker:
"semantic_extract": "🎯",
"seed": "🌱",
"split": "✂️",
"triple_store": "🗄️",
"triplet_store": "🗄️",
"vector_store": "📊",
"export": "💾",
"reasoning": "🤔",
+21 -28
View File
@@ -3,7 +3,7 @@ Vector Store Management Module
This module provides comprehensive vector storage and retrieval capabilities for the
Semantica framework, including support for multiple vector store backends (FAISS,
Pinecone, Weaviate, Qdrant, Milvus), hybrid search combining vector similarity and
Weaviate, Qdrant, Milvus), hybrid search combining vector similarity and
metadata filtering, metadata management, and namespace isolation.
Algorithms Used:
@@ -50,25 +50,30 @@ Namespace Management:
Adapter Pattern:
- FAISS Adapter: Local vector storage, FAISS index management, index persistence (save/load), batch operations, multiple index types support
- Pinecone Adapter: Cloud vector database integration, HTTP API communication, index management, upsert operations, query operations, metadata filtering
- Weaviate Adapter: GraphQL-based queries, schema management, object-oriented storage, rich metadata support, batch operations
- Qdrant Adapter: REST API communication, collection management, vector operations, payload (metadata) filtering, batch operations
- Milvus Adapter: gRPC communication, collection management, vector operations, metadata filtering, batch operations
- Unified Interface: Common interface for all adapters, backend-specific operation delegation, adapter factory pattern, connection management
- Weaviate Adapter: Schema-aware storage, GraphQL query support, object-oriented data model, batch operations, schema management
- Qdrant Adapter: Point-based storage, payload filtering, collection management, optimized search, batch operations
- Milvus Adapter: Scalable vector database, collection management, partitioning, complex querying, index building
Batch Operations:
- Batch Vector Operations: Chunking algorithm (fixed-size batch creation), batch processing, progress tracking, error handling per batch, retry mechanism
- Batch Indexing: Batch vector addition to index, incremental index updates, batch index training, batch index optimization
- Batch Search: Batch query processing, parallel search execution (when supported), result aggregation, batch result formatting
Supported Backends:
- FAISS: In-memory/local disk (Facebook AI Similarity Search)
- Weaviate: Cloud/Self-hosted (Schema-aware vector database)
- Qdrant: Cloud/Self-hosted (Vector database for the next generation of AI)
- Milvus: Cloud/Self-hosted (Highly scalable vector database)
- InMemory: Simple list-based storage for testing/small datasets
Performance Optimization:
- Vector Normalization: L2 normalization for cosine similarity, normalization caching, batch normalization
- Index Optimization: Index parameter tuning, index rebuilding for better performance, memory optimization, search speed optimization
- Caching: Query result caching, vector caching, metadata caching, cache invalidation strategies
- Parallel Processing: Batch-level parallelization, multi-threaded search (when supported), concurrent index operations
Configuration:
- Environment variables (SEMANTICA_VECTOR_STORE_*)
- Configuration files (yaml/json)
- Runtime configuration via VectorStoreConfig
Dependencies:
- faiss-cpu (or faiss-gpu)
- weaviate-client
- qdrant-client
- pymilvus
Key Features:
- Multi-backend vector store support (FAISS, Pinecone, Weaviate, Qdrant, Milvus)
- Multi-backend vector store support (FAISS, Weaviate, Qdrant, Milvus)
- Vector indexing and similarity search
- Metadata indexing and filtering
- Hybrid search combining vector and metadata queries
@@ -84,7 +89,6 @@ Main Classes:
- VectorRetriever: Vector retrieval and similarity search
- VectorManager: Vector store management and operations
- FAISSAdapter: FAISS integration for local vector storage
- PineconeAdapter: Pinecone cloud vector database integration
- WeaviateAdapter: Weaviate vector database integration
- QdrantAdapter: Qdrant vector database integration
- MilvusAdapter: Milvus vector database integration
@@ -141,12 +145,6 @@ from .methods import (
)
from .milvus_adapter import MilvusAdapter, MilvusClient, MilvusCollection, MilvusSearch
from .namespace_manager import Namespace, NamespaceManager
from .pinecone_adapter import (
PineconeAdapter,
PineconeIndex,
PineconeMetadata,
PineconeQuery,
)
from .qdrant_adapter import QdrantAdapter, QdrantClient, QdrantCollection, QdrantSearch
from .registry import MethodRegistry, method_registry
from .vector_store import VectorIndexer, VectorManager, VectorRetriever, VectorStore
@@ -168,11 +166,6 @@ __all__ = [
"FAISSIndex",
"FAISSSearch",
"FAISSIndexBuilder",
# Pinecone
"PineconeAdapter",
"PineconeIndex",
"PineconeQuery",
"PineconeMetadata",
# Weaviate
"WeaviateAdapter",
"WeaviateClient",
-2
View File
@@ -116,8 +116,6 @@ class VectorStoreConfig:
"VECTOR_STORE_ENABLE_HYBRID_SEARCH": "enable_hybrid_search",
"VECTOR_STORE_NAMESPACE": "default_namespace",
"VECTOR_STORE_FAISS_INDEX_TYPE": "faiss_index_type",
"VECTOR_STORE_PINECONE_API_KEY": "pinecone_api_key",
"VECTOR_STORE_PINECONE_ENVIRONMENT": "pinecone_environment",
"VECTOR_STORE_WEAVIATE_URL": "weaviate_url",
"VECTOR_STORE_QDRANT_URL": "qdrant_url",
"VECTOR_STORE_MILVUS_HOST": "milvus_host",
-510
View File
@@ -1,510 +0,0 @@
"""
Pinecone Adapter Module
This module provides Pinecone cloud vector database integration for vector storage
and similarity search in the Semantica framework, supporting serverless and pod-based
deployments with namespace isolation and metadata filtering.
Key Features:
- Cloud-based vector storage and retrieval
- Serverless and pod-based index specifications
- Namespace isolation for multi-tenant support
- Metadata filtering and querying
- Batch upsert and query operations
- Index statistics and monitoring
- Optional dependency handling
Main Classes:
- PineconeAdapter: Main Pinecone adapter for cloud vector operations
- PineconeIndex: Pinecone index wrapper with operations
- PineconeQuery: Pinecone query builder and executor
- PineconeMetadata: Metadata validation and sanitization
Example Usage:
>>> from semantica.vector_store import PineconeAdapter
>>> adapter = PineconeAdapter(api_key="your-api-key")
>>> adapter.connect()
>>> index = adapter.create_index("my-index", dimension=768, metric="cosine")
>>> adapter.upsert_vectors(vectors, ids, metadata, namespace="docs")
>>> results = adapter.query_vectors(query_vector, top_k=10, namespace="docs")
>>> stats = adapter.get_stats()
Author: Semantica Contributors
License: MIT
"""
from typing import Any, Dict, List, Optional, Union
import numpy as np
from ..utils.exceptions import ProcessingError, ValidationError
from ..utils.logging import get_logger
from ..utils.progress_tracker import get_progress_tracker
# Optional Pinecone import
try:
import pinecone
from pinecone import Pinecone, PodSpec, ServerlessSpec
PINECONE_AVAILABLE = True
except ImportError:
PINECONE_AVAILABLE = False
pinecone = None
Pinecone = None
ServerlessSpec = None
PodSpec = None
class PineconeIndex:
"""Pinecone index wrapper."""
def __init__(self, index: Any, index_name: str):
"""Initialize Pinecone index wrapper."""
self.index = index
self.index_name = index_name
self.logger = get_logger("pinecone_index")
def upsert_vectors(
self, vectors: List[Dict[str, Any]], namespace: Optional[str] = None, **options
) -> Dict[str, Any]:
"""Upsert vectors to index."""
if not PINECONE_AVAILABLE:
raise ProcessingError("Pinecone not available")
try:
response = self.index.upsert(
vectors=vectors, namespace=namespace, **options
)
return response
except Exception as e:
raise ProcessingError(f"Failed to upsert vectors: {str(e)}")
def query_vectors(
self,
query_vector: np.ndarray,
top_k: int = 10,
namespace: Optional[str] = None,
filter: Optional[Dict[str, Any]] = None,
**options,
) -> Dict[str, Any]:
"""Query similar vectors."""
if not PINECONE_AVAILABLE:
raise ProcessingError("Pinecone not available")
try:
response = self.index.query(
vector=query_vector.tolist(),
top_k=top_k,
namespace=namespace,
filter=filter,
include_metadata=True,
**options,
)
return response
except Exception as e:
raise ProcessingError(f"Failed to query vectors: {str(e)}")
def delete_vectors(
self, ids: List[str], namespace: Optional[str] = None, **options
) -> Dict[str, Any]:
"""Delete vectors from index."""
if not PINECONE_AVAILABLE:
raise ProcessingError("Pinecone not available")
try:
response = self.index.delete(ids=ids, namespace=namespace, **options)
return response
except Exception as e:
raise ProcessingError(f"Failed to delete vectors: {str(e)}")
def fetch_vectors(
self, ids: List[str], namespace: Optional[str] = None, **options
) -> Dict[str, Any]:
"""Fetch vectors by IDs."""
if not PINECONE_AVAILABLE:
raise ProcessingError("Pinecone not available")
try:
response = self.index.fetch(ids=ids, namespace=namespace, **options)
return response
except Exception as e:
raise ProcessingError(f"Failed to fetch vectors: {str(e)}")
def describe_index_stats(self, namespace: Optional[str] = None) -> Dict[str, Any]:
"""Get index statistics."""
if not PINECONE_AVAILABLE:
raise ProcessingError("Pinecone not available")
try:
stats = self.index.describe_index_stats(namespace=namespace)
return stats
except Exception as e:
raise ProcessingError(f"Failed to get index stats: {str(e)}")
class PineconeQuery:
"""Pinecone query builder."""
def __init__(self, index: PineconeIndex):
"""Initialize Pinecone query builder."""
self.index = index
self.logger = get_logger("pinecone_query")
def build_query(
self,
query_vector: np.ndarray,
top_k: int = 10,
namespace: Optional[str] = None,
filter: Optional[Dict[str, Any]] = None,
**options,
) -> Dict[str, Any]:
"""Build query parameters."""
return {
"vector": query_vector.tolist(),
"top_k": top_k,
"namespace": namespace,
"filter": filter,
**options,
}
def execute(self, query_params: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Execute query and format results."""
response = self.index.query_vectors(**query_params)
results = []
for match in response.get("matches", []):
results.append(
{
"id": match.get("id"),
"score": match.get("score", 0.0),
"metadata": match.get("metadata", {}),
}
)
return results
class PineconeMetadata:
"""Pinecone metadata handler."""
@staticmethod
def validate_metadata(metadata: Dict[str, Any]) -> Dict[str, Any]:
"""Validate and sanitize metadata."""
# Pinecone metadata restrictions
validated = {}
for key, value in metadata.items():
# Convert to allowed types
if isinstance(value, (str, int, float, bool, list)):
validated[key] = value
elif isinstance(value, dict):
# Nested dicts not directly supported
validated[key] = str(value)
else:
validated[key] = str(value)
return validated
class PineconeAdapter:
"""
Pinecone adapter for vector storage and similarity search.
Pinecone connection and authentication
Vector storage and retrieval
Similarity search and filtering
Namespace and index management
Performance optimization
Error handling and recovery
"""
def __init__(
self, api_key: Optional[str] = None, environment: Optional[str] = None, **config
):
"""Initialize Pinecone adapter."""
self.logger = get_logger("pinecone_adapter")
self.config = config
self.progress_tracker = get_progress_tracker()
self.api_key = api_key or config.get("api_key")
self.environment = environment or config.get("environment")
self.client: Optional[Any] = None
self.index: Optional[PineconeIndex] = None
self.query_builder: Optional[PineconeQuery] = None
# Check Pinecone availability
if not PINECONE_AVAILABLE:
self.logger.warning(
"Pinecone not available. Install with: pip install pinecone-client"
)
def connect(self, api_key: Optional[str] = None, **options) -> bool:
"""
Connect to Pinecone service.
Args:
api_key: Pinecone API key
**options: Connection options
Returns:
True if connected successfully
"""
if not PINECONE_AVAILABLE:
raise ProcessingError(
"Pinecone is not available. Install it with: pip install pinecone-client"
)
api_key = api_key or self.api_key
if not api_key:
raise ValidationError("Pinecone API key is required")
try:
self.client = Pinecone(api_key=api_key)
self.logger.info("Connected to Pinecone")
return True
except Exception as e:
raise ProcessingError(f"Failed to connect to Pinecone: {str(e)}")
def create_index(
self,
index_name: str,
dimension: int,
metric: str = "cosine",
spec: Optional[Dict[str, Any]] = None,
**options,
) -> PineconeIndex:
"""
Create new vector index.
Args:
index_name: Name of the index
dimension: Vector dimension
metric: Distance metric ("cosine", "euclidean", "dotproduct")
spec: Index specification (serverless or pod)
**options: Additional options
Returns:
PineconeIndex instance
"""
if self.client is None:
self.connect()
if not PINECONE_AVAILABLE:
raise ProcessingError("Pinecone not available")
try:
# Check if index exists
existing_indexes = [idx.name for idx in self.client.list_indexes()]
if index_name in existing_indexes:
self.logger.info(f"Index {index_name} already exists")
return self.get_index(index_name)
# Create index specification
if spec is None:
spec = ServerlessSpec(cloud="aws", region="us-east-1")
# Create index
self.client.create_index(
name=index_name,
dimension=dimension,
metric=metric,
spec=spec,
**options,
)
self.logger.info(f"Created Pinecone index: {index_name}")
return self.get_index(index_name)
except Exception as e:
raise ProcessingError(f"Failed to create index: {str(e)}")
def get_index(self, index_name: str) -> PineconeIndex:
"""
Get existing index.
Args:
index_name: Name of the index
Returns:
PineconeIndex instance
"""
if self.client is None:
self.connect()
if not PINECONE_AVAILABLE:
raise ProcessingError("Pinecone not available")
try:
index = self.client.Index(index_name)
self.index = PineconeIndex(index, index_name)
self.query_builder = PineconeQuery(self.index)
return self.index
except Exception as e:
raise ProcessingError(f"Failed to get index: {str(e)}")
def upsert_vectors(
self,
vectors: List[Union[np.ndarray, List[float]]],
ids: List[str],
metadata: Optional[List[Dict[str, Any]]] = None,
namespace: Optional[str] = None,
**options,
) -> Dict[str, Any]:
"""
Insert or update vectors.
Args:
vectors: List of vectors
ids: Vector IDs
metadata: Vector metadata
namespace: Namespace name
**options: Additional options
Returns:
Upsert response
"""
tracking_id = self.progress_tracker.start_tracking(
module="vector_store",
submodule="PineconeAdapter",
message=f"Upserting {len(vectors)} vectors to Pinecone",
)
try:
if self.index is None:
self.progress_tracker.stop_tracking(
tracking_id, status="failed", message="Index not initialized"
)
raise ProcessingError(
"Index not initialized. Call create_index() or get_index() first."
)
# Format vectors
self.progress_tracker.update_tracking(
tracking_id, message="Formatting vectors..."
)
formatted_vectors = []
for i, vector in enumerate(vectors):
if isinstance(vector, np.ndarray):
vector = vector.tolist()
vector_data = {"id": ids[i], "values": vector}
if metadata and i < len(metadata):
vector_data["metadata"] = PineconeMetadata.validate_metadata(
metadata[i]
)
formatted_vectors.append(vector_data)
self.progress_tracker.update_tracking(
tracking_id, message="Upserting vectors to Pinecone..."
)
result = self.index.upsert_vectors(formatted_vectors, namespace, **options)
self.progress_tracker.stop_tracking(
tracking_id,
status="completed",
message=f"Upserted {len(vectors)} vectors",
)
return result
except Exception as e:
self.progress_tracker.stop_tracking(
tracking_id, status="failed", message=str(e)
)
raise
def query_vectors(
self,
query_vector: np.ndarray,
top_k: int = 10,
namespace: Optional[str] = None,
filter: Optional[Dict[str, Any]] = None,
**options,
) -> List[Dict[str, Any]]:
"""
Query similar vectors.
Args:
query_vector: Query vector
top_k: Number of results
namespace: Namespace name
filter: Metadata filter
**options: Additional options
Returns:
List of search results
"""
tracking_id = self.progress_tracker.start_tracking(
module="vector_store",
submodule="PineconeAdapter",
message=f"Querying {top_k} similar vectors from Pinecone",
)
try:
if self.query_builder is None:
self.progress_tracker.stop_tracking(
tracking_id, status="failed", message="Index not initialized"
)
raise ProcessingError(
"Index not initialized. Call create_index() or get_index() first."
)
self.progress_tracker.update_tracking(
tracking_id, message="Building query..."
)
query_params = self.query_builder.build_query(
query_vector, top_k, namespace, filter, **options
)
self.progress_tracker.update_tracking(
tracking_id, message="Executing query..."
)
results = self.query_builder.execute(query_params)
self.progress_tracker.stop_tracking(
tracking_id,
status="completed",
message=f"Query completed: {len(results) if isinstance(results, list) else 'N/A'} results",
)
return results
except Exception as e:
self.progress_tracker.stop_tracking(
tracking_id, status="failed", message=str(e)
)
raise
def delete_vectors(
self, ids: List[str], namespace: Optional[str] = None, **options
) -> Dict[str, Any]:
"""
Delete vectors from index.
Args:
ids: Vector IDs to delete
namespace: Namespace name
**options: Additional options
Returns:
Delete response
"""
if self.index is None:
raise ProcessingError(
"Index not initialized. Call create_index() or get_index() first."
)
return self.index.delete_vectors(ids, namespace, **options)
def get_stats(self, namespace: Optional[str] = None) -> Dict[str, Any]:
"""Get index statistics."""
if self.index is None:
raise ProcessingError(
"Index not initialized. Call create_index() or get_index() first."
)
stats = self.index.describe_index_stats(namespace)
return {
"total_vector_count": stats.get("total_vector_count", 0),
"dimension": stats.get("dimension", 0),
"index_fullness": stats.get("index_fullness", 0.0),
"namespaces": stats.get("namespaces", {}),
}
+8
View File
@@ -58,8 +58,16 @@ class VectorStore:
Provides vector store operations
"""
SUPPORTED_BACKENDS = {"faiss", "weaviate", "qdrant", "milvus", "inmemory"}
def __init__(self, backend="faiss", config=None, **kwargs):
"""Initialize vector store."""
if backend.lower() not in self.SUPPORTED_BACKENDS:
raise ValueError(
f"Unsupported backend: {backend}. "
f"Supported backends are: {', '.join(sorted(self.SUPPORTED_BACKENDS))}"
)
self.logger = get_logger("vector_store")
self.config = config or {}
self.config.update(kwargs)

Some files were not shown because too many files have changed in this diff Show More