Panoramica delle query

Questa pagina descrive la funzione SEARCH e la modalità di query avanzata, che vengono utilizzate per eseguire query di ricerca full-text sulle tabelle Spanner.

Eseguire query su un indice di ricerca

Spanner fornisce la funzione SEARCH da utilizzare per le query dell'indice di ricerca. Un caso d'uso di esempio è un'applicazione in cui gli utenti inseriscono testo in una casella di ricerca e l'applicazione invia l&#39input utentee direttamente alla funzione SEARCH. La funzione SEARCH utilizzerebbe quindi un indice di ricerca per trovare il testo.

La funzione SEARCH richiede due argomenti:

  • Un nome di indice di ricerca
  • Una query di ricerca

La funzione SEARCH funziona solo quando è definito un indice di ricerca. La funzione SEARCH può essere combinata con qualsiasi costrutto SQL arbitrario, come filtri, aggregazioni o join.

La funzione SEARCH non può essere utilizzata con le query sulle transazioni.

La seguente query utilizza la funzione SEARCH per restituire tutti gli album che contengono friday o monday nel titolo:

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'friday OR monday')

PostgreSQL

Questo esempio utilizza spanner.search.

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'friday OR monday')

Query di ricerca

Per impostazione predefinita, le query di ricerca utilizzano la sintassi della query di ricerca non elaborata. È possibile specificare sintassi alternative utilizzando l'argomento SEARCH dialect.

rquery dialect

Il dialetto predefinito è query di ricerca non elaborata. Spanner utilizza un linguaggio specifico per il dominio (DSL) chiamato rquery.

Il linguaggio rquery segue le stesse regole del tokenizer di testo normale quando divide la query di ricerca di input in termini distinti. Ciò include la segmentazione delle lingue asiatiche.

Per informazioni sull'utilizzo di rquery, vedi Sintassi di rquery.

words dialect

La parola dialect è simile a rquery, ma più semplice. Non utilizza operatori speciali. Ad esempio, OR viene trattato come un termine di ricerca anziché come un operatore di disgiunzione. Le virgolette doppie vengono gestite come segni di punteggiatura anziché come una ricerca di una frase e vengono ignorate.

Con la parola dialetto, AND viene applicato implicitamente a tutti i termini ed è obbligatorio durante la corrispondenza. Segue le stesse regole del tokenizer di testo normale quando suddivide la query di ricerca inserita in termini.

Per informazioni sull'utilizzo della parola dialetto, vedi Sintassi delle parole.

words_phrase dialect

Il dialetto words_phrase non utilizza operatori speciali e tutti i termini vengono trattati come una frase, il che significa che i termini devono essere adiacenti e nell'ordine specificato.

Come rquery, il dialetto words_phrase segue le stesse regole del tokenizzatore di testo normale quando divide la query di ricerca di input in termini.

Per informazioni sull'utilizzo del dialetto words_phrase, consulta la sintassi di words phrase.

Modalità di query avanzata

Spanner offre due modalità di ricerca a testo intero: una ricerca di base basata su token e una modalità più avanzata chiamata enhance_query. Se attivata, enhance_query espande la query di ricerca per includere termini e sinonimi correlati, aumentando la probabilità di trovare risultati pertinenti.

Per attivare questa opzione, imposta l'argomento facoltativo enhance_query=>true nella funzione SEARCH. Ad esempio, la query di ricerca hotl cal corrisponde all'album Hotel California.

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'hotl cal', enhance_query=>true)

PostgreSQL

SELECT albumid
FROM albums
WHERE spanner.search(albumtitle_tokens, 'hotl cal', enhance_query=>true)

La modalità enhance_query è un'opzione di query. Non influisce sulla tokenizzazione. Puoi utilizzare lo stesso indice di ricerca con o senza enhance_query.

Google migliora costantemente gli algoritmi di miglioramento delle query. Di conseguenza, una query con enhance_query == true potrebbe produrre risultati leggermente diversi nel tempo.

