יישום חיפוש מטושטש ליישומי אינטרנט
משתמש מקליד "נאושניק" — תוצאה ריקה. 70% מהמבקרים האלה עוזבים למתחרים. חיפוש מטושטש מתקן שגיאות הקלדה ומחזיר מוצרים רלוונטיים. לאורך השנים, יישמנו חיפוש מטושטש ביותר מ-30 פרויקטים של מסחר אלקטרוני וקטלוגים. אנו בוחרים את המנוע שמתאים לסטack שלך ולעומס: pg_trgm, Meilisearch, או Elasticsearch. עם כוונון נכון, ההמרה גדלה ב-15–25%, ועלויות התחזוקה יורדות — המקרים שלנו מאשרים זאת.
לדוגמה, עבור חנות מקוונת למוצרי חשמל ביתיים, הפחתנו את שיעור התוצאות הריקות מ-25% ל-3% על ידי מעבר ל-Meilisearch. ההמרה גדלה ב-22%. זמן התגובה ירד מ-200 אלפיות השנייה ל-4 אלפיות השנייה. הזמינו פרויקט פיילוט — נבדוק על הנתונים שלכם.
אילו אלגוריתמי מרחק משמשים?
מרחק לוונשטיין — המספר המינימלי של הכנסות, מחיקות והחלפות כדי לשנות מחרוזת אחת לאחרת, המתואר בויקיפדיה. מרחק דמרו-לוונשטיין מוסיף טרנספוזיציה (החלפת תווים סמוכים). עבור רוסית, זה עדיף: "наушники" → "наушинки" הוא טרנספוזיציה אחת במקום שתי פעולות. בפועל, אנו משתמשים במרחק דמרו-לוונשטיין. הבחירה משפיעה על האיכות: מרחק דמרו-לוונשטיין מניב 10% פחות החמצות עבור שאילתות ברוסית.
PostgreSQL: pg_trgm
ההרחבה pg_trgm עובדת עם טריגרמים ואינה דורשת שירותים חיצוניים. זה הפתרון הפשוט ביותר אם הסטack שלך כבר כולל PostgreSQL.
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE INDEX idx_products_title_trgm ON products USING GIN (title gin_trgm_ops);
CREATE INDEX idx_products_description_trgm ON products USING GIN (description gin_trgm_ops);
SET pg_trgm.similarity_threshold = 0.3;
SELECT id, title, similarity(title, 'наушниик') AS sim
FROM products
WHERE title % 'наушниик'
ORDER BY sim DESC
LIMIT 10;
-- Комбинируем fuzzy с полнотекстовым поиском
SELECT p.id, p.title, p.price,
greatest(similarity(p.title, 'беспродные наушники'), ts_rank(p.search_vector, plainto_tsquery('russian', 'беспродные наушники'))) AS relevance
FROM products p
WHERE p.title % 'беспродные наушники'
OR p.search_vector @@ plainto_tsquery('russian', 'беспродные')
ORDER BY relevance DESC
LIMIT 20;האופרטור CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE INDEX idx_products_title_trgm ON products USING GIN (title gin_trgm_ops); CREATE INDEX idx_products_description_trgm ON products USING GIN (description gin_trgm_ops); SET pg_trgm.similarity_threshold = 0.3; SELECT id, title, similarity(title, 'наушниик') AS sim FROM products WHERE title % 'наушниик' ORDER BY sim DESC LIMIT 10; -- Комбинируем fuzzy с полнотекстовым поиском SELECT p.id, p.title, p.price, greatest(similarity(p.title, 'беспродные наушники'), ts_rank(p.search_vector, plainto_tsquery('russian', 'беспродные наушники'))) AS relevance FROM products p WHERE p.title % 'беспродные наушники' OR p.search_vector @@ plainto_tsquery('russian', 'беспродные') ORDER BY relevance DESC LIMIT 20; משתמש באינדקס GIN. סף הדמיון של 0.3 הוא ליברלי; 0.5 הוא מחמיר. עבור שאילתות קצרות, בחרו בגבול הנמוך. בפועל, אנו ממליצים להתחיל ב-0.3 ולהתאים באמצעות בדיקות A/B: העלאת הסף ל-0.5 מפחיתה תוצאות חיוביות שגויות אך עלולה להחמיץ תוצאות רלוונטיות. חיסכון בתשתית עם pg_trgm מגיע עד 40% בהשוואה למנועים חיצוניים.
Meilisearch — מנוע חיפוש מטושטש ייעודי
Meilisearch כתוב ב-Rust ותומך בסובלנות לשגיאות הקלדה כברירת מחדל. הוא תוכנן במיוחד לחיפוש מטושטש מהיר ודורש מעט הגדרות.
import meilisearch
client = meilisearch.Client('http://localhost:7700', 'your-master-key')
index = client.index('products')
# Настройки индекса
index.update_settings({
'searchableAttributes': ['title', 'brand', 'description', 'tags'],
'filterableAttributes': ['category_id', 'status', 'price', 'brand'],
'sortableAttributes': ['price', 'created_at', 'popularity'],
'rankingRules': ['words', 'typo', 'proximity', 'attribute', 'sort', 'exactness'],
'typoTolerance': {
'enabled': True,
'minWordSizeForTypos': {
'oneTypo': 5,
'twoTypos': 9
},
'disableOnWords': ['iPhone', 'iPad'],
'disableOnAttributes': ['sku', 'barcode'],
},
'pagination': {
'maxTotalHits': 10000
},
})
# Батчевая индексация
batch_size = 1000
for i in range(0, len(documents), batch_size):
batch = documents[i:i + batch_size]
task = index.add_documents(batch)
index.wait_for_task(task.task_uid) דוגמה לתגובת Meilisearch
{
"hits": [
{
"id": 1234,
"title": "Sony WH-1000XM5 беспроводные наушники",
"_formatted": {
"title": "Sony WH-1000XM5 беспроводные <mark>наушники</mark>"
}
}
],
"query": "наушниик sony",
"processingTimeMs": 4,
"totalHits": 38,
"page": 1,
"hitsPerPage": 20
}Meilisearch מספק זמני תגובה ממוצעים מתחת ל-10 אלפיות השנייה עבור קטלוגים עד 10 מיליון רשומות, מהיר פי 10 מ-pg_trgm בנפחים גדולים.
Elasticsearch: שאילתת Fuzzy
אם Elasticsearch כבר בשימוש, הוסיפו fuzzy ל-multi-match:
{
"query": {
"bool": {
"should": [
{
"multi_match": {
"query": "наушниик",
"fields": ["title^3", "brand^2", "description"],
"fuzziness": "AUTO",
"prefix_length": 2,
"max_expansions": 50
}
},
{
"match_phrase": {
"title": {
"query": "наушниик",
"slop": 2
}
}
}
]
}
}
}% — התאמה מדויקת של שני התווים הראשונים מפחיתה תוצאות חיוביות שגויות. Elasticsearch מתאים לנפחים גדולים (10M+) ולשילוב אנליטיקה, אך דורש תשתית מורכבת יותר.
איזה מנוע לבחור?
| קריטריון | pg_trgm | Meilisearch | Elasticsearch |
|---|---|---|---|
| עומס | עד 100 אלף רשומות | עד 10 מיליון רשומות | 10 מיליון+ רשומות |
| מהירות | ~100 אלפיות השנייה | <10 אלפיות השנייה | <50 אלפיות השנייה |
| מורכבות | נמוכה | בינונית | גבוהה |
| מסננים/פאסטות | SQL בלבד | מובנה | עוצמתי |
| דרישות תשתית | רק PostgreSQL | שרת נפרד | קלאסטר |
עבור סטארטאפים, pg_trgm הוא אופטימלי — עלות פריסה מינימלית. אם אתם מצפים לצמיחה, תכננו מעבר ל-Meilisearch. עבור פרויקטים ארגוניים עם אנליטיקה, Elasticsearch.
למה כוונון סובלנות לשגיאות הקלדה הוא קריטי?
כל פרמטר משפיע על האיכות: ספים ליברליים מדי מייצרים רעש, מחמירים מדי מפספסים שגיאות הקלדה. בפועל, אנו משתמשים ב:
| סוג שאילתה | סובלנות מומלצת |
|---|---|
| 1–2 מילים | שגיאת הקלדה אחת (minWordSizeForTypos: 5) |
| 3–4 מילים | 2 שגיאות הקלדה (minWordSizeForTypos: 9) |
| שאילתות ארוכות (5+) | 2–3 שגיאות הקלדה |
כוונון עדין מניב עלייה של 15–25% בהמרה בהתבסס על המדידות שלנו ביותר מ-30 פרויקטים. חיסכון בעבודה מחדש לאחר השקה מגיע עד 30% מזמן הצוות.
תהליך
אנליטיקה — ביקורת על החיפוש הנוכחי, איסוף סטטיסטיקות שגיאות הקלדה. בחירת מנוע — pg_trgm, Meilisearch, או Elasticsearch עבור הסטack שלך. אינטגרציה — הגדרת אינדקסים, הגדרות, API. בדיקות — בדיקת A/B עם שאילתות אמיתיות, התאמת ספים. פריסה — ניטור ותמיכה.
לוחות זמנים
pg_trgm (הרחבה, אינדקסים, שאילתות, כוונון סף): יום אחד. Meilisearch (פריסה, הגדרה, סנכרון, API): 2–3 ימים. Fuzzy ב-Elasticsearch קיים: יום אחד.
מה כלול
הגדרת אינדקס והגדרות סוגי שגיאות הקלדה. אינטגרציה דרך REST API או SDK. תיעוד תפעולי. אחריות — אנו מתקנים באגים תוך שבועיים.
נעריך יישום חיפוש מטושטש עבור הפרויקט שלכם. קבלו ייעוץ — צרו קשר. נעזור לבחור את הפתרון האופטימלי ולהתאים אותו לסטack שלכם.







