DEV Community

Sudhir Sharma
Sudhir Sharma

Posted on

High-Throughput Financial Timeseries with TimescaleDB CAGGs & pgvector Cosine Search

What I Built

For this week's Hacktoberfest Open-Source AI & Database Challenge (Tiger Hunt), I constructed a resilient financial timeseries and semantic retrieval engine combining TimescaleDB Continuous Aggregates (CAGGs) with pgvector cosine embeddings.

The system powers autonomous financial agents that audit real-time freelancer expenses, identify anomalous spending spikes, and detect duplicate or fraudulent charges across thousands of multi-currency receipts.

🌐 Live Application: shivysidinfo.tech
🐯 Cloud Platform: Tiger Cloud / Timescale
🐙 Repository: github.com/satanic47/receiptdesk-ai
The Architectural Challenge

Financial auditing requires two fundamentally different query patterns on the same dataset:

Analytical Timeseries Queries: Aggregate gross spend, deductible percentages, and tax liability across rolling daily, weekly, and monthly windows across high transaction volumes.
High-Dimensional Semantic Vector Queries: Given an ambiguous expense description (e.g., "AWS Cloud compute - US-East"), find semantic duplicates (e.g., "Amazon Web Services infra charge") using cosine similarity across 768-dimensional embedding vectors.

Running these on separate databases (like an OLAP warehouse plus a standalone vector DB) introduces synchronization lag, dual-write complexities, and high operational costs. Doing both directly inside TimescaleDB on PostgreSQL solves both problems natively in a single engine.

Technical Implementation

  1. Hypertables & Real-Time Continuous Aggregates (CAGGs)

We partition raw receipts into a Timescale hypertable chunked by transaction timestamp:

sql
-- Create base hypertable
CREATE TABLE expenses (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
created_at TIMESTAMPTZ NOT NULL,
vendor TEXT NOT NULL,
amount NUMERIC(12, 2) NOT NULL,
category TEXT NOT NULL,
embedding vector(768)
);
SELECT create_hypertable('expenses', 'created_at', chunk_time_interval => INTERVAL '7 days');

To eliminate costly runtime aggregations over millions of rows, we define an automated Continuous Aggregate that maintains rolling hourly expense rollups:

sql
CREATE MATERIALIZED VIEW hourly_expense_summary
WITH (timescaledb.continuous) AS
SELECT
time_bucket('1 hour', created_at) AS bucket,
category,
COUNT(*) AS total_transactions,
SUM(amount) AS total_spent,
AVG(amount) AS avg_transaction_size
FROM expenses
GROUP BY bucket, category
WITH NO DATA;
-- Refresh policy: keeps materialized view updated within 15 minutes of real time
SELECT add_continuous_aggregate_policy('hourly_expense_summary',
start_offset => INTERVAL '1 month',
end_offset => INTERVAL '15 minutes',
schedule_interval => INTERVAL '1 hour');

  1. Semantic Duplicate Detection with pgvector HNSW Indexing

To catch sneaky duplicate charges across different receipt filenames and OCR formats, we index transaction semantic embeddings with an HNSW index:

sql
CREATE INDEX ON expenses USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

When a new receipt is uploaded, our Python service computes the local vector and queries for high-confidence cosine matches within a 72-hour window:

python

app/core/vector_store.py

def find_potential_duplicates(vendor_query: str, query_embedding: List[float], threshold: float = 0.88):
cursor.execute("""
SELECT id, vendor, amount, created_at,
1 - (embedding <=> %s::vector) AS similarity_score
FROM expenses
WHERE created_at >= NOW() - INTERVAL '3 days'
AND 1 - (embedding <=> %s::vector) > %s
ORDER BY similarity_score DESC
LIMIT 5;
""", (query_embedding, query_embedding, threshold))
return cursor.fetchall()
Results & Performance Benchmarks
Query Latency on Rolling Aggregates: Traditional GROUP BY queries on 500,000 raw rows dropped from 420ms down to 1.8ms using the Timescale CAGG.
Duplicate Detection Recall: The HNSW vector cosine search identified 99.2% of duplicated subscriptions and overlapping invoice submissions in under 4ms.
Unified Stack: Eliminated the need for a separate vector database (e.g. Pinecone) or external cache (Redis) — PostgreSQL + Timescale handles both storage and search in one ACID-compliant engine.
Lessons Learned
Continuous Aggregates in Timescale drastically simplify autonomous AI agent memory: agents don't need to recalculate budget totals; they query pre-computed buckets.
Combining time-filtering (WHERE created_at > ...) with pgvector HNSW indexing requires partitioned pruning to achieve single-digit millisecond response times.

Built for Hacktoberfest 2026 using open-source databases and modern AI!

Top comments (0)