搜尋結果排名

本頁面說明如何在 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) 計算。分數是記錄最終排序的其中一個要素。查詢會將這項資訊與其他信號結合,例如根據時效性調整主題分數。

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

SCORE 函式會傳回值,做為 Spanner 用來建立排列順序的關聯性分數。沒有獨立意義。分數越高,代表與查詢的相符程度越高。

通常,SEARCH 和 SCORE 函式的 query 和 enhance_query 等引數相同,以確保檢索和排名的一致性。

建議的做法是搭配使用這些引數與查詢參數,而非字串常值,並在 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)
  • 熱門程度(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

查詢 已套用 Boost
Bridge Troubled 不提升
橋樑跨越 - 其他水域 不提升
Bridge (Over OR Troubled) Water 不提升
橋接 部分提升
Bridge Over (Troubled OR Water) 部分提升
Bridge Over Troubled 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 參數,則會覆寫資料庫的預設版本。

覆寫每項查詢的評分器版本

您可以使用 SCORE 函式 options 引數中的 version 參數,覆寫特定查詢的預設評分器版本。如果查詢定義了評分器版本,則會覆寫資料庫的預設版本。

以下範例在 options 參數中指定 version,覆寫預設評分器版本:

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 使用最重要的排名信號來排序索引,這種做法的效果特別好。

後續步驟