Ranking with ts_rank in PostgreSQL - Time & Space Complexity
When we rank search results using ts_rank, we want to know how the time to get results changes as the data grows.
We ask: How does the ranking process scale when there are more rows to check?
Analyze the time complexity of the following code snippet.
SELECT id, ts_rank(to_tsvector(content), query) AS rank
FROM documents, (SELECT to_tsquery('search & term') AS query) q
WHERE to_tsvector(content) @@ query
ORDER BY rank DESC
LIMIT 10;
This query finds documents matching a search query, ranks them by relevance, and returns the top 10.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Calculating
ts_rankfor each matching row. - How many times: Once for every row that matches the search condition.
As the number of matching rows grows, the database must calculate ts_rank for each one before sorting.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 rank calculations and sorting |
| 100 | About 100 rank calculations and sorting |
| 1000 | About 1000 rank calculations and sorting |
Pattern observation: The work grows roughly in direct proportion to the number of matching rows.
Time Complexity: O(n log n)
This means the time grows a bit faster than the number of matching rows because of sorting after ranking.
[X] Wrong: "Ranking results with ts_rank is always very slow because it checks every row in the table."
[OK] Correct: The query uses an index to find matching rows first, so ts_rank runs only on those matches, not the whole table.
Understanding how ranking scales helps you explain search query performance clearly and confidently.
What if we removed the LIMIT 10? How would the time complexity change?
Practice
ts_rank function do in PostgreSQL full-text search?Solution
Step 1: Understand the purpose of ts_rank
Thets_rankfunction scores how well a document matches a search query in full-text search.Step 2: Differentiate from related functions
to_tsvectorprepares text,to_tsquerycreates queries, butts_rankranks results.Final Answer:
It calculates the relevance ranking of a document for a search query. -> Option CQuick Check:
ts_rank = relevance score [OK]
- Confusing ts_rank with to_tsvector
- Thinking ts_rank creates search queries
- Assuming ts_rank sorts alphabetically
ts_rank in PostgreSQL?Solution
Step 1: Check correct function arguments
ts_rankrequires a tsvector and a tsquery, soto_tsvector(text_column)andto_tsquery('search')are correct.Step 2: Verify ordering and syntax
Ordering by rank descending shows best matches first, matching SELECT *, ts_rank(to_tsvector(text_column), to_tsquery('search')) AS rank FROM table ORDER BY rank DESC;.Final Answer:
SELECT *, ts_rank(to_tsvector(text_column), to_tsquery('search')) AS rank FROM table ORDER BY rank DESC; -> Option AQuick Check:
Correct ts_rank syntax = SELECT *, ts_rank(to_tsvector(text_column), to_tsquery('search')) AS rank FROM table ORDER BY rank DESC; [OK]
- Swapping to_tsvector and to_tsquery arguments
- Ordering results ascending instead of descending
- Passing plain text instead of tsvector or tsquery
documents with column content, what will this query return?SELECT content, ts_rank(to_tsvector(content), to_tsquery('cat & dog')) AS rank FROM documents ORDER BY rank DESC LIMIT 2;Solution
Step 1: Understand the query components
The query usesto_tsquery('cat & dog')which searches for documents containing both 'cat' and 'dog'.Step 2: Analyze ordering and limit
Results are ordered byts_rankdescending, so highest relevance first, limited to 2 rows.Final Answer:
The two documents with the highest relevance to both 'cat' and 'dog'. -> Option BQuick Check:
ts_rank orders best matches first [OK]
- Thinking it returns documents with either word
- Assuming alphabetical order instead of rank
- Believing LIMIT causes an error with ts_rank
SELECT content, ts_rank(to_tsquery(content), to_tsvector('search')) AS rank FROM documents ORDER BY rank DESC;Solution
Step 1: Check ts_rank argument order
ts_rankexpectstsvectorfirst, thentsquery. Here, they are reversed.Step 2: Confirm argument types
to_tsquery(content)is incorrect becausecontentis text, not a query string; alsoto_tsvector('search')is a vector, but arguments are swapped.Final Answer:
Arguments to ts_rank are reversed; tsvector should be first, tsquery second. -> Option AQuick Check:
ts_rank(tsvector, tsquery) order matters [OK]
- Swapping ts_rank arguments
- Using to_tsquery on text column
- Ignoring argument types for ts_rank
ts_rank with weights to achieve this?Solution
Step 1: Understand weighting with setweight
Usingsetweightwith 'A' assigns highest weight to terms into_tsvector, boosting the relevance of matching terms.Step 2: Analyze the query logic
to_tsquery('apple | orange')searches for either word, and ordering by rank descending with LIMIT 3 returns top 3 relevant documents.Step 3: Compare options
SELECT content, ts_rank(to_tsvector(content), to_tsquery('apple & orange')) AS rank FROM documents ORDER BY rank DESC LIMIT 3; uses AND (&) which requires both words, not either. SELECT content, ts_rank(to_tsvector(content), to_tsquery('apple | orange')) AS rank FROM documents ORDER BY rank ASC LIMIT 3; orders ascending, showing least relevant first. SELECT content, ts_rank(setweight(to_tsvector(content), 'D'), to_tsquery('apple | orange')) AS rank FROM documents ORDER BY rank ASC LIMIT 3; uses weight 'D' which is lowest, so it does not boost relevance as much.Final Answer:
SELECT content, ts_rank(setweight(to_tsvector(content), 'A'), to_tsquery('apple | orange')) AS rank FROM documents ORDER BY rank DESC LIMIT 3; -> Option DQuick Check:
Weighted ts_rank with OR query = SELECT content, ts_rank(setweight(to_tsvector(content), 'A'), to_tsquery('apple | orange')) AS rank FROM documents ORDER BY rank DESC LIMIT 3; [OK]
- Using AND instead of OR in tsquery
- Ordering by rank ascending instead of descending
- Assigning lowest weight to preferred terms
Ready to prove it?
Pass the test and this pattern moves unknown
