패싯을 사용하여 검색 실행

이 페이지에서는 전체 텍스트 검색에 패싯을 사용하는 방법을 설명합니다. 상호작용 필터링의 일부로 패싯은 잠재적인 필터 값과 해당 필터의 일치 항목 수입니다. 이 기능이 있는 웹사이트에서 검색어를 입력하면 탐색 메뉴에 결과 목록이 표시되고, 검색 결과를 좁히는 데 사용할 수 있는 패싯 목록과 각 카테고리에 맞는 결과 수가 표시됩니다.

예를 들어 'foo'라는 쿼리를 사용하여 앨범을 검색하면 수백 개의 결과가 표시될 수 있습니다. 장르 패싯이 있는 경우 '록 (250)', 'R&B (50)', '팝 (150)'과 같은 장르별로 선택할 수 있습니다.

Spanner 전체 텍스트 검색에서는 필터링과 필터링된 개수 계산 모두에 표준 SQL 표현식과 전체 텍스트 검색 함수를 사용할 수 있습니다. 패싯을 사용하기 위해 특수 구문을 사용할 필요는 없습니다.

전체 텍스트 검색에 사용할 패싯 추가

다음 예시에서는 앨범 테이블을 만들고 각 앨범의 제목을 토큰화합니다. 이 표는 이 페이지의 예시에 사용됩니다.

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에 검색 색인을 만듭니다. 선택적으로 패싯을 계산하는 동안 기본 테이블에 대한 백조인을 방지하기 위해 검색 색인에 Title, Genres, Rating을 저장할 수 있습니다.

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)

단일 패싯의 개수 값 가져오기

이 예시에서는 Rating 패싯에서 패싯 수를 실행하는 방법을 보여줍니다. 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 (...)은 결과의 첫 페이지와 패싯 계산에 사용할 초기 검색 결과를 많이 수집합니다.
  • SEARCH(Title_Tokens, "foo")은 기본 검색어입니다.
  • LIMIT 10000은 결과 집합을 10,000으로 줄여 검색 비용을 제한합니다. 수백만 개의 결과를 반환할 수 있는 매우 광범위한 검색의 경우 전체 데이터 세트에서 정확한 패싯 수를 계산하는 데 비용이 많이 들 수 있습니다. 검색 결과를 제한하면 쿼리에서 대략적인 (하한) 패싯 수를 빠르게 제공할 수 있습니다. 즉, 개수는 최소한 그만큼의 결과를 반영하지만 10,000개 한도를 초과하는 일치하는 결과가 더 있을 수 있습니다.
  • result_page 하위 쿼리는 사용자에게 표시되는 검색 결과의 첫 페이지를 생성합니다. LikesAlbumId로 정렬된 search_results에서 상위 50개 레코드만 선택합니다. 사용자에게 처음에 표시되는 내용입니다.
  • rating_counts 하위 쿼리는 Rating의 패싯 수를 계산합니다. search_results의 모든 레코드를 Rating별로 그룹화하고 각 평가 카테고리에 속하는 결과 수를 계산합니다.
  • genres_counts 하위 쿼리는 Genres의 패싯 수를 계산합니다. 배열이므로 UNNEST(Genres)로 결합하여 배열 내 각 장르를 집계할 별도의 행으로 처리합니다.

후속 페이지 가져오기

초기 패싯 쿼리 후 연속 페이지를 쿼리할 때 첫 번째 페이지에서 반환된 패싯 수를 재사용할 수 있습니다.

페이지로 나누는 방법에 관한 자세한 내용은 키 기반 페이지로 나누기 사용을 참고하세요.