使用 Facet 執行搜尋

本頁面說明如何使用 facets 進行全文搜尋。在互動式篩選功能中,分面是潛在的篩選值,以及該篩選條件的相符項目數量。在具備這項功能的網站上輸入搜尋詞組時,導覽選單會顯示結果清單,以及可用於縮小搜尋結果範圍的側欄清單,並顯示符合各類別的結果數量。

舉例來說,如果您使用查詢「foo」搜尋專輯,可能會得到數百個結果。如果類型有分類,你可以依類型選取,例如「搖滾 (250)」、「R&B (50)」或「流行 (150)」。

在 Spanner 全文搜尋中,您可以使用標準 SQL 運算式和全文搜尋函式進行篩選和篩選計數。使用構面時,不需要使用特殊語法。

新增用於全文搜尋的 Facet

下列範例會建立專輯資料表,並為每張專輯的名稱進行權杖化。本頁的範例會使用這個資料表。

GoogleSQL

CREATE TABLE Albums (
  AlbumId INT64 NOT NULL,
  Title STRING(MAX),
  Rating INT64,
  Genres ARRAY<STRING(MAX)>,
  Likes INT64 NOT NULL,
  Title_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN,
) PRIMARY KEY(AlbumId);

PostgreSQL

CREATE TABLE albums (
  albumid bigint NOT NULL,
  title text,
  rating bigint,
  genres text[],
  likes bigint NOT NULL,
  title_tokens spanner.TOKENLIST GENERATED ALWAYS AS (spanner.TOKENIZE_FULLTEXT(Title)) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));

Title_Tokens 上建立搜尋索引。您可以選擇在搜尋索引中儲存 TitleGenresRating,避免在計算 facets 時回溯加入基本資料表。

GoogleSQL

CREATE SEARCH INDEX AlbumsIndex
ON Albums (Title_Tokens)
STORING (Title, Genres, Rating)
ORDER BY Likes DESC;

PostgreSQL

CREATE SEARCH INDEX albumsindex
ON albums (title_tokens)
INCLUDE (title, genres, rating)
ORDER BY likes DESC

在本範例中,請將下列資料插入資料表。

GoogleSQL

INSERT INTO Albums (AlbumId, Title, Rating, Genres, Likes) VALUES
(1, "The Foo Strike Again", 5, ["Rock", "Alternative"], 600),
(2, "Who are the Who?", 5, ["Progressive", "Indie"], 200),
(3, "No Foo For You", 4, ["Metal", "Alternative"], 50)

PostgreSQL

INSERT INTO albums (albumid, title, rating, genres, likes) VALUES
(1, 'The Foo Strike Again', 5,'{"Rock", "Alternative"}', 600),
(2, 'Who are the Who?', 5,'{"Progressive", "Indie"}', 200),
(3, 'No Foo For You', 4,'{"Metal", "Alternative"}', 50)

擷取單一 facet 的計數值

這個範例說明如何對「評分」面向執行面向計數。這會在 Albums 資料表的 Title_Tokens 欄中執行「foo」的文字搜尋。

GoogleSQL

SELECT Rating, COUNT(*) AS result_count
FROM Albums
WHERE SEARCH(Title_Tokens, "foo")
GROUP BY Rating
ORDER BY Rating DESC

| Rating | result_count |
|--------|--------------|
| 5      | 1            |
| 4      | 1            |

PostgreSQL

SELECT rating, COUNT(*) AS result_count
FROM albums
WHERE spanner.SEARCH(title_tokens, 'foo')
GROUP BY rating
ORDER BY rating DESC;

| rating | result_count |
|--------|--------------|
| 5      | 1            |
| 4      | 1            |

擷取多個商情項目的計數值

這個範例說明如何對多個層面執行層面計數。 這項功能會執行下列操作:

  1. 擷取初始搜尋結果:在 Albums 表格的 Title_Tokens 欄中執行「foo」的文字搜尋。
  2. 計算側滑片計數:然後計算 RatingGenres 側滑片的計數。