Quando la modalità enhance_query è attiva, il numero di termini che la funzione SEARCH cerca potrebbe aumentare, il che potrebbe aumentare leggermente la latenza.

Requisiti delle query SQL

Per utilizzare un indice di ricerca, una query SQL deve soddisfare diverse condizioni. Se queste condizioni non vengono soddisfatte, la query utilizza un piano di query alternativo o ha esito negativo se non esiste un piano alternativo.

Le query devono soddisfare le seguenti condizioni:

  • Le funzioni SEARCH e SEARCH_SUBSTRING richiedono un indice di ricerca. Spanner non supporta queste funzioni nelle query sulla tabella di base o sugli indici secondari.

  • Gli indici partizionati devono avere tutte le colonne di partizione vincolate da una condizione di uguaglianza nella clausola WHERE della query.

    Ad esempio, se un indice di ricerca è definito come PARTITION BY x, y, la query deve avere una congiunzione nella clausola WHERE di x = <parameter or constant> AND y = <parameter or constant>. Questo indice di ricerca non viene preso in considerazione dall'ottimizzatore delle query se manca una condizione di questo tipo.

  • Tutte le colonne TOKENLIST a cui fanno riferimento gli operatori SEARCH e SEARCH_SUBSTRING devono essere indicizzate nello stesso indice di ricerca.

    Ad esempio, considera la seguente tabella e la definizione dell'indice:

    GoogleSQL

    CREATE TABLE Albums (
        AlbumId STRING(MAX) NOT NULL,
        AlbumTitle STRING(MAX),
        AlbumStudio STRING(MAX),
        AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,
        AlbumStudio_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumStudio)) HIDDEN
    ) PRIMARY KEY(AlbumId);
    
    CREATE SEARCH INDEX AlbumsTitleIndex ON Albums(AlbumTitle_Tokens);
    CREATE SEARCH INDEX AlbumsStudioIndex ON Albums(AlbumStudio_Tokens);
    

    PostgreSQL

    CREATE TABLE albums (
        albumid character varying NOT NULL,
        albumtitle character varying,
        albumstudio character varying,
        albumtitle_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,
        albumstudio_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumstudio)) VIRTUAL HIDDEN,
    PRIMARY KEY(albumid));
    
    CREATE SEARCH INDEX albumstitleindex ON albums(albumtitle_tokens);
    CREATE SEARCH INDEX albumsstudioindex ON albums(albumstudio_tokens);
    

    La seguente query non va a buon fine perché non esiste un singolo indice di ricerca che indicizzi sia AlbumTitle_Tokens che AlbumStudio_Tokens:

    GoogleSQL

    SELECT AlbumId
    FROM Albums
    WHERE SEARCH(AlbumTitle_Tokens, @p1)
        AND SEARCH(AlbumStudio_Tokens, @p2)
    

    PostgreSQL

    Questo esempio utilizza parametri di ricerca $1 e $2, associati rispettivamente a "auto veloce" e "blue note".

    SELECT albumid
    FROM albums
    WHERE spanner.search(albumtitle_tokens, $1)
        AND spanner.search(albumstudio_tokens, $2)
    
  • Se la colonna dell'ordinamento è annullabile, sia lo schema sia la query devono escludere le righe in cui la colonna dell'ordinamento è NULL. Per maggiori dettagli, vedi Ordine di ordinamento dell'indice di ricerca.

  • Se l'indice di ricerca è filtrato NULL, la query deve includere la stessa espressione di filtro NULL utilizzata in un indice. Per ulteriori dettagli, consulta Indici di ricerca filtrati con NULL.

  • Gli indici di ricerca e le funzioni di ricerca non sono supportati in DML, DML partizionato o query partizionate.

  • Indici di ricerca e funzioni di ricerca vengono in genere utilizzati nelle transazioni di sola lettura. Se i requisiti dell'applicazione consentono risultati obsoleti, potresti migliorare la latenza eseguendo query di ricerca con una durata di obsolescenza di 10 secondi o più. Per saperne di più, consulta Lettura di dati obsoleti. Ciò è particolarmente utile per le query di ricerca che si estendono a molte suddivisioni dell'indice.

