Temporal Index (B-tree)
The TemporalIndex uses a B-tree for efficient time-based queries.
Creating an Index
use spatial_narrative::index::TemporalIndex;
use spatial_narrative::core::{Event, Location, Timestamp};
// Empty index
let mut index: TemporalIndex<Event> = TemporalIndex::new();
// Insert items
let event = Event::new(
Location::new(40.7128, -74.0060),
Timestamp::parse("2024-01-15T10:00:00Z").unwrap(),
"Morning meeting"
);
index.insert(event, &Timestamp::parse("2024-01-15T10:00:00Z").unwrap());
From Iterator
let index = TemporalIndex::from_iter(
events.iter().cloned(),
|event| &event.timestamp
);
Query Types
Time Range Query
Find items within a time range:
use spatial_narrative::core::TimeRange;
let range = TimeRange::new(
Timestamp::parse("2024-01-01T00:00:00Z").unwrap(),
Timestamp::parse("2024-01-31T23:59:59Z").unwrap(),
);
let january_events = index.query_range(&range);
println!("Found {} events in January", january_events.len());
Convenience Ranges
// Entire year
let results = index.query_range(&TimeRange::year(2024));
// Specific month
let results = index.query_range(&TimeRange::month(2024, 6)); // June 2024
// Specific day
let results = index.query_range(&TimeRange::day(2024, 7, 4)); // July 4th
Before/After Queries
let cutoff = Timestamp::parse("2024-06-01T00:00:00Z").unwrap();
// All events before June
let before = index.before(&cutoff);
// All events after June
let after = index.after(&cutoff);
// Including the cutoff time
let at_or_before = index.at_or_before(&cutoff);
let at_or_after = index.at_or_after(&cutoff);
First and Last
// Get earliest event
if let Some(first) = index.first() {
println!("First event: {}", first.text);
}
// Get latest event
if let Some(last) = index.last() {
println!("Last event: {}", last.text);
}
Chronological Iteration
// Iterate in time order
for event in index.chronological() {
println!("{}: {}", event.timestamp.to_rfc3339(), event.text);
}
Reverse Chronological
// Most recent first
for event in index.reverse_chronological() {
println!("{}: {}", event.timestamp.to_rfc3339(), event.text);
}
Sliding Window
Iterate with a sliding time window:
use spatial_narrative::index::SlidingWindowIter;
use std::time::Duration;
let window_size = Duration::from_secs(3600); // 1 hour
let step = Duration::from_secs(1800); // 30 minute steps
for window in index.sliding_window(window_size, step) {
println!("Window {}: {} events",
window.start.to_rfc3339(),
window.events.len());
}
Methods Reference
| Method | Description |
|---|---|
new() | Create empty index |
from_iter() | Build from iterator |
insert(item, timestamp) | Add an item |
query_range(range) | Query time range |
before(timestamp) | Items before (exclusive) |
after(timestamp) | Items after (exclusive) |
at_or_before(timestamp) | Items at or before (inclusive) |
at_or_after(timestamp) | Items at or after (inclusive) |
first() | Earliest item |
last() | Latest item |
chronological() | Time-ordered iterator |
reverse_chronological() | Reverse time iterator |
sliding_window(size, step) | Sliding window iterator |
time_range() | Get overall time range |
len() | Number of items |
Use Cases
Timeline Visualization
// Get events in order for display
let timeline: Vec<_> = index.chronological().collect();
for event in timeline {
println!("{}: {}",
event.timestamp.format("%Y-%m-%d %H:%M"),
event.text);
}
Activity Analysis
use std::time::Duration;
// Count events per hour
let hour = Duration::from_secs(3600);
let mut hourly_counts = Vec::new();
for window in index.sliding_window(hour, hour) {
hourly_counts.push((window.start, window.events.len()));
}
// Find busiest hour
if let Some((time, count)) = hourly_counts.iter().max_by_key(|(_, c)| c) {
println!("Busiest hour: {} with {} events",
time.to_rfc3339(), count);
}
Recent Events
use std::time::Duration;
// Get events from the last 24 hours
let now = Timestamp::now();
let yesterday = now.subtract(Duration::from_secs(86400));
let range = TimeRange::new(yesterday, now);
let recent = index.query_range(&range);
println!("{} events in the last 24 hours", recent.len());
Gap Detection
// Find gaps between events
let ordered: Vec<_> = index.chronological().collect();
for window in ordered.windows(2) {
let gap = window[1].timestamp.duration_since(&window[0].timestamp);
if gap > Duration::from_secs(3600 * 6) { // 6+ hour gap
println!("Gap from {} to {}",
window[0].timestamp.to_rfc3339(),
window[1].timestamp.to_rfc3339());
}
}