本頁說明如何在 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 函式的輸出內容套用乘法升幅。這項加成有兩種版本:部分比對和完全比對。在下列情況下,系統會套用部分相符的提升效果:
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 | 完全提升 |
Scorer 版本
評分演算法會定期更新。每個版本都會整合一組評分演算法改良項目。如需各版本差異的詳細清單,請參閱「評分者版本」。
您可以為資料庫設定預設評分者版本,也可以為特定查詢指定版本。
設定資料庫的預設評分者版本
您可以為資料庫設定評分演算法的預設版本。如果呼叫 SCORE 函式時未明確指定 version 分數選項,系統就會使用這個選項,決定 Spanner 要採用哪個版本的評分演算法。
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
限制擷取深度
搜尋索引通常包含數百萬份文件。如果查詢的述詞選擇性較低,就不適合對所有結果進行排序。評分查詢通常有兩項限制:
- 擷取深度限制:要評分的資料列數量上限。
- 結果集大小限制:查詢應傳回的資料列數上限 (通常是頁面大小)。
查詢可使用 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 使用最重要的排名信號排序索引,這項做法特別有效。
後續步驟
- 瞭解全文搜尋查詢。
- 瞭解如何執行子字串搜尋。
- 瞭解如何將搜尋結果分頁。
- 瞭解如何混合使用全文和非文字查詢。
- 瞭解如何搜尋多個資料欄。