יצירה וניהול של אינדקס RUM

אינדקסים של RUM ב-AlloyDB ל-PostgreSQL מאפשרים להאיץ שאילתות חיפוש טקסט מלא על ידי אחסון מידע על מיקום ומאפיינים לצד לקסמות באינדקס. אפשר להפעיל את התוסף rum כדי ליצור אינדקסים של RUM ולשפר את דירוג הרלוונטיות, את החיפושים של ביטויים ואת המיון לפי חותמות זמן.

לפני שמתחילים

כדי ליצור את התוסף RUM, צריך להיות לכם תפקיד מסד הנתונים alloydbsuperuser.

תפקיד האדמין ב-AlloyDB‏ (roles/alloydb.admin) ב-IAM נותן שליטה מלאה במשאבים של AlloyDB, אבל לא נותן את תפקיד מסד הנתונים alloydbsuperuser. כדי ליצור את התוסף, אדמין צריך להקצות לכם באופן מפורש את התפקיד alloydbsuperuser במסד הנתונים.

מידע נוסף על הענקת תפקידים זמין במאמר הוספת חשבון משתמש או חשבון שירות ב-IAM לאשכול.

יצירת תוסף RUM

צריך ליצור את התוסף RUM פעם אחת לכל מסד נתונים.

  1. מתחברים למסד הנתונים של AlloyDB באמצעות psql או לקוח אחר. מידע נוסף זמין במאמר בנושא חיבור למופע של אשכול.
  2. מריצים את פקודת ה-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.

  1. צור טבלה בשם documents:

    CREATE TABLE documents (
      id SERIAL PRIMARY KEY,
      title TEXT NOT NULL,
      content TEXT NOT NULL,
      published_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
    );
    
  2. מאכלסים את הטבלה documents בנתונים לדוגמה:

    INSERT INTO documents (title, content) VALUES
      ('Title', 'This search engine is working as intended');
    
  3. הוספת עמודת tsvector שנוצרה לטבלה. בעמודה הזו נשמר באופן אוטומטי הטקסט שעבר עיבוד, והיא משפרת את ביצועי השאילתות:

    ALTER TABLE documents
    ADD COLUMN search_vector tsvector
    GENERATED ALWAYS AS (to_tsvector('english', content)) STORED;
    
  4. יוצרים את אינדקס ה-RUM בעמודה החדשה search_vector:

    CREATE INDEX idx_docs_rum
    ON documents
    USING rum (search_vector rum_tsvector_ops);
    
  5. שולחים שאילתה לטבלה באמצעות האינדקס. האופרטור <=> מחשב את ציון הרלוונטיות או המרחק בין המסמך לבין השאילתה ישירות מהאינדקס, וכך מאפשר מיון מהיר:

    SELECT title, content
    FROM documents
    WHERE search_vector @@ to_tsquery('english', 'search <-> engine')
    ORDER BY search_vector <=> to_tsquery('english', 'search <-> engine');
    
  6. מילוי טבלת 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');
    
  7. מריצים שאילתת חיפוש של קידומת. החיפוש הזה מוצא מסמכים שמכילים מילים שמתחילות ב-eng, כמו engineer או english:

    SELECT title, content
    FROM documents
    WHERE search_vector @@ to_tsquery('english', 'eng:*');
    

כדי להקטין את גודל האינדקס ולשפר את מהירות העדכון, משתמשים במחלקת האופרטור rum_tsvector_hash_ops. המחלקה הזו מאחסנת גיבוב (hash) של כל לקסמה במקום את הלקסמה המלאה. הגישה הזו יוצרת אינדקס קטן יותר, אבל לא תומכת בחיפוש לפי תחילית. בדוגמה הבאה נניח שיש לכם טבלה בשם documents עם עמודה בשם search_vector.

  1. יוצרים את אינדקס ה-RUM באמצעות מחלקת האופרטור hash:

    CREATE INDEX idx_docs_rum_hash
    ON documents
    USING rum (search_vector rum_tsvector_hash_ops);
    
  2. מילוי טבלת documents בנתונים נוספים:

    INSERT INTO documents (title, content) VALUES ('Title3', 'That person was driving incredibly fast, however the routing was not very efficient');
    
  3. מריצים שאילתת התאמה רגילה:

    SELECT * FROM documents WHERE search_vector @@ to_tsquery('english', 'fast & efficient');
    
    

אינדקס לחיפוש ממוין לפי חותמת זמן

משתמשים במחלקת האופרטורים rum_tsvector_addon_ops כדי לבצע אופטימיזציה של שאילתות שמסננות לפי טקסט וממיינות לפי שדה אחר, כמו חותמת זמן. התבנית הזו מאחסנת את הערך של השדה הנוסף ישירות באינדקס, וכך נמנעת פעולת מיון איטית אחרי החיפוש. בדוגמה הבאה אנחנו מניחים שיש לכם טבלה בשם documents עם עמודה search_vector ועמודה published_at.

  1. יוצרים אינדקס שכולל את חותמת הזמן של 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');
    
  2. מריצים שאילתה שמחפשת מסמכים שמכילים את המילה engine וממיינים אותם לפי תאריך הוצאה לאור. האינדקס מטפל ביעילות גם בחיפוש וגם במיון:

    SELECT title, published_at
    FROM documents
    WHERE search_vector @@ to_tsquery('english', 'engine')
    ORDER BY published_at DESC;
    

