במסמך הזה מוסבר איך ליצור את התוסף RUM ואינדקסים כדי לבצע אופטימיזציה של חיפוש טקסט מלא ב-AlloyDB ל-PostgreSQL. הוא כולל דוגמאות לתרחישי שימוש נפוצים, כולל דירוג, חיפוש של צירופי מילים ומיון לפי חותמת זמן.
לפני שמתחילים
כדי ליצור את התוסף RUM, צריך להיות לכם תפקיד מסד הנתונים alloydbsuperuser.
תפקיד האדמין ב-AlloyDB (roles/alloydb.admin) ב-IAM מעניק שליטה מלאה במשאבי AlloyDB, אבל לא מעניק את תפקיד מסד הנתונים alloydbsuperuser. כדי ליצור את התוסף, אדמין צריך להעניק לכם באופן מפורש את תפקיד מסד הנתונים alloydbsuperuser.
מידע נוסף על הענקת תפקידים זמין במאמר הוספת חשבון משתמש או חשבון שירות ב-IAM לאשכול.
יצירת תוסף RUM
צריך ליצור את תוסף ה-RUM פעם אחת לכל מסד נתונים.
- מתחברים למסד הנתונים של AlloyDB באמצעות
psqlאו לקוח אחר. מידע נוסף זמין במאמר בנושא חיבור למופע של אשכול. מריצים את פקודת ה-SQL הבאה כדי ליצור את התוסף:
CREATE EXTENSION IF NOT EXISTS rum;
יצירת אינדקס RUM
כדי לבצע אופטימיזציה של שאילתות חיפוש טקסט מלא, צריך ליצור אינדקס RUM על הנתונים. RUM מציע כמה מחלקות אופרטורים לתרחישי שימוש שונים.
סוגים של מחלקות אופרטורים של RUM
בטבלה הבאה מסוכמים הסוגים השונים של אופרטורים של RUM והתרחישים העיקריים לשימוש בהם.
| סוג המפעיל | תרחיש השימוש העיקרי | מגבלות |
|---|---|---|
rum_tsvector_ops |
חיפוש טקסט מלא רגיל עם דירוג וחיפוש ביטויים. | לא רלוונטי |
rum_tsvector_hash_ops |
אינדקס קטן יותר ועדכונים מהירים יותר לחיפוש טקסט מלא. | לא תומך בחיפוש לפי קידומת. |
rum_tsvector_addon_ops |
חיפוש טקסט מלא שממוין לפי עמודה אחרת. | לא רלוונטי |
rum_anyarray_ops |
חיפוש בעמודות של מערכים. | לא רלוונטי |
rum_<TYPE>_ops |
יצירת אינדקס לסוגים סקלריים של שאילתות שמבוססות על מרחק. | לא רלוונטי |
rum_tsvector_hash_addon_ops |
חיפוש טקסט מלא מבוסס-גיבוב שממוין לפי עמודה אחרת. | אין תמיכה בהתאמה של קידומות. |
rum_tsquery_ops |
יצירת אינדקס של ערכי tsquery מאוחסנים לחיפוש הפוך. |
לא רלוונטי |
rum_anyarray_addon_ops |
חיפוש במערך ממוין לפי עמודה אחרת. | לא רלוונטי |
אינדקס לחיפוש טקסט מלא בסיסי
משתמשים במחלקת האופרטורים rum_tsvector_ops לחיפוש טקסט רגיל שדורש דירוג מהיר ויכולות חיפוש של צירופי מילים. במחלקת האופרטורים הזו מאוחסן המיקום של כל לקסמה באינדקס. בדוגמה הבאה נוצרת טבלה בשם documents עם עמודה בשם content.
צור טבלה בשם
documents:CREATE TABLE documents ( id SERIAL PRIMARY KEY, title TEXT NOT NULL, content TEXT NOT NULL, published_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() );מאכלסים את הטבלה
documentsבנתונים לדוגמה:INSERT INTO documents (title, content) VALUES ('Title', 'This search engine is working as intended');מוסיפים לטבלה עמודה שנוצרה על ידי
tsvector. בעמודה הזו מאוחסן באופן אוטומטי הטקסט שעבר עיבוד, והיא משפרת את ביצועי השאילתות:ALTER TABLE documents ADD COLUMN search_vector tsvector GENERATED ALWAYS AS (to_tsvector('english', content)) STORED;יוצרים את אינדקס ה-RUM בעמודה החדשה
search_vector:CREATE INDEX idx_docs_rum ON documents USING rum (search_vector rum_tsvector_ops);שולחים שאילתה לטבלה באמצעות האינדקס. האופרטור
<=>מחשב את ציון הרלוונטיות או המרחק בין המסמך לבין השאילתה ישירות מהאינדקס, וכך מאפשר מיון מהיר:SELECT title, content FROM documents WHERE search_vector @@ to_tsquery('english', 'search <-> engine') ORDER BY search_vector <=> to_tsquery('english', 'search <-> engine');מילוי טבלת
documentsבנתונים נוספים:INSERT INTO documents (title, content) VALUES ('Title1', 'English is my primary language.'); INSERT INTO documents (title, content) VALUES ('Title2', 'Google has a great engineering culture');מריצים שאילתת חיפוש של קידומת. כך מוצאים מסמכים שמכילים מילים שמתחילות ב-
eng, כמוengineerאוenglish:SELECT title, content FROM documents WHERE search_vector @@ to_tsquery('english', 'eng:*');
אינדקס לחיפוש אופטימלי של גיבוב
כדי להקטין את גודל האינדקס ולשפר את מהירויות העדכון, משתמשים במחלקת האופרטורים rum_tsvector_hash_ops. במחלקה הזו מאוחסן גיבוב של כל לקסמה במקום הלקסמה המלאה. הגישה הזו יוצרת אינדקס קטן יותר, אבל לא תומכת בחיפוש של תחיליות. בדוגמה הבאה נניח שיש לכם טבלה בשם documents עם עמודה בשם search_vector.
יוצרים את אינדקס ה-RUM באמצעות מחלקת האופרטורים של הגיבוב:
CREATE INDEX idx_docs_rum_hash ON documents USING rum (search_vector rum_tsvector_hash_ops);מילוי טבלת
documentsבנתונים נוספים:INSERT INTO documents (title, content) VALUES ('Title3', 'That person was driving incredibly fast, however the routing was not very efficient');הפעלת שאילתת התאמה רגילה:
SELECT * FROM documents WHERE search_vector @@ to_tsquery('english', 'fast & efficient');
אינדקס לחיפוש ממוין לפי חותמת זמן
משתמשים במחלקת האופרטורים rum_tsvector_addon_ops כדי לבצע אופטימיזציה של שאילתות שמסננות לפי טקסט וממיינות לפי שדה אחר, כמו חותמת זמן. בדפוס הזה, הערך של השדה הנוסף מאוחסן ישירות באינדקס, וכך נמנעת פעולת מיון איטית אחרי החיפוש. בדוגמה הבאה מניחים שיש לכם טבלה בשם documents עם עמודה search_vector ועמודה published_at.
יוצרים אינדקס שכולל את חותמת הזמן
published_at:CREATE INDEX idx_docs_rum_timestamp ON documents USING rum (search_vector rum_tsvector_addon_ops, published_at) WITH (attach = 'published_at', to = 'search_vector');מריצים שאילתה שמחפשת מסמכים שמכילים את המילה
engineוממיינת אותם לפי תאריך הוצאה לאור. האינדקס מטפל ביעילות גם בחיפוש וגם במיון:SELECT title, published_at FROM documents WHERE search_vector @@ to_tsquery('english', 'engine') ORDER BY published_at DESC;
אינדקס לחיפוש במערך
אפשר להשתמש במחלקת האופרטורים rum_anyarray_ops כדי ליצור אינדקס לעמודות של מערכים, כמו רשימה של תגים. כך אפשר לבצע שאילתות יעילות לגבי מערכים שחופפים (&&), מכילים (@>) או מוכלים על ידי (<@) מערכים אחרים. בדוגמה הבאה מוסיפים עמודה tags לטבלה documents.
מוסיפים עמודה
tagsומאכלסים אותה בנתונים:ALTER TABLE documents ADD COLUMN tags TEXT[]; INSERT INTO documents (title, content, tags) VALUES ( 'Title4', 'Sample Text', ARRAY['ai', 'ml'] );יוצרים את אינדקס ה-RUM בעמודה
TEXT[]בשםtags:CREATE INDEX idx_tags_rum ON documents USING rum (tags rum_anyarray_ops);מריצים שאילתה כדי למצוא מסמכים שיש להם את התגים
aiאוml:SELECT * FROM documents WHERE tags && '{"ai", "ml"}';
אינדקס של סוגים סקלריים
משתמשים במחלקות האופרטורים rum_<TYPE>_ops כדי ליצור אינדקס לעמודות שמכילות ערכים רציפים, כמו מספרים שלמים, חותמות זמן או מספרים עם נקודה צפה (floating-point). בעזרת המחלקות האלה של אופרטורים אפשר להשתמש באופרטור <=> כדי לחשב ביעילות את המרחק בין ערכים. בדוגמה הבאה אנחנו מניחים שיש לכם טבלה בשם documents.
מוסיפים עמודה כללית של מספרים שלמים, כמו
rating, לטבלהdocuments:ALTER TABLE documents ADD COLUMN rating INT; UPDATE documents SET rating = floor(random() * 5 + 1);יוצרים אינדקס RUM בעמודה
rating:CREATE INDEX idx_rating_rum ON documents USING rum (rating rum_int4_ops);מריצים שאילתה כדי למצוא מסמכים עם
ratingהכי קרוב לערך 5:SELECT title, rating FROM documents ORDER BY rating <=> 5;
אינדקס לחיפוש אופטימלי של גיבובים, ממוין לפי חותמת זמן
משתמשים במחלקת האופרטורים rum_tsvector_hash_addon_ops כדי לשלב את היתרונות של אינדקס גיבוב עם יכולות המיון של אינדקס תוסף. במחלקת הנתונים הזו מאוחסן גיבוב של כל לקסמה, יחד עם הערך של עמודה נוספת. ההגדרה הזו תומכת במיון יעיל לפי העמודה הנוספת, אבל לא תומכת בהתאמה של קידומת. בדוגמה הבאה מניחים שיש לכם טבלה בשם documents עם עמודה search_vector ועמודת חותמת זמן published_at.
יוצרים אינדקס RUM שמשתמש במחלקת אופרטור הגיבוב וכולל את
published_atחותמת הזמן:CREATE INDEX idx_docs_rum_hash_timestamp ON documents USING rum (search_vector rum_tsvector_hash_addon_ops, published_at) WITH (attach = 'published_at', to = 'search_vector');מריצים שאילתה שמוצאת מסמכים שמכילים את
engineוממיינים אותם לפי תאריך הוצאה לאור:SELECT title, published_at FROM documents WHERE search_vector @@ to_tsquery('english', 'engine') ORDER BY published_at DESC;
אינדקס לשאילתות מאוחסנות
משתמשים במחלקת האופרטורים rum_tsquery_ops כדי ליצור אינדקס לערכים של tsquery. כך אפשר לבצע 'חיפוש הפוך' ולזהות אילו שאילתות מאוחסנות תואמות למסמך קלט נתון. בדוגמה הבאה נוצרת טבלה בשם queries.
יוצרים טבלה לאחסון שאילתות:
CREATE TABLE queries ( query_text tsquery ); INSERT INTO queries (query_text) VALUES (plainto_tsquery('AlloyDB is fast!'));יוצרים אינדקס RUM בעמודה
query_text:CREATE INDEX idx_queries_rum ON queries USING rum (query_text rum_tsquery_ops);מריצים שאילתה כדי למצוא שאילתות שמורות שתואמות למסמך:
SELECT * FROM queries WHERE to_tsvector('english', 'AlloyDB is fast') @@ query_text;
אינדקס לחיפוש במערך, ממוין לפי חותמת זמן
משתמשים במחלקת האופרטורים rum_anyarray_addon_ops כדי ליצור אינדקס לעמודות של מערכים יחד עם עמודה נוספת למיון. בדוגמה הבאה נניח שיש לכם טבלה בשם documents עם עמודה tags ועמודת חותמת זמן published_at.
יוצרים אינדקס RUM בעמודה
tagsשכוללת את חותמת הזמןpublished_at:CREATE INDEX idx_tags_rum_timestamp ON documents USING rum (tags rum_anyarray_addon_ops, published_at) WITH (attach = 'published_at', to = 'tags');מריצים שאילתה כדי למצוא מסמכים עם התג
ai, ממוינים לפי תאריך הוצאה לאור:SELECT title, published_at FROM documents WHERE tags @> '{"ai"}' ORDER BY published_at DESC;