Suchergebnisse einstufen

Auf dieser Seite wird beschrieben, wie Sie Suchergebnisse für Volltextsuchen in Spanner einstufen.

Spanner unterstützt die Berechnung eines Aktualitätswerts, der einen Baustein für die Erstellung komplexer Ranking-Funktionen darstellt. Mit diesen Werten wird die Relevanz eines Ergebnisses für eine Anfrage auf Grundlage der Häufigkeit des Suchbegriffs und anderer anpassbarer Optionen berechnet.

Im folgenden Beispiel wird gezeigt, wie Sie mit der Funktion SCORE eine Suche mit Rangfolge durchführen:

GoogleSQL

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

PostgreSQL

In diesem Beispiel wird spanner.search mit spanner.score verwendet.

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

Suchbegriffe mit der Funktion SCORE bewerten

Die Funktion SCORE berechnet einen Wert für jeden Suchbegriff und kombiniert dann die Werte. Die Punktzahl für jeden Begriff basiert in etwa auf Begriffshäufigkeit – umgekehrte Dokumenthäufigkeit (TF/IDF). Die Punktzahl ist eine Komponente der endgültigen Reihenfolge für einen Datensatz. In der Abfrage wird sie mit anderen Signalen kombiniert, z. B. mit der Aktualität, die den Aktualitätswert beeinflusst.

In der aktuellen Implementierung ist der IDF-Teil von TF/IDF nur verfügbar, wenn enhance_query=>true verwendet wird. Dabei wird die relative Häufigkeit von Wörtern auf Grundlage des gesamten Webkorpus berechnet, der von der Google Suche verwendet wird, und nicht auf Grundlage eines bestimmten Suchindex. Wenn die rquery-Optimierung nicht aktiviert ist, wird bei der Bewertung nur die Komponente für die Begriffshäufigkeit (TF) verwendet. Der IDF-Begriff wird also auf 1 gesetzt.

Die Funktion SCORE gibt Werte zurück, die als Relevanzwerte dienen, mit denen Spanner eine Sortierreihenfolge festlegt. Sie haben keine eigenständige Bedeutung. Je höher der Wert, desto besser passt das Ergebnis zur Anfrage.

Normalerweise sind Argumente wie query und enhance_query für die Funktionen SEARCH und SCORE identisch, um eine konsistente Abfrage und einheitliches Ranking zu gewährleisten.

Die empfohlene Vorgehensweise ist, diese Argumente mit Abfrageparametern anstelle von String-Literalen zu verwenden und dieselben Abfrageparameter in den Funktionen SEARCH und SCORE anzugeben.

Mehrere Spalten bewerten

In Spanner wird die Funktion SCORE verwendet, um jedes Feld einzeln zu bewerten. In der Abfrage werden diese einzelnen Werte dann kombiniert. Eine gängige Methode hierfür ist, die einzelnen Werte zu addieren und dann entsprechend den vom Nutzer angegebenen Feldgewichten zu erhöhen (die über SQL-Abfrageparameter bereitgestellt werden).

In der folgenden Abfrage wird beispielsweise die Ausgabe von zwei SCORE-Funktionen kombiniert:

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

In diesem Beispiel werden die Abfrageparameter $1 und $2 verwendet, die an „fünfte Sinfonie“ bzw. „Blue Note“ gebunden sind.

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

Im folgenden Beispiel werden zwei Boost-Parameter hinzugefügt:

  • Die Aktualität (FreshnessBoost) erhöht die Punktzahl um (1 + @freshnessweight * GREATEST(0, 30 - DaysOld) / 30).
  • „Beliebtheit(PopularityBoost)“ erhöht die Punktzahl, indem sie mit dem Faktor (1 + IF(HasGrammy, @grammyweight, 0) multipliziert wird.

Aus Gründen der Lesbarkeit wird in der Abfrage der Operator WITH verwendet.

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

In diesem Beispiel werden die Abfrageparameter $1, $2, $3, $4, $5 und $6 verwendet, die an die für titlequery, studioquery, titleweight, studioweight, grammyweight bzw. freshnessweight angegebenen Werte gebunden sind.

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 kann auch sowohl für die Suche als auch für die Bewertung verwendet werden, um Abfragen bei Bedarf zu vereinfachen.

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

In diesem Beispiel wird spanner.tokenlist_concat verwendet. Der Abfrageparameter $1 ist an „blue note“ gebunden.

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

Übereinstimmungen mit der Reihenfolge der Suchanfrage hochstufen

Spanner wendet einen multiplikativen Boost auf die Ausgabe der Funktion SCORE für Werte an, die die Suchbegriffe in derselben Reihenfolge wie in der Abfrage enthalten. Es gibt zwei Versionen dieser Steigerung: Teilübereinstimmung und genaue Übereinstimmung. Ein Boost für teilweise Übereinstimmungen wird angewendet, wenn:

  1. TOKENLIST enthält alle ursprünglichen Begriffe in der Anfrage.
  2. Die Tokens stehen nebeneinander und in derselben Reihenfolge wie in der Anfrage.

Für Konjunktionen, Negationen und Wortgruppen gelten bestimmte Sonderregeln:

  • Bei einer Anfrage mit einer Negation kann keine Steigerung durch Teilübereinstimmungen erfolgen.
  • Eine Anfrage mit einer Konjunktion erhält einen Boost, wenn ein Teil der Konjunktion an den entsprechenden Stellen erscheint.
  • Eine Anfrage mit einer Wortgruppe wird optimiert, wenn die Wortgruppe in der TOKENLIST vorkommt und der Begriff links von der Wortgruppe in der Anfrage links von der Wortgruppe in der TOKENLIST vorkommt. Das Gleiche gilt für den Begriff rechts von der Wortgruppe.

Spanner wendet einen Exact Match Boost an, wenn alle vorherigen Regeln zutreffen und die ersten und letzten Tokens in der Anfrage die ersten und letzten Tokens im Dokument sind.

Beispieldokument: Bridge Over Troubled Water

Abfrage Boost angewendet
Bridge Troubled Keine Steigerung
Brücke über anderes Gewässer Keine Steigerung
Bridge (Over Troubled) Water Keine Steigerung
Bridge Over Teilweise Steigerung
Bridge Over (Troubled OR Water) Teilweise Steigerung
Bridge Over Troubled Water genaue Steigerung
Brücke „Over Troubled Water“ genaue Steigerung
Brücke („Over Troubled“ ODER missingterm) Wasser genaue Steigerung

Abruftiefe begrenzen

Suchindexe enthalten oft Millionen von Dokumenten. Bei Abfragen, bei denen die Prädikate eine geringe Selektivität aufweisen, ist es nicht praktikabel, alle Ergebnisse zu ranken. Für Scoring-Abfragen gelten in der Regel zwei Grenzwerte:

  1. Limit für die Abruftiefe: Die maximale Anzahl der zu bewertenden Zeilen.
  2. Limit für die Größe des Ergebnissatzes: Die maximale Anzahl von Zeilen, die von der Abfrage zurückgegeben werden sollen (in der Regel die Seitengröße).

Mit SQL-Unterabfragen kann die Abruftiefe begrenzt werden:

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

In diesem Beispiel werden die Abfrageparameter $1, $2 und $3 verwendet, die an die für title_query, retrieval_limit bzw. page_size angegebenen Werte gebunden sind.

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

Das funktioniert besonders gut, wenn Spanner das wichtigste Ranking-Signal zum Sortieren des Index verwendet.

Nächste Schritte