# arrow-graph-core
Arrow-native graph store with configurable namespace partitioning.
Store RDF-like triples in Apache Arrow RecordBatches with:
- **Configurable namespaces** — partition your graph by any string key
- **Optional layer column** — sub-partition within namespaces (e.g., for knowledge layers)
- **Provenance tracking** — causal chains, source documents, confidence scores
- **Zero-copy operations** — queries filter Arrow RecordBatches without materialization
- **Schema versioning** — read-path migration when schemas evolve
## Quick Start
```rust
use arrow_graph_core::store::{ArrowGraphStore, Triple, QuerySpec};
// Create a store with your own namespace partitions
let mut store = ArrowGraphStore::new(&["world", "code", "self"]);
let triple = Triple {
subject: "Alice".to_string(),
predicate: "knows".to_string(),
object: "Bob".to_string(),
graph: None,
confidence: Some(0.9),
source_document: None,
source_chunk_id: None,
extracted_by: Some("agent-1".to_string()),
caused_by: None,
derived_from: None,
consolidated_at: None,
};
let id = store.add_triple(&triple, "world", Some(1)).unwrap();
assert_eq!(store.len(), 1);
// Query by subject
let results = store.query(&QuerySpec {
subject: Some("Alice".to_string()),
..Default::default()
}).unwrap();
```
## Three API Levels
| **Raw** | `ArrowGraphStore` | Full control over namespaces and layers |
| **Simple** | `SimpleTripleStore` | Default namespace, simplified add/query/remove |
| **KG** | `KgStore` | URI prefix management, keyword search, gap tracking |
### SimpleTripleStore
```rust
use arrow_graph_core::triple_store::SimpleTripleStore;
let mut store = SimpleTripleStore::new();
let id = store.add("Alice", "knows", "Bob", 0.9, "source").unwrap();
let results = store.query(Some("Alice"), None, None).unwrap();
store.remove(&id).unwrap();
```
### KgStore (Knowledge Graph)
```rust
use arrow_graph_core::kg_store::KgStore;
let mut store = KgStore::new();
store.bind_prefix("ex", "http://example.org/");
store.add_triple("ex:Alice", "rdf:type", "ex:Person", None, 1.0).unwrap();
// Keyword search (case-insensitive)
let results = store.search_by_keywords(&["Alice"]);
```
## Causal Chains
Track provenance with `caused_by` and `derived_from` links:
```rust
use arrow_graph_core::store::{ArrowGraphStore, Triple};
let mut store = ArrowGraphStore::new(&["default"]);
let t0 = Triple {
subject: "observation".into(), predicate: "saw".into(), object: "rain".into(),
caused_by: None, derived_from: None,
graph: None, confidence: Some(1.0), source_document: None,
source_chunk_id: None, extracted_by: None, consolidated_at: None,
};
let id0 = store.add_triple(&t0, "default", None).unwrap();
let t1 = Triple {
subject: "inference".into(), predicate: "implies".into(), object: "wet_ground".into(),
caused_by: Some(id0.clone()), derived_from: None,
graph: None, confidence: Some(0.8), source_document: None,
source_chunk_id: None, extracted_by: None, consolidated_at: None,
};
let id1 = store.add_triple(&t1, "default", None).unwrap();
// Traverse the causal chain
let chain = store.causal_chain(&id1);
assert_eq!(chain.len(), 2); // t1 → t0
```
## Schema
The triples table has 16 columns (v1.1.0):
| `triple_id` | Utf8 | UUID (auto-generated) |
| `subject` | Utf8 | RDF subject |
| `predicate` | Utf8 | RDF predicate |
| `object` | Utf8 | RDF object |
| `graph` | Utf8? | Named graph / context |
| `namespace` | Utf8 | Partition key |
| `layer` | UInt8 | Sub-partition (0 if unused) |
| `confidence` | Float64? | Confidence score |
| `source_document` | Utf8? | Provenance path |
| `source_chunk_id` | Utf8? | FK to chunks table |
| `extracted_by` | Utf8? | Creator agent |
| `created_at` | Timestamp(ms) | Creation time |
| `caused_by` | Utf8? | Causal predecessor |
| `derived_from` | Utf8? | Derivation source |
| `consolidated_at` | Timestamp(ms)? | Consolidation time |
| `deleted` | Boolean | Logical delete flag |
Access columns by name constant: `col::SUBJECT`, `col::PREDICATE`, etc.
## License
MIT