Time-Series Data with Vector Analysis
HeliosDB Lite analyses time-series data and its vector embeddings in one database for monitoring and anomaly investigation: timestamp and measurement columns use STORAGE COLUMNAR for aggregation scans, a VECTOR column holds an embedding of each window of readings, an HNSW index finds windows similar to a known pattern, and window functions such as LAG compute changes between consecutive readings.
Executive Summary
This unique combination delivers:
- Extreme data compression (100:1 ratio for time-series data)
- Real-time anomaly detection (patterns detected within seconds of occurrence)
- Embedded deployment (no separate time-series database required)
Problem Being Solved
The Time-Series + AI Analytics Dilemma
Option B: Relational Database + Time-Series DB
- Pro: Flexible SQL queries
- Pro: ACID compliance
- Pro: Time-series compression
- Con: Two systems to manage (complexity doubles)
- Con: Data synchronization issues (consistency problems)
- Con: Cannot do semantic queries (requires ML pipeline)
Option C: Data Lake + ML Pipeline (Modern Approach)
- Pro: Can do semantic analysis
- Pro: Flexible data storage
- Con: Complex data pipeline (5-10 components to manage)
- Con: Operational burden (requires data engineering team)
Enterprise Pain Points
Operational Complexity:
- Managing separate databases (time-series + relational)
- Synchronizing data between systems
- Debugging data consistency issues
- Scaling databases separately
- Complex disaster recovery procedures
Technical Limitations:
- No semantic queries: Cannot ask "find patterns similar to this failure"
- Batch analysis only: Pattern detection happens hours later
- Data silos: IoT data separate from business data
- Schema rigidity: Changes require pipeline reconfiguration
- No transactional guarantees: Data loss during failures
Implementation Examples
Example 2: Real-Time Monitoring Dashboard (React)
import React, { useState, useEffect } from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid } from 'recharts';
export function TimeSeriesMonitor() {
const [readings, setReadings] = useState([]);
const [anomalies, setAnomalies] = useState([]);
const [connected, setConnected] = useState(false);
useEffect(() => {
// WebSocket connection for real-time data
const ws = new WebSocket('ws://localhost:8080/sensor-stream');
ws.onopen = () => {
setConnected(true);
// Subscribe to sensor data
ws.send(JSON.stringify({
action: 'subscribe',
sensors: ['sensor-42', 'sensor-43', 'sensor-44'],
}));
};
ws.onmessage = async (event) => {
const message = JSON.parse(event.data);
if (message.type === 'reading') {
// Add new reading to chart
setReadings((prev) => [
...prev.slice(-99), // Keep last 100
{
timestamp: new Date(message.timestamp).toLocaleTimeString(),
sensor_id: message.sensor_id,
temperature: message.temperature,
},
]);
// Check for anomalies
if (message.anomaly_score > 0.85) {
setAnomalies((prev) => [
{
id: message.sensor_id,
pattern: message.pattern_description,
confidence: message.anomaly_score,
timestamp: new Date(),
},
...prev.slice(0, 4), // Keep last 5
]);
}
}
};
ws.onerror = () => setConnected(false);
ws.onclose = () => setConnected(false);
return () => ws.close();
}, []);
return (
<div className="time-series-monitor">
<div className="header">
<h2>Real-Time IoT Monitoring</h2>
<div className={`status ${connected ? 'connected' : 'disconnected'}`}>
{connected ? ' Connected' : ' Disconnected'}
</div>
</div>
<div className="charts-section">
<h3>Temperature Readings (Last 100)</h3>
<LineChart width={800} height={300} data={readings}>
<CartesianGrid />
<XAxis dataKey="timestamp" />
<YAxis />
<Line
type="monotone"
dataKey="temperature"
stroke="#8884d8"
dot={false}
isAnimationActive={false}
/>
</LineChart>
</div>
<div className="anomalies-section">
<h3> Recent Anomalies</h3>
{anomalies.length === 0 ? (
<p>No anomalies detected</p>
) : (
<table>
<thead>
<tr>
<th>Sensor</th>
<th>Pattern</th>
<th>Confidence</th>
<th>Time</th>
</tr>
</thead>
<tbody>
{anomalies.map((anomaly) => (
<tr key={`${anomaly.id}-${anomaly.timestamp}`}>
<td>{anomaly.id}</td>
<td>{anomaly.pattern}</td>
<td>{(anomaly.confidence * 100).toFixed(1)}%</td>
<td>{anomaly.timestamp.toLocaleTimeString()}</td>
</tr>
))}
</tbody>
</table>
)}
</div>
</div>
);
}
Example 3: Time-Series Queries with Vector Analysis (SQL)
-- 1. Find all sensors with anomalous patterns (vector similarity)
SELECT
s.sensor_id,
s.sensor_name,
s.location,
fp.pattern_description,
1 - (se.embedding <-> fp.pattern_embedding) as similarity,
COUNT(*) as matching_events
FROM sensor_embeddings se
JOIN known_failure_patterns fp ON 1 = 1 -- Cross join for similarity
JOIN sensors s ON se.sensor_id = s.sensor_id
WHERE 1 - (se.embedding <-> fp.pattern_embedding) > 0.85
AND se.timestamp > datetime('now', '-1 hour')
GROUP BY s.sensor_id, fp.pattern_id
ORDER BY similarity DESC
LIMIT 50;
-- 2. Temperature gradient analysis (find rapid changes)
WITH temp_changes AS (
SELECT
sensor_id,
timestamp,
temperature,
LAG(temperature) OVER (
PARTITION BY sensor_id
ORDER BY timestamp
) as prev_temp,
ABS(temperature - LAG(temperature) OVER (
PARTITION BY sensor_id
ORDER BY timestamp
)) as temp_change_rate
FROM sensor_readings
WHERE timestamp > datetime('now', '-6 hours')
)
SELECT
sensor_id,
COUNT(*) as rapid_changes,
MAX(temp_change_rate) as max_change,
AVG(temp_change_rate) as avg_change,
STDDEV(temp_change_rate) as volatility
FROM temp_changes
WHERE temp_change_rate > 2.0 -- Degrees per minute
GROUP BY sensor_id
HAVING COUNT(*) > 5 -- Multiple changes (pattern)
ORDER BY volatility DESC;
-- 3. Correlation analysis (multi-sensor failure patterns)
SELECT
s1.sensor_id as sensor_1,
s2.sensor_id as sensor_2,
CORR(s1.temperature, s2.temperature) as temp_correlation,
CORR(s1.humidity, s2.humidity) as humidity_correlation,
COUNT(*) as reading_pairs
FROM sensor_readings s1
JOIN sensor_readings s2
ON s1.timestamp = s2.timestamp
AND s1.sensor_id < s2.sensor_id
WHERE s1.timestamp > datetime('now', '-24 hours')
GROUP BY s1.sensor_id, s2.sensor_id
HAVING CORR(s1.temperature, s2.temperature) > 0.9 -- Strong correlation
ORDER BY reading_pairs DESC;
-- 4. Predictive pattern detection (before failure occurs)
WITH recent_readings AS (
SELECT
sensor_id,
timestamp,
temperature,
humidity,
pressure,
ROW_NUMBER() OVER (
PARTITION BY sensor_id
ORDER BY timestamp DESC
) as recency
FROM sensor_readings
WHERE timestamp > datetime('now', '-4 hours')
)
SELECT
r.sensor_id,
s.sensor_name,
COUNT(*) as reading_count,
AVG(r.temperature) as avg_temp,
STDDEV(r.temperature) as temp_volatility,
MAX(r.pressure) as max_pressure,
CASE
WHEN STDDEV(r.temperature) > 5 THEN 'HIGH_THERMAL_VOLATILITY'
WHEN STDDEV(r.humidity) > 15 THEN 'HIGH_HUMIDITY_VARIANCE'
WHEN MAX(r.pressure) > 1050 THEN 'PRESSURE_SPIKE'
ELSE 'NORMAL'
END as risk_level
FROM recent_readings r
JOIN sensors s ON r.sensor_id = s.sensor_id
WHERE r.recency <= 60
GROUP BY r.sensor_id
HAVING STDDEV(r.temperature) > 3 -- Statistical anomaly
ORDER BY temp_volatility DESC;
-- 5. Semantic similarity search (find similar event sequences)
SELECT
e1.event_id as query_event,
e2.event_id as similar_event,
e2.event_type as similar_type,
1 - (e1.embedding <-> e2.embedding) as similarity,
e2.description,
e2.resolution_time_ms
FROM events e1
CROSS JOIN events e2
WHERE e1.event_id = 'event_12345' -- Find similar to this event
AND 1 - (e1.embedding <-> e2.embedding) > 0.8 -- 80% similar
AND e2.event_id != e1.event_id
ORDER BY similarity DESC
LIMIT 10;
Example 5: Docker Compose - Full IoT Stack
# Dockerfile - IoT monitoring application
FROM rust:latest as builder
WORKDIR /app
COPY Cargo.* ./
COPY src ./src
RUN cargo build --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y curl
COPY --from=builder /app/target/release/iot-monitor /usr/local/bin/
RUN mkdir -p /data && chmod 700 /data
RUN useradd -m -u 1000 app
USER app:app
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/health || exit 1
ENTRYPOINT ["iot-monitor"]
# docker-compose.yml - Complete IoT monitoring stack
version: '3.8'
services:
# IoT monitoring backend
iot-monitor:
build: .
environment:
RUST_LOG: info
DATABASE_PATH: /data/iot.db
MAX_MEMORY_MB: 512
COMPRESSION_LEVEL: 9
VECTOR_SEARCH_ENABLED: "true"
volumes:
- iot-data:/data
ports:
- "8080:8080"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 3s
retries: 3
# Sensor simulator (for testing)
sensor-simulator:
image: node:18-alpine
working_dir: /app
volumes:
- ./simulator:/app
- /app/node_modules
environment:
API_URL: http://iot-monitor:8080
SENSORS_COUNT: 100
READINGS_PER_SECOND: 1000
command: npm start
depends_on:
- iot-monitor
# Grafana dashboard
grafana:
image: grafana/grafana:latest
environment:
GF_SECURITY_ADMIN_PASSWORD: admin
ports:
- "3000:3000"
volumes:
- grafana-storage:/var/lib/grafana
- ./grafana/datasources:/etc/grafana/provisioning/datasources
depends_on:
- iot-monitor
volumes:
iot-data:
grafana-storage:
Conclusion
By combining extreme compression, native vector search, and ACID guarantees, it enables organizations to:
- Enable predictive maintenance (prevent failures before they occur)
For any organization managing IoT or time-series data: HeliosDB Lite is transformational in cost, performance, and capability.
Performance depends on workload and hardware. Published figures are measured on representative fixtures; see the benchmarks page and reproduce them on your own workload.