Gli indici di ricerca e le funzioni di ricerca non sono consigliati nelle transazioni di lettura/scrittura. Durante l'esecuzione, le query di ricerca bloccano un'intera partizione dell'indice; di conseguenza, un tasso elevato di query di ricerca nelle transazioni di lettura/scrittura potrebbe causare conflitti di blocco che portano a picchi di latenza. Per impostazione predefinita, gli indici di ricerca non vengono selezionati automaticamente nelle transazioni di lettura/scrittura. Se una query è costretta a utilizzare un indice di ricerca in una transazione di lettura/scrittura, l'operazione non va a buon fine per impostazione predefinita. L'operazione non riesce anche se la query contiene una delle funzioni di ricerca. Questo comportamento può essere ignorato con il suggerimento a livello di istruzione @{ALLOW_SEARCH_INDEXES_IN_TRANSACTION=TRUE} GoogleSQL (ma le query sono comunque soggette a conflitti di blocco).

Una volta soddisfatte le condizioni di idoneità dell'indice, l'ottimizzatore delle query tenta di accelerare le condizioni delle query non di testo (come Rating > 4). Se l'indice di ricerca non include la colonna TOKENLIST appropriata, la condizione non viene accelerata e rimane una condizione residua.

Parametri di query

Gli argomenti della query di ricerca vengono specificati come valore letterale o come parametro di query. Ti consigliamo di utilizzareparametri di ricercay per la ricerca full-text anziché i valori letterali delle stringhe quando gli argomenti consentonvalore parametroro di query.

Selezione dell'indice

Spanner in genere seleziona l'indice più efficiente per una query utilizzando la modellazione basata sui costi. Tuttavia, il suggerimento FORCE_INDEX indica esplicitamente a Spanner di utilizzare un indice di ricerca specifico. Ad esempio, il seguente codice mostra come forzare Spanner a utilizzare AlbumsIndex:

GoogleSQL

SELECT AlbumId
FROM Albums @{FORCE_INDEX=AlbumsIndex}
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")

PostgreSQL

SELECT albumid
FROM albums/*@force_index=albumsindex*/
WHERE spanner.search(albumtitle_tokens, 'fifth symphony')

Se l'indice di ricerca specificato non è idoneo, la query non va a buon fine, anche se sono presenti altri indici di ricerca idonei.

Snippet nei risultati di ricerca

Uno snippet è un frammento di testo estratto da una determinata stringa che fornisce agli utenti un'idea dei contenuti di un risultato di ricerca e del motivo per cui il risultato è pertinente alla loro query.

Ad esempio, Gmail utilizza gli snippet per indicare la parte di un'email che corrisponde alla query di ricerca:

Elenco di snippet

La generazione di uno snippet da parte del database offre diversi vantaggi:

  1. Comodità: non devi implementare la logica per generare snippet da una query di ricerca.
  2. Efficienza: gli snippet riducono le dimensioni dell'output del server.

La funzione SNIPPET crea lo snippet. Restituisce la parte pertinente del valore della stringa originale insieme alle posizioni dei caratteri da evidenziare. Il cliente può quindi scegliere come mostrare lo snippet all'utente finale (ad esempio, utilizzando testo evidenziato o in grassetto).

Ad esempio, il seguente codice utilizza SNIPPET per recuperare il testo da AlbumTitle:

GoogleSQL

SELECT AlbumId, SNIPPET(AlbumTitle, "Fast Car")
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "Fast Car")

PostgreSQL

Questo esempio utilizza spanner.snippet.

SELECT albumid, spanner.snippet(albumtitle, 'Fast Car')
FROM albums
WHERE spanner.search(albumtitle_tokens, 'Fast Car')

Passaggi successivi