GoogleSQL

WITH search_results AS (
  SELECT AlbumId, Title, Genres, Rating, Likes
  FROM Albums
  WHERE SEARCH(Title_Tokens, "foo")
  ORDER BY Likes DESC, AlbumId
  LIMIT 10000
)

SELECT
-- Result set #1: First page of search results
ARRAY(
  SELECT AS STRUCT *
  FROM search_results
  ORDER BY Likes DESC, AlbumId
  LIMIT 50
) as result_page,
-- Result set #2: Number of results by rating
ARRAY(
  SELECT AS STRUCT Rating, COUNT(*) as result_count
  FROM search_results
  GROUP BY Rating
  ORDER BY result_count DESC, Rating DESC
) as rating_counts,
-- Result set #3: Number of results for top 5 genres
ARRAY(
  SELECT AS STRUCT genre, COUNT(*) as result_count
  FROM search_results
  JOIN UNNEST(Genres) genre
  GROUP BY genre
  ORDER BY result_count DESC, genre
  LIMIT 5
) as genres_counts

PostgreSQL

WITH search_results AS (
  SELECT albumid, title, genres, rating, likes
  FROM albums
  WHERE spanner.SEARCH(title_tokens, 'foo')
  ORDER BY likes DESC, albumid
  LIMIT 10000
)

-- The pattern ARRAY(SELECT TO_JSONB ...) enables returning multiple nested
-- result sets in the same query.
SELECT
  -- Result set #1: First page of search results
  ARRAY(
  SELECT JSONB_BUILD_OBJECT(
    'albumid', albumid,
    'title', title,
    'genres', genres,
    'rating', rating,
    'likes', likes
    )
  FROM search_results
  ORDER BY likes DESC, albumid
  LIMIT 50
) as result_page,
-- Result set #2: Number of results by rating
ARRAY(
  SELECT JSONB_BUILD_OBJECT(
    'rating', rating,
    'result_count', COUNT(*)
    )
  FROM search_results
  GROUP BY rating
  ORDER BY COUNT(*) DESC, rating DESC
) as rating_counts,
-- Result set #3: Number of results for top 5 genres
ARRAY(
  SELECT JSONB_BUILD_OBJECT(
    'genre', genre,
    'result_count', COUNT(*)
    )
  FROM
    search_results,
    UNNEST(genres) AS genre
  GROUP BY genre
  ORDER BY COUNT(*) DESC, genre
  LIMIT 5
) as genres_counts

具體來說,這個範例會執行下列作業:

  • WITH search_results AS (...) 會收集大量初始搜尋結果,用於第一頁結果和 Facet 計算。
  • SEARCH(Title_Tokens, "foo") 是主要搜尋查詢。
  • LIMIT 10000 會將結果集縮減至 10,000 個,藉此限制搜尋費用。如果搜尋範圍很廣,可能會傳回數百萬筆結果,這時計算整個資料集的確切 Facet 數量可能需要大量資源。藉由限制搜尋結果,查詢可以快速提供近似 (下限) 構面計數。也就是說,計數反映的結果至少有這麼多,但可能還有更多相符結果,只是超過 10,000 筆的上限。
  • result_page 子查詢會產生顯示給使用者的搜尋結果第一頁。這項查詢只會選取前 50 筆記錄 (依 LikesAlbumId 排序)。search_results這是使用者一開始看到的畫面。
  • rating_counts 子查詢會計算 Rating 的側邊欄篩選條件計數。這項函式會依據 Ratingsearch_results 中的所有記錄分組,並計算每個評分類別的結果數量。
  • genres_counts 子查詢會計算 Genres 的側邊數。由於這是陣列,請使用 UNNEST(Genres) 聯結,將陣列中的每個類型視為獨立資料列進行計數。

擷取後續網頁

在初始商情項目查詢後查詢後續頁面時,可以重複使用第一頁傳回的商情項目計數。

如要進一步瞭解如何分頁,請參閱「使用以鍵為準的分頁」。