ILIKE Search
The intentionally naive baseline.
Case-insensitive substring matching across
product fields using
ILIKE '%query%'.
An evolving product search engine built from
PostgreSQL primitives — beginning with naive
ILIKE substring matching and
progressively adding full-text retrieval,
indexes, relevance ranking, fuzzy matching
and caching.
Each version keeps the previous problem visible, then introduces one meaningful architectural improvement.
The intentionally naive baseline.
Case-insensitive substring matching across
product fields using
ILIKE '%query%'.
Move from raw substring matching to
PostgreSQL linguistic retrieval using
tokens, lexemes, stemming and
tsquery.
Keep full-text retrieval while adding a GIN-backed search vector so PostgreSQL can locate candidates through an index.
Open V3 →Recover from misspellings and failed searches using PostgreSQL trigram similarity and typo-tolerant fallback.
Open V4 →Cache repeated normalized searches and compare database execution with cache hits, TTLs and cache-key design.
Open V5 →Every version is measured independently so application latency and PostgreSQL execution behavior can be compared without hiding what changed underneath.
benchmark.log
SearchLab keeps application measurements separate from PostgreSQL execution diagnostics.
Python's
perf_counter()
measures application-observed elapsed
time around the database operation.
tracemalloc
records current and peak tracked Python
allocations during the search.
EXPLAIN ANALYZE
exposes execution time, planning time,
rows processed and the chosen plan.
BUFFERS
shows whether database pages were already
available in PostgreSQL's shared cache or
needed to be read.
Don't memorize that GIN and Redis are fast. Build the bad version first, inspect the query planner, measure the failure mode, and understand why the architecture had to evolve.
SearchLab is not meant to hide PostgreSQL behind abstractions. Each version keeps the SQL, execution plan, application measurements and limitations visible.