חיפוש טקסט מלא באמצעות pg_textsearch

התוסף pg_textsearch ב-Cloud SQL ל-PostgreSQL מספק חיפוש טקסט מלא באמצעות אלגוריתם הניקוד BM25 (Best Matching 25), שהוא אלגוריתם סטנדרטי בתעשייה, כדי לספק ניקוד רלוונטיות מדויק מאוד. התוסף הוא פרויקט קוד פתוח שזמין ב-GitHub.

התוסף pg_textsearch דורש PostgreSQL מגרסה 17 ואילך.

מכיוון ש-pg_textsearch תומכת בתדירות מסמך הפוכה, ברוויית תדירות מונחים ובנורמליזציה של אורך המסמך, היא יכולה להפיק תוצאות רלוונטיות יותר מאשר הפונקציה המובנית ts_rank של PostgreSQL. בנוסף, מכיוון שהוא פועל ישירות בדפי אחסון רגילים של PostgreSQL, לא צריך להתקין מנוע חיצוני כמו Elasticsearch, או לדאוג לתחזוקה של שני אשכולות ולסנכרון נתונים. באמצעות pg_textsearch, אתם יכולים ליצור חוויות חיפוש חזקות, ניתנות להרחבה ורלוונטיות מאוד בלי לצאת מהסביבה של PostgreSQL.

יש כמה אפשרויות לחיפוש טקסט ב-Cloud SQL ל-PostgreSQL:

  • התאמה מדויקת: בחיפוש SQL סטנדרטי, משתמשים בהצהרות LIKE ו-ILIKE כדי לסרוק רצף מדויק של תווים. דוגמה לשאילתה: ILIKE '%smart fitness watches%'. השאילתה הזו תמצא מופעים כמו:

    • "כדאי לעיין במבצעים שלנו על שעוני כושר חכמים חדשים".
    • "שעונים חכמים לאימוני כושר הם מתנות נהדרות".

    עם זאת, היא לא תצליח למצוא:

    • "Runners want a smart waterproof fitness watch."
    • ‫"This watch is particularly smart about fitness."
  • חיפוש טקסט מלא: חיפוש טקסט מלא משתמש באלגוריתם BM25 ובפונקציה tsvector כדי לחלק את הטקסט למילים בסיסיות, להתעלם ממילות סינון ולדרג את הרלוונטיות. היא מבינה את כללי השפה, כולל צורות רבים ודקדוק, ומתחשבת בתדירות המילים. חיפוש טקסט מלא של smart AND fitness AND watches ימצא את המקרים שהשאילתה לדוגמה עם ההתאמה המדויקת לא תמצא, וגם מקרים מורכבים יותר כמו אלה:

    • "שעון חכם מושלם לשגרת הכושר היומית שלך".
    • "Not every watch is this smart when it comes to fitness."

    עם זאת, היא לא תצליח למצוא:

    • "שעון חכם שמודע לבריאות יכול לעזור לכם בתוכנית האימונים".
    • "הצמיד החכם הזה למעקב אחר פעילות גופנית הוא מציאה".
  • חיפוש סמנטי: חיפוש סמנטי ממיר טקסט לווקטורים ומודד את מרחק הדמיון באמצעות מודלים של AI. הוא מבין משמעות, כוונה, הקשר, מילים נרדפות ומושגים קשורים. חיפוש סמנטי של smart fitness watches ימצא את המקרים לדוגמה ששיטות החיפוש האחרות יפספסו. הוא יבין ש'שעון חכם עם מעקב אחר מדדי בריאות' זהה ל'שעון לאימוני כושר', וגם ש'צמיד חכם עם מעקב אחר פעילות גופנית' יכול להיות רלוונטי. יכול להיות שהיא תתאים בטעות לרצועת מד צעדים אם היא לא תיתן עדיפות מספקת למילה 'שעון'.

התקנת התוסף pg_textsearch

