דירוג תוצאות החיפוש

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

‫Spanner תומך בחישוב ציון רלוונטיות לנושא, שמספק אבן בניין ליצירת פונקציות דירוג מתוחכמות. הציונים האלה מחושבים על סמך הרלוונטיות של תוצאה לשאילתה, בהתבסס על התדירות של מונח השאילתה ואפשרויות אחרות שניתנות להתאמה אישית.

בדוגמה הבאה אפשר לראות איך מבצעים חיפוש מדורג באמצעות הפונקציה SCORE:

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
ORDER BY SCORE(AlbumTitle_Tokens, "fifth symphony") DESC

PostgreSQL

בדוגמה הזו נעשה שימוש ב-spanner.search עם spanner.score.

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY spanner.score(albumtitle_tokens, 'fifth symphony') DESC

הקצאת ציון למונחי שאילתות באמצעות הפונקציה SCORE

הפונקציה SCORE מחשבת ציון לכל מונח בשאילתה, ואז משלבת את הציונים. הניקוד לכל מונח מבוסס בערך על תדירות המונח – תדירות מסמך הפוכה (TF/IDF). הניקוד הוא רכיב אחד בסדר הסופי של הרשומה. השאילתה משלבת את זה עם אותות אחרים, כמו עדכניות שמשפיעה על ניקוד הרלוונטיות לנושא.

ביישום הנוכחי, החלק IDF של TF/IDF זמין רק כשמשתמשים ב-enhance_query=>true. הוא מחשב את התדירות היחסית של מילים על סמך מאגר הנתונים המלא של האינטרנט שמשמש את חיפוש Google, ולא על סמך אינדקס חיפוש ספציפי. אם לא מפעילים את שיפור השאילתה, הניקוד מבוסס רק על רכיב תדירות המונח (TF) (כלומר, מונח ה-IDF מוגדר כ-1).

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

בדרך כלל הארגומנטים כמו query ו-enhance_query זהים בפונקציות SEARCH ו-SCORE כדי להבטיח עקביות באחזור ובדירוג.

הדרך המומלצת לעשות את זה היא להשתמש בארגומנטים האלה עם פרמטרים של שאילתה ולא עם מחרוזות מילוליות, ולציין את אותם פרמטרים של שאילתה בפונקציות SEARCH ו-SCORE.

הוספת ניקוד למספר עמודות

ב-Spanner נעשה שימוש בפונקציה SCORE כדי לתת ניקוד לכל שדה בנפרד. לאחר מכן, השאילתה משלבת את הציונים הנפרדים האלה. דרך נפוצה לעשות את זה היא לסכם את הציונים האישיים ואז להגדיל אותם בהתאם למשקלים של השדות שסופקו על ידי המשתמש (שמסופקים באמצעות פרמטרים של שאילתת SQL).

לדוגמה, השאילתה הבאה משלבת את הפלט של שתי פונקציות SCORE:

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(Title_Tokens, @p1) OR SEARCH(Studio_Tokens, @p2)
ORDER BY SCORE(Title_Tokens, @p1) * @titleweight + SCORE(Studio_Tokens, @p2) * @studioweight
LIMIT 25

PostgreSQL

בדוגמה הזו נעשה שימוש בפרמטרים של שאילתה $1 ו-$2 שמשויכים לערכים fifth symphony ו-blue note, בהתאמה.

SELECT albumid
FROM albums
WHERE spanner.search(title_tokens, $1) OR spanner.search(studio_tokens, $2)
ORDER BY spanner.score(title_tokens, $1) * $titleweight
        + spanner.score(studio_tokens, $2) * $studioweight
LIMIT 25

