שילוב של שאילתות עם טקסט מלא ושאילתות בלי טקסט

בדף הזה מוסבר איך לבצע חיפוש שמשלב נתונים של טקסט מלא ונתונים שאינם טקסט.

אינדקסים של חיפוש תומכים בחיפוש טקסט מלא, בהתאמה מדויקת, בעמודות מספריות ובעמודות JSON/JSONB. אפשר לשלב תנאים של טקסט ותנאים של לא-טקסט בפסקה WHERE, בדומה לשאילתות חיפוש מרובות עמודות. אופטימיזציית השאילתות מנסה לבצע אופטימיזציה של פרדיקטים שאינם טקסט באמצעות אינדקס חיפוש. אם זה לא אפשרי, Spanner מעריך את התנאי לכל שורה שתואמת לאינדקס החיפוש. עמודות שההפניה אליהן לא מאוחסנת באינדקס החיפוש מאוחזרות מהטבלה הבסיסית.

דוגמה:

GoogleSQL

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  Title STRING(MAX),
  Rating FLOAT64,
  Genres ARRAY<STRING(MAX)>,
  Likes INT64,
  Cover BYTES(MAX),
  Title_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN,
  Rating_Tokens TOKENLIST AS (TOKENIZE_NUMBER(Rating)) HIDDEN,
  Genres_Tokens TOKENLIST AS (TOKEN(Genres)) HIDDEN
) PRIMARY KEY(AlbumId);

CREATE SEARCH INDEX AlbumsIndex
ON Albums(Title_Tokens, Rating_Tokens, Genres_Tokens)
STORING (Likes);

PostgreSQL

יש מגבלות מסוימות לתמיכה ב-PostgreSQL ב-Spanner:

  • הפונקציה spanner.tokenize_number תומכת רק בסוג bigint.
  • spanner.token לא תומך בטוקניזציה של מערכים.
CREATE TABLE albums (
  albumid character varying NOT NULL,
  title character varying,
  rating bigint,
  genres character varying NOT NULL,
  likes bigint,
  cover bytea,
  title_tokens spanner.tokenlist AS (spanner.tokenize_fulltext(title)) VIRTUAL HIDDEN,
  rating_tokens spanner.tokenlist AS (spanner.tokenize_number(rating)) VIRTUAL HIDDEN,
  genres_tokens spanner.tokenlist AS (spanner.token(genres)) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));

CREATE SEARCH INDEX albumsindex
ON albums(title_tokens, rating_tokens, genres_tokens)
INCLUDE (likes);

התנהגות השאילתות בטבלה הזו כוללת את הדברים הבאים:

  • Rating ו-Genres נכללים באינדקס החיפוש. ‫Spanner מאיץ את התנאים באמצעות רשימות של פריטי אינדקס לחיפוש. ‫ARRAY_INCLUDES_ANY, ARRAY_INCLUDES_ALL הן פונקציות GoogleSQL ולא נתמכות בניב PostgreSQL.

    SELECT Album
    FROM Albums
    WHERE Rating > 4
      AND ARRAY_INCLUDES_ANY(Genres, ['jazz'])
    
  • אפשר לשלב בשאילתה בין מילות חיבור, מילות הפרדה ושלילות בכל דרך, כולל שילוב בין פרדיקטים של טקסט מלא ופרדיקטים שאינם טקסט. השאילתה הזו מואצת באופן מלא על ידי אינדקס החיפוש.

    SELECT Album
    FROM Albums
    WHERE (SEARCH(Title_Tokens, 'car')
          OR Rating > 4)
      AND NOT ARRAY_INCLUDES_ANY(Genres, ['jazz'])
    
  • הפרמטר Likes מאוחסן באינדקס, אבל הסכימה לא מבקשת מ-Spanner ליצור אינדקס של טוקנים לערכים האפשריים שלו. לכן, החיפוש המלא של הטקסט ב-Title והחיפוש של הטקסט ב-Rating מואצים, אבל החיפוש ב-Likes לא מואץ. ב-Spanner, השאילתה מאחזרת את כל המסמכים עם המונח car ב-Title ודירוג גבוה מ-4, ואז היא מסננת מסמכים שלא קיבלו לפחות 1,000 לייקים. השאילתה הזו משתמשת בהרבה משאבים אם כמעט לכל האלבומים יש את המילה 'מכונית' בשם שלהם וכמעט לכולם יש דירוג של 5, אבל רק למעט אלבומים יש 1,000 לייקים. במקרים כאלה, יצירת אינדקס Likes באופן דומה ל-Rating חוסכת משאבים.

    GoogleSQL

    SELECT Album
    FROM Albums
    WHERE SEARCH(Title_Tokens, 'car')
      AND Rating > 4
      AND Likes >= 1000
    

    PostgreSQL

    SELECT album
    FROM albums
    WHERE spanner.search(title_tokens, 'car')
      AND rating > 4
      AND likes >= 1000
    
  • הערך Cover לא מאוחסן באינדקס. השאילתה הבאה מבצעת back join בין AlbumsIndex ל-Albums כדי לאחזר את Cover לכל האלבומים התואמים.

    GoogleSQL

    SELECT AlbumId, Cover
    FROM Albums
    WHERE SEARCH(Title_Tokens, 'car')
      AND Rating > 4
    

    PostgreSQL

    SELECT albumid, cover
    FROM albums
    WHERE spanner.search(title_tokens, 'car')
      AND rating > 4
    

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