- a small Node.js application,
- a Docker Compose setup that launches PostgreSQL and the app, and
- code that loads a CSV of support-ticket data into both backends so you can compare queries side-by-side.
- Docker and Docker Compose installed
- A machine with internet access (the build will pull container images)
http://localhost:3000 in your browser.
Project overview
This demo is a simple Node.js application that accepts a CSV of support tickets and loads the rows into:
- PostgreSQL (tabular storage)
- LanceDB (vector storage; stores embeddings/vectors representing text content)
package.json:
- Click “Choose CSV File” in the web UI and select the provided support-tickets CSV.
- Preview the CSV to inspect fields such as
title,body,category,priority,status,resolution,language,created_on, andtags. - Click the button to load the file into Postgres and LanceDB. The app will:
- Insert rows into a Postgres
documentstable. - Create embeddings (vectors) from the text and store them in LanceDB along with metadata (
id,title,category, etc.).
- Insert rows into a Postgres
- PostgreSQL: rows are stored in a table with columns like
id,title,body,category,priority,status,created_at,resolution, etc. This is a traditional tabular representation suitable for structured queries and analytics. - LanceDB (vector DB): for each document the application stores:
- an embedding vector (a numeric array representing semantic features of the text), and
- accompanying metadata such as
id,title, andcategory. The vector DB indexes those vectors to support fast similarity search. The “vector preview” shown in the UI is the embedding representation, not a relational row.
- Exact / keyword search with SQL
To find tickets mentioning a forgotten password or related issues, a typical SQL pattern-matching query:
title or body.
- Natural-language / semantic search with a vector DB
With a vector DB you issue a natural-language query and retrieve documents ranked by similarity to that query. For example:
- Aggregation and analytics — SQL
For counts, groupings, and analytics, SQL provides powerful aggregation functions. Example: tickets per category:
| Capability | PostgreSQL (relational) | LanceDB (vector DB) |
|---|---|---|
| Exact keyword search | Excellent (SQL WHERE / ILIKE / regex) | Possible only via metadata or additional text fields |
| Semantic / natural-language search | Limited — requires synonyms, additional tooling | Excellent — built for embedding similarity search |
| Aggregations and analytics | Native (GROUP BY, COUNT, JOINs) | Not designed for complex aggregations |
| Transactional integrity | Strong (ACID) | Not a replacement for transactional storage |
| Best for | Reporting, structured retrieval, transactional data | Retrieval for conversational agents, semantic search, fuzzy matching |
- SQL returns exact or pattern-based matches as defined by your WHERE clause — deterministic and precise.
- Vector DB returns semantically similar results based on embedding similarity — fuzzy, ranked, and great for conversational or ambiguous queries.
GROUP BY, counts, joins, or strict transactional consistency. For analytics, reporting, and structured queries, a relational database like PostgreSQL remains the appropriate tool.
Use PostgreSQL (or another relational DB) for structured storage, deterministic filters, aggregations, and transactional integrity. Use a vector DB (LanceDB in this demo) for semantic search, similarity matching, and conversational retrieval. Many real-world systems combine both: vectors for retrieval and relational DB for storage, metadata, and analytics.
- Hybrid approach (recommended): store full records and metadata in PostgreSQL for durability, aggregation, and joins; store embeddings in LanceDB and use the vector DB to retrieve candidate documents by semantic relevance. Then enrich or filter those candidates using SQL queries on metadata.
- Common pipeline:
- Ingest raw document into PostgreSQL (store source text & metadata).
- Compute embedding for text and insert into LanceDB with the same
idand metadata. - For queries, run a semantic search on LanceDB → get top-N candidate ids → fetch full records from PostgreSQL for display or further filtering.
- Both systems can store and surface the same underlying documents, but they index and retrieve them differently.
- SQL queries are explicit, precise, and ideal for analytics and structured retrieval.
- Vector search accepts natural-language queries and returns semantically similar content ranked by score — excellent for search and conversational retrieval, but not for structured aggregations.
- A hybrid approach (use both) is common in production: vector DB for retrieval, relational DB for analytics and persistence.
- LanceDB: https://github.com/lancedb/lancedb
- PostgreSQL Documentation: https://www.postgresql.org/docs/
- Retrieval-Augmented Generation (RAG) overview: https://learn.kodekloud.com/user/courses/fundamentals-of-rag