為搜尋結果排名

本頁說明如何在 Spanner 中,為全文搜尋結果排名。

Spanner 支援計算主題性分數,可做為建立複雜排名函式的建構區塊。這些分數會根據查詢字詞頻率和其他可自訂選項,計算結果與查詢的關聯性。

以下範例說明如何使用 SCORE 函式執行排名搜尋:

GoogleSQL

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

PostgreSQL

本範例使用 spanner.searchspanner.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) 計算而得。分數是記錄最終排序的其中一個要素。查詢會將這項信號與其他信號合併,例如新鮮度會調控主題分數。

在目前的實作項目中,只有在使用 enhance_query=>true 時,才能取得 TF/IDF 的 IDF 部分。這項工具會根據 Google 搜尋使用的完整網路語料庫,而非特定搜尋索引,計算字詞的相對頻率。如果未啟用 rquery 強化功能,評分只會使用詞頻 (TF) 元件 (也就是 IDF 字詞設為 1)。

SCORE 函式會傳回相關分數,Spanner 會根據這些分數建立排序順序。沒有獨立意義。分數越高,表示與查詢的相符程度越高。

通常 SEARCHSCORE 函式中的 queryenhance_query 等引數會相同,確保擷取和排序作業的一致性。

建議您使用這些引數搭配查詢參數,而非字串常值,並在 SEARCHSCORE 函式中指定相同的查詢參數。

為多個資料欄評分

Spanner 會使用 SCORE 函式,個別為每個欄位評分。然後查詢會將這些個別分數合併。常見做法是加總個別分數,然後根據使用者提供的欄位權重 (使用 SQL 查詢參數提供) 提高分數。

舉例來說,下列查詢會合併兩個 SCORE 函式的輸出內容:

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(Title_Tokens, @p1) AND 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) AND 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)
  • 熱門程度(PopularityBoost) 會將分數乘以係數 (1 + IF(HasGrammy, @grammyweight, 0),藉此提高分數。

為了方便閱讀,查詢會使用 WITH 運算子。

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(Title_Tokens, @p1) AND 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,這些參數分別繫結至 titlequerystudioquerytitleweightstudioweightgrammyweightfreshnessweight 指定的值。

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) AND 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 中詞組左側,且查詢中詞組右側的字詞出現在 TOKENLIST 中詞組右側,則含有該詞組的查詢會獲得加成。

如果先前的所有規則都成立,且查詢中的第一個和最後一個符記與文件中的第一個和最後一個符記相同,Spanner 就會套用完全比對的提升效果。

範例文件:Bridge Over Troubled Water

查詢 已套用 Boost
Bridge Troubled 不加成
Bridge Over - other water 不加成
Bridge (Over OR Troubled) Water 不加成
Bridge Over 部分提升
Bridge Over (Troubled OR Water) 部分提升
Bridge Over Troubled Water 精確提升
Bridge Over Troubled Water 精確提升
Bridge ("Over Troubled" OR missingterm) Water 精確提升

限制擷取深度

搜尋索引通常包含數百萬份文件。如果查詢的述詞選擇性較低,就不適合對所有結果進行排序。評分查詢通常有兩項限制:

  1. 擷取深度限制:要評分的資料列數量上限。
  2. 結果集大小限制:查詢應傳回的資料列數量上限 (通常是頁面大小)。

查詢可使用 SQL 子查詢限制擷取深度:

GoogleSQL

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

PostgreSQL

這個範例使用查詢參數 $1$2$3,這些參數分別繫結至 title_queryretrieval_limitpage_size 指定的值。

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

如果 Spanner 使用最重要的排名信號排序索引,這項做法特別有效。

後續步驟