การจับคู่แบบคลุมเครือด้วยความคล้ายคลึงของ pg_trgm
เพิ่มประสิทธิภาพการค้นหาที่ทนต่อการพิมพ์ผิดและการเติมคำอัตโนมัติด้วยดัชนีไตรแกรมและเกณฑ์ความคล้ายคลึง
การจับคู่แบบคลุมเครือด้วยความคล้ายคลึงของ pg_trgm เป็นบทเรียน PostgreSQL Performance & Query Optimization ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน PostgreSQL Performance & Query Optimization และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส PostgreSQL Performance & Query Optimization มีบทเรียนทั้งหมด 4 บทเรียน
บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ
Why Fuzzy Matching?
Users misspell things. They type jonh instead of john, or postgers instead of postgres. A plain = or even LIKE comparison returns nothing for these typos.
Fuzzy matching finds rows that are close enough to the search term, not just exact matches. PostgreSQL ships this capability in the pg_trgm extension, which powers:
- Typo-tolerant search — match despite small spelling errors
- Autocomplete — suggest as the user types
- Deduplication — find near-duplicate names or addresses
The key idea is measuring similarity rather than equality.
What Is a Trigram?
A trigram is a group of three consecutive characters in a string. pg_trgm breaks every string into its set of trigrams, padding the start and end with spaces.
For the word cat, PostgreSQL produces the trigrams: " c", " ca", "cat", "at ". You can inspect this yourself with show_trgm().
Two strings are considered similar when they share many trigrams. Because trigrams overlap, a single typo only damages a few of them, so similar words still share most of their set.
-- Enable the extension once per database
CREATE EXTENSION IF NOT EXISTS pg_trgm;
-- Inspect the trigrams of a word
SELECT show_trgm('cat');
-- {" c"," ca","at ","cat"}The similarity() Function
The core measure is similarity(a, b). It returns a real between 0 (no shared trigrams) and 1 (identical strings).
Internally it is the count of shared trigrams divided by the count of the union of both trigram sets (a Jaccard-style ratio). The closer the spelling, the higher the score.
Notice how a single typo only drops the score a little, while an unrelated word scores near zero.
SELECT
similarity('postgres', 'postgres') AS exact, -- 1
similarity('postgres', 'postgers') AS typo, -- ~0.45
similarity('postgres', 'banana') AS unrelated; -- 0The % Similarity Operator
Writing similarity(a, b) > threshold everywhere is verbose, and more importantly it cannot use a trigram index directly. Instead, pg_trgm gives you the % operator.
a % b returns true when the similarity of the two strings exceeds the current similarity threshold. This operator is index-aware, so a GIN or GiST trigram index can accelerate it.
The default threshold is 0.3. You read the session value with show_limit() (legacy) or the GUC pg_trgm.similarity_threshold.
-- These two rows are 'similar enough' at the default 0.3 threshold
SELECT 'postgres' % 'postgers' AS is_similar; -- t
-- See the current threshold
SHOW pg_trgm.similarity_threshold; -- 0.3Tuning the Similarity Threshold
The threshold controls the trade-off between recall (catching more matches) and precision (avoiding junk matches).
- Lower threshold (e.g. 0.2) → more permissive, more results, more false positives
- Higher threshold (e.g. 0.5) → stricter, fewer results, risk of missing real typos
Set it per session with SET pg_trgm.similarity_threshold. The % operator immediately respects the new value, and any index scan stays valid.
-- Tighten matching for this session
SET pg_trgm.similarity_threshold = 0.45;
SELECT name
FROM products
WHERE name % 'wireles keyboad'
ORDER BY similarity(name, 'wireles keyboad') DESC;Trigram Indexes: GIN vs GiST
Without an index, % forces a sequential scan that computes similarity for every row — fine for hundreds of rows, painful for millions. pg_trgm supports two index types:
- GIN (
gin_trgm_ops) — faster lookups, smaller-to-build for read-heavy search; usually the default choice. - GiST (
gist_trgm_ops) — supports distance ordering for KNN (<->) and can be cheaper to update.
For typical typo-tolerant search you want GIN. Build it on the column you search.
-- GIN index for fast % and LIKE/ILIKE acceleration
CREATE INDEX idx_products_name_trgm
ON products
USING gin (name gin_trgm_ops);How the Index Accelerates % and LIKE
A trigram GIN index does more than help %. Because PostgreSQL can extract trigrams from a LIKE or ILIKE pattern, the same index also speeds up wildcard searches like '%board%' — including leading wildcards that a normal B-tree cannot use.
Run EXPLAIN ANALYZE and look for a Bitmap Index Scan on your trigram index instead of a Seq Scan. That confirms the planner is using it.
EXPLAIN ANALYZE
SELECT name
FROM products
WHERE name ILIKE '%keyboard%';
-- -> Bitmap Index Scan on idx_products_name_trgmRanking Results by Similarity
Matching is only half the job — users expect the best match first. Filter with % (index-friendly) and then sort with similarity() in ORDER BY.
Keep the WHERE name % :q predicate so the index narrows candidates, then rank the survivors. Computing similarity() only on the filtered set is cheap.
SELECT name, similarity(name, 'mechancal keybord') AS score
FROM products
WHERE name % 'mechancal keybord'
ORDER BY score DESC
LIMIT 10;KNN Distance Ordering with <->
For pure "give me the N closest names" queries, pg_trgm offers the distance operator <->, defined as 1 - similarity(a, b). Smaller distance means more similar.
When you ORDER BY column <-> :q, a GiST trigram index can return rows in distance order directly (a KNN index scan) — no sort step, no explicit threshold needed. This is ideal for autocomplete and "closest match" lookups.
-- Requires a GiST trigram index for the KNN scan
CREATE INDEX idx_products_name_gist
ON products USING gist (name gist_trgm_ops);
SELECT name
FROM products
ORDER BY name <-> 'wireles mouse'
LIMIT 5;word_similarity for Autocomplete
Plain similarity() penalizes length differences: matching the short query app against the long string apple smartphone pro scores low because most trigrams belong to the longer text.
word_similarity(a, b) fixes this by finding the best-matching contiguous portion of b. It has its own operator <% and its own GUC pg_trgm.word_similarity_threshold (default 0.6) — perfect for autocomplete where the query is a prefix or single word.
SELECT
similarity('app', 'apple smartphone') AS plain, -- low
word_similarity('app', 'apple smartphone') AS word; -- higher
-- Index-friendly autocomplete filter
SELECT name FROM products WHERE 'app' <% name;Practical Pitfalls
A few things commonly trip people up with pg_trgm:
- Very short queries (1-2 chars) have almost no trigrams, so similarity is unreliable — gate autocomplete on a minimum length.
- Case and accents: trigram matching is case-insensitive for similarity, but normalize accents (e.g. via
unaccent) if your data needs it. - Index choice: don't reach for GiST unless you need
<->KNN ordering; GIN is usually faster for%. - Threshold per use case: search, autocomplete, and dedup often want different thresholds — set them per session, not globally.
Quick Check
Test your understanding of trigram search performance.
Recap
You can now build fast, typo-tolerant search in PostgreSQL with pg_trgm:
- Trigrams split strings into 3-character chunks; shared chunks mean similarity.
similarity()scores 0-1; the % operator filters by thepg_trgm.similarity_threshold(default 0.3) and is index-aware.- Build a GIN index (
gin_trgm_ops) to accelerate%,LIKE, andILIKE— including leading wildcards. - Filter with
%, then rank withsimilarity()inORDER BY; or use<->distance with a GiST index for KNN ordering. - Use
word_similarity/<%for autocomplete, and tune thresholds per use case.
Always confirm with EXPLAIN ANALYZE that you get a Bitmap (or KNN) Index Scan rather than a Seq Scan.
เรียนรู้ SQL ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 22
- บทเรียน
- 88
คำถามที่พบบ่อย
บทเรียน “การจับคู่แบบคลุมเครือด้วยความคล้ายคลึงของ pg_trgm” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การจับคู่แบบคลุมเครือด้วยความคล้ายคลึงของ pg_trgm” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส PostgreSQL Performance & Query Optimization ให้อัปเกรดเป็น CoddyKit PRO คอร์ส PostgreSQL Performance & Query Optimization มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การจับคู่แบบคลุมเครือด้วยความคล้ายคลึงของ pg_trgm”
เพิ่มประสิทธิภาพการค้นหาที่ทนต่อการพิมพ์ผิดและการเติมคำอัตโนมัติด้วยดัชนีไตรแกรมและเกณฑ์ความคล้ายคลึง คุณปฏิบัติ PostgreSQL Performance & Query Optimization ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน PostgreSQL Performance & Query Optimization หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน PostgreSQL Performance & Query Optimization บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “การจับคู่แบบคลุมเครือด้วยความคล้ายคลึงของ pg_trgm” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน PostgreSQL Performance & Query Optimization นี้ได้ไหม
ได้ บทเรียน PostgreSQL Performance & Query Optimization ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การออกแบบคอลัมน์ tsvector และดัชนี GIN
- การจัดอันดับและปรับความเกี่ยวข้องด้วย ts_rank
- การจับคู่แบบคลุมเครือด้วยความคล้ายคลึงของ pg_trgm
- การรวมตัวกรองกับเพรดิเคตการค้นหา