כדי להתקין ולהפעיל את pg_textsearch, פועלים לפי השלבים הבאים:

  1. מגדירים את הדגל cloudsql.enable_pg_textsearch לערך on כמו שמתואר במאמר הגדרת דגלים של מסד נתונים. הפעולה הזו תוסיף את pg_textsearch לshared_preload_libraries.

  2. התקנת התוסף pg_textsearch

      CREATE EXTENSION pg_textsearch;
    
  3. מאמתים את ההתקנה:

      SELECT extversion FROM pg_extension WHERE extname = 'pg_textsearch'
    

חיפוש באמצעות pg_textsearch

נניח שמילאתם נתונים בטבלת הדוגמה הבאה:

CREATE TABLE documents (
    doc_id TEXT PRIMARY KEY,
    content TEXT,
    text_embedding vector(3072)
    GENERATED ALWAYS AS (embedding('gemini-embedding-001', content)) STORED 
  );

לפני שמשתמשים בחיפוש טקסט מלא, צריך ליצור קודם אינדקס BM25:

CREATE INDEX idx_docs_bm25
      ON documents
      USING bm25 (content)
      WITH (text_config = 'english');

אחר כך אפשר להזין שאילתת חיפוש של טקסט מלא, כמו זו:

SELECT doc_id, content, content <@> 'database system'
      AS score FROM documents
      ORDER BY content <@> 'database system'
      ASC LIMIT 5;

ביצוע חיפושים היברידיים באמצעות pg_textsearch ו-vector

אתם יכולים להשתמש ב-pg_textsearch יחד עם התוסף vector חיפוש סמנטי כדי לבצע חיפושים היברידיים. כך מתקינים את התוסף vector חיפוש סמנטי:

CREATE EXTENSION IF NOT EXISTS vector CASCADE;

מזינים שאילתת חיפוש היברידית סמנטית וטקסט מלא, כמו זו:

WITH
  -- Semantic search results
  vector_search AS (
    SELECT doc_id,
      RANK () OVER (ORDER BY text_embedding <=>
                             google_ml.embedding('gemini-embedding-001',
                                                 'database')::VECTOR ) AS rank
      FROM documents
      ORDER BY text_embedding <=> google_ml.embedding('gemini-embedding-001',
                                                      'database')::VECTOR
    LIMIT 10
  ),
  -- Full text search results
  text_search AS (
    SELECT doc_id,
      RANK () OVER (ORDER BY content <@> 'database' ASC) AS rank
    FROM documents
    ORDER BY content <@> 'database' ASC
    LIMIT 10
  )
  -- RRF combining both semantic and full text search results
  SELECT
    COALESCE(vector_search.doc_id, text_search.doc_id) AS id,
    COALESCE(1.0 / (60 + vector_search.rank), 0.0) +
    COALESCE(1.0 / (60 + text_search.rank), 0.0) AS rrf_score
  FROM vector_search
    FULL OUTER JOIN text_search ON vector_search.doc_id = text_search.doc_id
  ORDER BY rrf_score DESC
  LIMIT 5;

דגלים להגדרת התוסף pg_textsearch

כדי להגדיר חיפוש טקסט מלא של pg_textsearch, משתמשים בדגלים הבאים:

  • pg_textsearch.bulk_load_threshold: תנאים לכל טרנזקציה לפני מעבר אוטומטי. כדי להשבית, צריך להגדיר את הערך כ-0. ברירת מחדל: 100,000.
  • pg_textsearch.compress_segments: דחיסת בלוקים של פוסטים בפלחים חדשים. ברירת מחדל: on.
  • pg_textsearch.default_limit: המספר המקסימלי של מסמכים שקיבלו ניקוד כשלא מופיעה פסוקית LIMIT. ברירת מחדל: 1,000.
  • pg_textsearch.memtable_pages_threshold: מספר הדפים לשרשור לפני מעבר אוטומטי לדף הבא. כדי להשבית, צריך להגדיר את הערך כ-0. ברירת מחדל: 64.
  • pg_textsearch.segments_per_level: מספר הפלחים בכל רמה לפני שהדחיסה האוטומטית מתבצעת. הטווח: 2-64. ברירת מחדל: 8.