בדוגמה הבאה מוסיפים שני פרמטרים של הגברת עוצמה:

  • עדכניות (FreshnessBoost) מעלה את הציון ב-(1 + @freshnessweight * GREATEST(0, 30 - DaysOld) / 30)
  • הפונקציה Popularity(PopularityBoost) מגדילה את הניקוד על ידי הכפלה שלו בפקטור (1 + IF(HasGrammy, @grammyweight, 0).

כדי שהשאילתה תהיה קלה יותר לקריאה, נעשה בה שימוש באופרטור WITH.

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(Title_Tokens, @p1) OR SEARCH(Studio_Tokens, @p2)
ORDER BY WITH(
  TitleScore AS SCORE(Title_Tokens, @p1) * @titleweight,
  StudioScore AS SCORE(Studio_Tokens, @p2) * @studioweight,
  DaysOld AS (UNIX_MICROS(CURRENT_TIMESTAMP()) - ReleaseTimestamp) / 8.64e+10,
  FreshnessBoost AS (1 + @freshnessweight * GREATEST(0, 30 - DaysOld) / 30),
  PopularityBoost AS (1 + IF(HasGrammy, @grammyweight, 0)),
  (TitleScore + StudioScore) * FreshnessBoost * PopularityBoost)
LIMIT 25

PostgreSQL

בדוגמה הזו נעשה שימוש בפרמטרים של שאילתה $1,‏ $2,‏ $3,‏ $4,‏ $5 ו-$6 שמקושרים לערכים שצוינו עבור titlequery,‏ studioquery,‏ titleweight,‏ studioweight,‏ grammyweight ו-freshnessweight, בהתאמה.

SELECT albumid
FROM
  (
    SELECT
      albumid,
      spanner.score(title_tokens, $1) * $3 AS titlescore,
      spanner.score(studio_tokens, $2) * $4 AS studioscore,
      (extract(epoch FROM current_timestamp) * 10e+6 - releasetimestamp) / 8.64e+10 AS daysold,
      (1 + CASE WHEN hasgrammy THEN $5 ELSE 0 END) AS popularityboost
    FROM albums
    WHERE spanner.search(title_tokens, $1) OR spanner.search(studio_tokens, $2)
  ) AS subquery
ORDER BY (subquery.TitleScore + subquery.studioscore)
  * (1 + $6 * greatest(0, 30 - subquery.daysold) / 30) * subquery.popularityboost
LIMIT 25

TOKENLIST_CONCAT יכולה לשמש גם לחיפוש ולדירוג כדי לפשט שאילתות כשזה מתאים.

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(TOKENLIST_CONCAT([Title_Tokens, Studio_Tokens]), @p)
ORDER BY SCORE(TOKENLIST_CONCAT([Title_Tokens, Studio_Tokens]), @p)
LIMIT 25

PostgreSQL

בדוגמה הזו נעשה שימוש ב-spanner.tokenlist_concat. פרמטר השאילתה $1 קשור ל-'blue note'.

SELECT albumid
FROM albums
WHERE spanner.search(spanner.tokenlist_concat(ARRAY[title_tokens, studio_tokens]), $1)
ORDER BY spanner.score(spanner.tokenlist_concat(ARRAY[title_tokens, studio_tokens]), $1)
LIMIT 25

שיפור ההתאמות של הזמנות לשאילתות

‫Spanner מחיל הגברה כפלית על הפלט של הפונקציה SCORE עבור ערכים שמכילים את מונחי השאילתה באותו סדר שבו הם מופיעים בשאילתה. יש שתי גרסאות של ההגדרה הזו: התאמה חלקית והתאמה מדויקת. הגברת התאמה חלקית מתרחשת במקרים הבאים:

  1. התג TOKENLIST מכיל את כל המונחים המקוריים בשאילתה.
  2. האסימונים צמודים זה לזה, ובאותו סדר שבו הם מופיעים בשאילתה.

יש כללים מיוחדים מסוימים לגבי מילות קישור, שלילות וצירופי מילים:

  • אי אפשר להגדיר לשאילתה עם שלילה הגברה של התאמה חלקית.
  • שאילתה עם מילת חיבור מקבלת דחיפה אם חלק ממילת החיבור מופיע במיקומים המתאימים.
  • שאילתה עם ביטוי מקבלת דחיפה אם הביטוי מופיע ב-TOKENLIST, והמונח שמשמאל לביטוי בשאילתה מופיע משמאל לביטוי ב-TOKENLIST, וכך גם לגבי המונח שמימין לביטוי.

‫Spanner מחיל חיזוק של התאמה מדויקת כשכל הכללים הקודמים מתקיימים, והטוקנים הראשון והאחרון בשאילתה הם הטוקנים הראשון והאחרון במסמך.

מסמך לדוגמה: Bridge Over Troubled Water

שאילתה ההגברה הוחלה
Bridge Troubled ללא הגדלה
גשר מעל – מים אחרים ללא הגדלה
Bridge (Over OR Troubled) Water ללא הגדלה
Bridge Over הגדלה חלקית
Bridge Over (Troubled OR Water) הגדלה חלקית
Bridge Over Troubled Water הגברה מדויקת
הגשר מעל המים הסוערים הגברה מדויקת
Bridge ("Over Troubled" OR missingterm) Water הגברה מדויקת

גרסאות של כלי הניקוד

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

אתם יכולים להגדיר את גרסת הכלי לחישוב ניקוד כברירת מחדל למסד הנתונים, או לציין גרסה לשאילתה ספציפית.

הגדרת גרסת ברירת המחדל של כלי הניקוד במסד הנתונים

אפשר להגדיר את גרסת ברירת המחדל של אלגוריתם הניקוד למסד הנתונים. האפשרות הזו קובעת באיזו גרסה של אלגוריתם הניקוד Spanner משתמש כשקוראים לפונקציה SCORE בלי אפשרות ניקוד version מפורשת.

GoogleSQL

מגדירים את האפשרות score_version מסד נתונים:

ALTER DATABASE database_name SET OPTIONS (score_version = 2)

PostgreSQL

מגדירים את האפשרות spanner.score_version מסד נתונים:

ALTER DATABASE database_name SET "spanner.score_version" = 2

הערכים התקינים לאפשרות מסד הנתונים הם 1 או 2. אם הפרמטר version מופיע בבקשה, הוא מבטל את גרסת ברירת המחדל של מסד הנתונים.

שינוי גרסת הכלי לניקוד לכל שאילתה

אפשר לשנות את גרסת ברירת המחדל של הדירוג לשאילתה ספציפית באמצעות הפרמטר version בארגומנט options של הפונקציה SCORE. אם שאילתה מגדירה גרסה של כלי לדירוג, היא מבטלת את הגרסה שמוגדרת כברירת מחדל במסד הנתונים.

בדוגמה הבאה מוחלפת גרסת הכלי לחישוב ניקוד ברירת המחדל על ידי ציון version בפרמטר options:

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, @query)
ORDER BY SCORE(
  AlbumTitle_Tokens,
  @query,
  options=>JSON '{"version": 2}'
) DESC

