검색 결과 순위 지정

이 페이지에서는 Spanner에서 전체 텍스트 검색의 검색 결과 순위를 지정하는 방법을 설명합니다.

Spanner는 정교한 순위 함수 만들기의 구성 요소를 제공하는 적합성 점수 계산을 지원합니다. 이러한 점수는 검색어 빈도 및 기타 맞춤설정 가능한 옵션을 기반으로 쿼리에 대한 결과의 관련성을 계산합니다.

다음 예시에서는 SCORE 함수를 사용하여 순위 기반 검색을 실행하는 방법을 보여줍니다.

GoogleSQL

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

PostgreSQL

이 예시에서는 spanner.score와 함께 spanner.search를 사용합니다.

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')
ORDER BY spanner.score(albumtitle_tokens, 'fifth symphony') DESC

SCORE 함수로 검색어 점수 매기기

SCORE 함수는 각 검색어의 점수를 계산한 후 점수를 결합합니다. 용어별 점수는 용어 빈도- 역문서 빈도(TF/IDF)를 기반으로 대략적으로 계산됩니다. 점수는 레코드의 최종 순서의 한 구성요소입니다. 쿼리는 이 점수를 적합성 점수를 조정하는 최신성 등 다른 신호와 결합합니다.

현재 구현에서는 TF/IDF의 IDF 부분은 enhance_query=>true가 사용되는 경우에만 사용할 수 있습니다. 특정 검색 색인이 아닌 Google 검색에서 사용하는 전체 웹 코퍼스를 기반으로 단어의 상대적 빈도를 계산합니다. 쿼리 개선이 사용 설정되지 않은 경우 점수 산정에서 용어 빈도(TF) 구성요소만 사용됩니다(즉, IDF 용어가 1로 설정됨).

SCORE 함수는 Spanner가 정렬 순서를 설정하는 데 사용하는 관련성 점수 역할을 하는 값을 반환합니다. 이는 단독으로 의미가 없습니다. 점수가 높을수록 검색어와 더 잘 일치합니다.

일반적으로 queryenhance_query와 같은 인수는 검색 및 순위 지정 일관성을 보장하기 위해 SEARCH 함수와 SCORE 함수에서 동일합니다.

이를 실행하는 권장 방법은 문자열 리터럴 대신 쿼리 파라미터와 함께 이러한 인수를 사용하고 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

이 예시에서는 각각 'fifth symphony' 및 'blue note'에 바인딩된 쿼리 파라미터 $1$2를 사용합니다.

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

이 예시에서는 titlequery, studioquery, titleweight, studioweight, grammyweight, freshnessweight에 지정된 값에 바인딩된 쿼리 파라미터 $1, $2, $3, $4, $5, $6를 사용합니다.

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에서 구문 왼쪽에 표시되며, 구문 오른쪽에 있는 용어에도 동일하게 적용됩니다.

Spanner는 이전 규칙이 모두 true이고 쿼리의 첫 번째 및 마지막 토큰이 문서의 첫 번째 및 마지막 토큰인 경우 정확한 일치 부스트를 적용합니다.

문서 예시: Bridge Over Troubled Water

쿼리 부스트 적용됨
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

이 예시에서는 title_query, retrieval_limit, page_size에 지정된 값에 각각 바인딩된 쿼리 파라미터 $1, $2, $3를 사용합니다.

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가 가장 중요한 순위 결정 신호를 사용하여 색인을 정렬하는 경우에 특히 효과적입니다.

다음 단계