אפשר להשתמש במחלקת האופרטורים rum_anyarray_ops כדי ליצור אינדקס לעמודות של מערכים, כמו רשימה של תגים. כך אפשר לבצע שאילתות יעילות לגבי מערכים שחופפים (&&), מכילים (@>) או מוכלים (<@) במערכים אחרים. בדוגמה הבאה מוסיפים עמודה מסוג tags לטבלה documents.

  1. מוסיפים עמודה של tags וממלאים אותה בנתונים:

    ALTER TABLE documents 
    ADD COLUMN tags TEXT[];
    
    INSERT INTO documents (title, content, tags) VALUES ( 'Title4', 'Sample Text', ARRAY['ai', 'ml'] );
    
  2. יוצרים את אינדקס ה-RUM בעמודה TEXT[] בשם tags:

    CREATE INDEX idx_tags_rum
    ON documents
    USING rum (tags rum_anyarray_ops);
    
  3. מריצים שאילתה כדי למצוא מסמכים שכוללים את התגים ai או ml:

    SELECT * FROM documents WHERE tags && '{"ai", "ml"}';
    

אינדקס לסוגים סקלריים

משתמשים במחלקות האופרטורים rum_<TYPE>_ops כדי ליצור אינדקס לעמודות שמכילות ערכים רציפים, כמו מספרים שלמים, חותמות זמן או מספרים בנקודה צפה. מחלקות האופרטורים האלה מאפשרות להשתמש באופרטור <=> כדי לחשב ביעילות את המרחק בין הערכים. בדוגמה הבאה אנחנו מניחים שיש לכם טבלה בשם documents.

  1. מוסיפים עמודה של מספר שלם כללי, כמו rating, לטבלה documents:

    ALTER TABLE documents
    ADD COLUMN rating INT;
    
    UPDATE documents 
    SET rating = floor(random() * 5 + 1);
    
  2. יוצרים אינדקס RUM בעמודה rating:

    CREATE INDEX idx_rating_rum
    ON documents
    USING rum (rating rum_int4_ops);
    
  3. מריצים שאילתה כדי למצוא מסמכים עם rating שהכי קרוב לערך 5:

    SELECT title, rating
    FROM documents
    ORDER BY rating <=> 5;
    

אינדקס לחיפוש אופטימלי של גיבובים, ממוין לפי חותמת זמן

משתמשים במחלקת האופרטור rum_tsvector_hash_addon_ops כדי לשלב את היתרונות של אינדקס גיבוב עם יכולות המיון של אינדקס תוסף. במחלקת הנתונים הזו מאוחסן גיבוב של כל לקסמה, יחד עם הערך של עמודה נוספת. ההגדרה הזו תומכת במיון יעיל לפי העמודה הנוספת, אבל לא תומכת בהתאמה לתחילית. בדוגמה הבאה נניח שיש לכם טבלה בשם documents עם עמודה search_vector ועמודה של חותמות זמן published_at.

  1. יוצרים אינדקס RUM שמשתמש במחלקת האופרטור hash וכולל את חותמת הזמן של 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');
    
  2. להריץ שאילתה שמוצאת מסמכים שמכילים את engine וממיינת אותם לפי תאריך הוצאה לאור:

    SELECT title, published_at
    FROM documents
    WHERE search_vector @@ to_tsquery('english', 'engine')
    ORDER BY published_at DESC;
    

אינדקס לשאילתות מאוחסנות

משתמשים במחלקת האופרטורים rum_tsquery_ops כדי להוסיף לאינדקס ערכי tsquery. כך אפשר לבצע "חיפוש הפוך" ולזהות אילו שאילתות שמורות תואמות למסמך קלט נתון. בדוגמה הבאה נוצרת טבלה בשם queries.

  1. יוצרים טבלה לאחסון שאילתות:

    CREATE TABLE queries (
    query_text tsquery
    );
    INSERT INTO queries (query_text) VALUES (plainto_tsquery('AlloyDB is fast!'));
    
  2. יצירת אינדקס RUM בעמודה query_text:

    CREATE INDEX idx_queries_rum
    ON queries
    USING rum (query_text rum_tsquery_ops);
    
  3. מריצים שאילתה כדי למצוא שאילתות מאוחסנות שתואמות למסמך:

    SELECT *
    FROM queries
    WHERE to_tsvector('english', 'AlloyDB is fast') @@ query_text;
    

אינדקס לחיפוש במערך, ממוין לפי חותמת זמן

משתמשים במחלקת האופרטורים rum_anyarray_addon_ops כדי להוסיף לאינדקס עמודות של מערכים, יחד עם עמודה נוספת למיון. בדוגמה הבאה מניחים שיש לכם טבלה בשם documents עם עמודה tags ועמודת חותמת זמן published_at.

  1. יוצרים אינדקס 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');
    
  2. מריצים שאילתה כדי למצוא מסמכים עם התג ai, ממוינים לפי תאריך הוצאה לאור:

    SELECT title, published_at
    FROM documents
    WHERE tags @> '{"ai"}'
    ORDER BY published_at DESC;
    

המאמרים הבאים