PostgreSQL

בדוגמה הזו נעשה שימוש בפרמטר השאילתה $1 שמשויך למחרוזת השאילתה.

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, $1)
ORDER BY spanner.score(
  albumtitle_tokens,
  $1,
  options => '{"version": 2}'::jsonb
) DESC

הגבלת עומק האחזור

אינדקסים של חיפושים מכילים בדרך כלל מיליוני מסמכים. בשאילתות שבהן יש פרדיקטים עם סלקטיביות נמוכה, לא מעשי לדרג את כל התוצאות. בדרך כלל יש שתי מגבלות על שאילתות ניקוד:

  1. מגבלת עומק האחזור: מספר השורות המקסימלי לניקוד.
  2. מגבלת גודל של קבוצת תוצאות: המספר המקסימלי של שורות שהשאילתה צריכה להחזיר (בדרך כלל גודל הדף).

אפשר להגביל את עומק האחזור של שאילתות באמצעות שאילתות משנה של SQL:

GoogleSQL

SELECT AlbumId
FROM
  (
    SELECT AlbumId, SCORE(Title_Tokens, @p1) AS score
    FROM Albums
    WHERE SEARCH(Title_Tokens, @p1)
    ORDER BY ReleaseTimestamp DESC
    LIMIT @retrieval_limit
  )
ORDER BY score DESC
LIMIT @page_size

PostgreSQL

בדוגמה הזו נעשה שימוש בפרמטרים של שאילתה $1, $2 ו-$3 שמשויכים לערכים שצוינו עבור title_query, retrieval_limit ו-page_size, בהתאמה.

SELECT albumid
FROM
  (
    SELECT albumid, spanner.score(title_tokens, $1) AS score
    FROM albums
    WHERE spanner.search(title_tokens, $1)
    ORDER BY releasetimestamp DESC
    LIMIT $2
  ) AS subquery
ORDER BY score DESC
LIMIT $3

השיטה הזו יעילה במיוחד אם Spanner משתמש באות הדירוג הכי חשוב כדי למיין את האינדקס.

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