חיפוש טקסט מלא ב-Postgres: tsvector, GIN ומתי לעבור ל-Elasticsearch
מאת צוות מדיה דיל · 24.06.2026 · טכנולוגיה · 4 דק׳
tsvector ו-tsquery, אינדקס GIN, דירוג עם ts_rank, stemming ומילות עצירה, faceted search ב-Elasticsearch, ושילוב עם חיפוש סמנטי מבוסס embeddings.
חיפוש טקסט עם LIKE '%term%' לא משתמש באינדקס וסורק את כל הטבלה, וגם כשמוסיפים אינדקס הוא לא יודע להתמודד עם ריבוי צורות של אותה מילה, סדר מילים שונה או דירוג תוצאות לפי רלוונטיות. Postgres כולל מנגנון חיפוש טקסט מלא מובנה — tsvector ו-tsquery עם אינדקס GIN — שפותר את רוב זה בלי להוסיף מערכת נוספת לארכיטקטורה, והשאלה המעשית היא מתי הוא מספיק ומתי כבר שווה לעבור למנוע חיפוש ייעודי כמו Elasticsearch. ההבדל הזה חוסך לצוותים רבים מערכת שלמה נוספת לתחזק, כל עוד הצרכים בפועל לא חורגים ממה שהמנוע המובנה יודע לתת.
tsvector: הפיכת טקסט למבנה שאפשר לחפש בו
tsvector הוא ייצוג מנורמל של טקסט: כל מילה עוברת stemming (לצורת השורש שלה), מילות עצירה כמו "של" ו-"את" מוסרות, ולכל token נשמרת גם הרשימה מיקומים בטקסט המקורי. השאילתה בצד השני, tsquery, עוברת אותה נורמליזציה כדי שחיפוש על "רץ" ימצא גם "רצה" ו-"ריצה". Postgres כולל תמיכה מובנית בעברית ובעוד עשרות שפות באמצעות מילוני stemming מוגדרים מראש, ואפשר גם להגדיר קונפיגורציה מותאמת אישית שמוסיפה מילון סינונימים או מילות עצירה ספציפיות לתחום של האפליקציה.
אינדקס GIN ומהירות החיפוש
בלי אינדקס, כל חיפוש טקסט מלא סורק את הטבלה כולה ומחשב tsvector בזמן אמת לכל שורה — יקר מאוד על טבלאות גדולות. אינדקס GIN (Generalized Inverted Index) שומר מיפוי הפוך מכל token לרשימת השורות שמכילות אותו, כך שחיפוש הופך לחיפוש בעץ B-tree קטן ולא לסריקה מלאה. ההבדל דומה לעיקרון שמאחורי אינדקסים רגילים ב-Postgres, רק שכאן המפתח הוא מילה ולא ערך שלם.
דירוג תוצאות עם ts_rank
מציאת שורות מתאימות זה חצי מהסיפור — צריך גם לדרג אותן. ts_rank ו-ts_rank_cd מחשבים ציון רלוונטיות לפי תדירות המילה, קרבתה למילים אחרות בשאילתה, ומשקל שאפשר להגדיר ידנית לכל שדה (כותרת חשובה יותר מגוף הטקסט, למשל, באמצעות setweight). זה מספיק כדי לבנות תוצאות חיפוש שמרגישות "חכמות" בלי שום תלות חיצונית, כל עוד מדובר בהתאמת מילות מפתח ולא בהבנה סמנטית של המשמעות.
מתי Postgres מספיק
עבור חיפוש בתוך אפליקציה אחת — חיפוש מוצרים בקטלוג, חיפוש כרטיסי תמיכה, חיפוש בתוך מסמכים פנימיים — tsvector עם GIN נותן ביצועים מצוינים בלי לתחזק מערכת נפרדת, בלי בעיית עקביות בין המסד למנוע החיפוש, ובלי עלות תפעולית נוספת. זה גם הבחירה הטבעית כשהחיפוש הוא רק תכונה משנית באפליקציה שממילא בנויה על Postgres.
מתי כדאי Elasticsearch
ברגע שיש דרישות כמו faceted search עם ריבוי פילטרים דינמיים, autocomplete ב-latency נמוך מאוד, חיפוש גיאוגרפי, ניתוח לוגים בהיקף גדול, או צורך ב-relevance tuning מתקדם ו-fuzzy matching מורכב, Elasticsearch נבנה בדיוק לזה ומספק כלים ש-Postgres לא מציע מובנה. חשוב לזכור גם ש-Elasticsearch לא מחליף מסד נתונים טרנזקציוני — הוא בדרך כלל מקבל נתונים מ-Postgres דרך CDC או ETL ומשמש כאינדקס חיפוש משני, לא כמקור אמת.
שילוב עם חיפוש סמנטי
כשהצורך הוא לא רק התאמת מילים אלא הבנת כוונה — "נעליים לריצה בגשם" שצריך למצוא גם מוצר שנקרא "נעלי טרייל עמידות למים" — לא GIN ולא Elasticsearch הרגיל פותרים את זה, וצריך חיפוש וקטורי על embeddings. בפועל הרבה מערכות חיפוש מודרניות משלבות full-text לדיוק מילולי וחיפוש סמנטי להבנת כוונה, ומאחדות את שני הציונים לתוצאה אחת — גישת hybrid search שנותנת גם דיוק על מונחים מדויקים כמו שם מוצר או קוד שגיאה, וגם גמישות כשהמשתמש מנסח את הבקשה במילים שלו.
בונים חיפוש שצריך להרגיש מדויק וגם מהיר? נשמח לעזור לכם בוואטסאפ.
תגיות: Full Text Search · Postgres · tsvector · GIN Index · Elasticsearch · חיפוש טקסט