Crea un indice ScaNN

Utilizza gli incorporamenti archiviati per generare indici vettoriali ScaNN ed eseguire query sugli incorporamenti con AlloyDB per PostgreSQL.

L'indice ScaNN è un indice di quantizzazione basato su alberi creato da Google per la ricerca del vicino più prossimo approssimato. Offre tempi di creazione dell'indice più brevi e un footprint della memoria più piccolo rispetto a HNSW. Inoltre, offre QPS più veloci rispetto a HNSW in base al carico di lavoro.

Prima di iniziare

Prima di poter iniziare a creare indici, devi completare i seguenti prerequisiti.

Creare un indice ottimizzato automaticamente

Gli indici ScaNN ottimizzati automaticamente semplificano la creazione degli indici consentendo ad AlloyDB di gestire e ottimizzare la struttura dell'indice. Se hai bisogno di un controllo granulare della regolazione dell'indice, crea un indice ScaNN regolato manualmente.

Gli indici ottimizzati automaticamente possono essere ottimizzati in due modi:

  • (Predefinito) Recupero e latenza della ricerca vettoriale a scapito del tempo di compilazione dell'indice
  • Bilanciare il tempo di compilazione dell'indice e il rendimento della ricerca

Per creare un indice ScaNN ottimizzato automaticamente, esegui questo comando.

CREATE INDEX INDEX_NAME ON TABLE
       USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)

Sostituisci quanto segue:

  • INDEX_NAME: il nome dell'indice che vuoi creare. Ad esempio, my_scann_index. I nomi degli indici sono condivisi nel database. Verifica che ogni nome di indice sia univoco per ogni tabella del database.

  • TABLE: la tabella a cui aggiungere l'indice.

  • EMBEDDING_COLUMN: colonna che memorizza i dati vector.

  • DISTANCE_FUNCTION: funzione di distanza da utilizzare con questo indice. Scegli una delle opzioni seguenti:

    • Distanza L2: l2

    • Prodotto scalare: dot_product

    • Distanza coseno: cosine

Questo comando crea un indice ScaNN ottimizzato per il rendimento della ricerca ed esegue la manutenzione automatica dell'indice. Se vuoi modificare una di queste impostazioni, esegui il seguente comando:

CREATE INDEX INDEX_NAME ON TABLE
       USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
WITH (MODE='AUTO',
      OPTIMIZATION='OPTIMIZATION',
      auto_maintenance='AUTO_MAINTENANCE')

Sostituisci quanto segue:

  • INDEX_NAME: il nome dell'indice che vuoi creare. Ad esempio, my_scann_index. I nomi degli indici sono condivisi nel database. Verifica che ogni nome di indice sia univoco per ogni tabella del database.

  • TABLE: la tabella a cui aggiungere l'indice.

  • EMBEDDING_COLUMN: colonna che memorizza i dati vector.

  • DISTANCE_FUNCTION: funzione di distanza da utilizzare con questo indice. Scegli una delle opzioni seguenti:

    • Distanza L2: l2

    • Prodotto scalare: dot_product

    • Distanza coseno: cosine

  • (Facoltativo) OPTIMIZATION: imposta uno dei seguenti valori:

    • (Predefinito) SEARCH_OPTIMIZED: ottimizza sia il richiamo della ricerca vettoriale sia la latenza della ricerca vettoriale a costo di tempi di creazione dell'indice più lunghi.

    • BALANCED: bilancia il tempo di compilazione dell'indice e le prestazioni di ricerca.

    Se OPTIMIZATION è impostato, deve essere incluso anche MODE='AUTO'.

  • (Facoltativo) AUTO_MAINTENANCE: controlla se la manutenzione automatica dell'indice è attivata o disattivata. Per saperne di più sulla manutenzione automatica, consulta Mantenere gli indici vettoriali.

    • (Predefinito) ON: AlloyDB esegue la manutenzione automatica dell'indice.

    • OFF: AlloyDB non esegue la manutenzione automatica dell'indice.

Creare un indice ottimizzato manualmente

Se la tua applicazione ha requisiti specifici per i tempi di richiamo e creazione dell'indice, puoi creare e ottimizzare manualmente l'indice ScaNN.

Per creare manualmente un indice ScaNN per una colonna contenente incorporamenti di vettori memorizzati, consulta i seguenti comandi.

Indice ad albero a due livelli

CREATE INDEX INDEX_NAME ON TABLE
       USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
WITH (mode='MANUAL',
      num_leaves=NUM_LEAVES_VALUE,
      quantizer=QUANTIZER,
      auto_maintenance=AUTO_MAINTENANCE);
  • INDEX_NAME: il nome dell'indice che vuoi creare. Ad esempio, my_scann_index. I nomi degli indici vengono condivisi nel tuo database. Assicurati che ogni nome di indice sia univoco per ogni tabella del tuo database.
  • TABLE: la tabella a cui aggiungere l'indice.
  • EMBEDDING_COLUMN: colonna che memorizza i dati `vector`.
  • DISTANCE_FUNCTION: funzione di distanza da utilizzare con questo indice. Scegli una delle seguenti opzioni:
    • Distanza L2: l2
    • Prodotto scalare: dot_product
    • Distanza coseno: cosine
  • NUM_LEAVES_VALUE: numero di partizioni da applicare a questo indice. Imposta un valore compreso tra 1 e 30 milioni. Per ulteriori informazioni su come scegliere questo valore, vedi Ottimizzare un indice ScaNN.
  • QUANTIZER: tipo di quantizzatore da utilizzare. Tieni presente che l'indice ScaNN può essere caricato nel motore colonnare per accelerare ulteriormente la ricerca vettoriale. Scegli una delle seguenti opzioni:
    • (Predefinito) SQ8: offre un equilibrio tra le prestazioni delle query con una perdita minima di richiamo. In genere, questa percentuale è inferiore all'1-2%.
    • Anteprima AH: l'hashing asimmetrico (AH) è fino a 4 volte più compresso rispetto a SQ8. Per un potenziale miglioramento delle prestazioni delle query quando il motore colonnare è abilitato e i dati di indice e tabella vengono inseriti nel motore colonnare, prendi in considerazione questa opzione per un potenziale miglioramento delle prestazioni delle query. Per saperne di più, consulta le best practice per l'ottimizzazione di ScaNN.
    • FLAT: fornisce il richiamo più elevato, pari al 99% o superiore, a scapito delle prestazioni di ricerca.
  • (Facoltativo) AUTO_MAINTENANCE: controlla se la manutenzione automatica dell'indice è attivata o disattivata. Per saperne di più sulla manutenzione automatica, consulta Gestire gli indici vettoriali.
    • (Predefinito) ON: AlloyDB esegue la manutenzione automatica dell'indice.
    • OFF: AlloyDB non esegue la manutenzione automatica dell'indice.

Indice ad albero a tre livelli

CREATE INDEX INDEX_NAME ON TABLE
       USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
WITH (mode='MANUAL',
      num_leaves=NUM_LEAVES_VALUE,
      quantizer=QUANTIZER,
      auto_maintenance=AUTO_MAINTENANCE,
      max_num_levels = 2);
  • INDEX_NAME: il nome dell'indice che vuoi creare. Ad esempio, my_scann_index. I nomi degli indici vengono condivisi nel tuo database. Assicurati che ogni nome di indice sia univoco per ogni tabella del tuo database.
  • TABLE: la tabella a cui aggiungere l'indice.
  • EMBEDDING_COLUMN: colonna che memorizza i dati `vector`.
  • DISTANCE_FUNCTION: funzione di distanza da utilizzare con questo indice. Scegli una delle seguenti opzioni:
    • Distanza L2: l2
    • Prodotto scalare: dot_product
    • Distanza coseno: cosine
  • NUM_LEAVES_VALUE: numero di partizioni da applicare a questo indice. Imposta un valore compreso tra 1 e 30 milioni. Per ulteriori informazioni su come scegliere questo valore, vedi Ottimizzare un indice ScaNN.
  • QUANTIZER: tipo di quantizzatore da utilizzare. Tieni presente che l'indice ScaNN può essere caricato nel motore colonnare per accelerare ulteriormente la ricerca vettoriale. Scegli una delle seguenti opzioni:
    • (Predefinito) SQ8: offre un equilibrio tra le prestazioni delle query con una perdita minima di richiamo. In genere, questa percentuale è inferiore all'1-2%.
    • Anteprima AH: l'hashing asimmetrico (AH) è fino a 4 volte più compresso rispetto a SQ8. Per un potenziale miglioramento delle prestazioni delle query quando il motore colonnare è abilitato e i dati di indice e tabella vengono inseriti nel motore colonnare, prendi in considerazione questa opzione per un potenziale miglioramento delle prestazioni delle query. Per saperne di più, consulta le best practice per l'ottimizzazione di ScaNN.
    • FLAT: fornisce il richiamo più elevato, pari al 99% o superiore, a scapito delle prestazioni di ricerca.
  • (Facoltativo) AUTO_MAINTENANCE: controlla se la manutenzione automatica dell'indice è attivata o disattivata. Per saperne di più sulla manutenzione automatica, consulta Gestire gli indici vettoriali.
    • (Predefinito) ON: AlloyDB esegue la manutenzione automatica dell'indice.
    • OFF: AlloyDB non esegue la manutenzione automatica dell'indice.

Indice ad albero a quattro livelli

Gli indici ad albero a quattro livelli sono in anteprima.

CREATE INDEX INDEX_NAME ON TABLE
       USING scann (EMBEDDING_COLUMN DISTANCE_FUNCTION)
WITH (mode='MANUAL',
      num_leaves=NUM_LEAVES_VALUE,
      quantizer=QUANTIZER,
      max_num_levels = 3);
  • INDEX_NAME: il nome dell'indice che vuoi creare. Ad esempio, my_scann_index. I nomi degli indici vengono condivisi nel tuo database. Assicurati che ogni nome di indice sia univoco per ogni tabella del tuo database.
  • TABLE: la tabella a cui aggiungere l'indice.
  • EMBEDDING_COLUMN: colonna che memorizza i dati `vector`.
  • DISTANCE_FUNCTION: funzione di distanza da utilizzare con questo indice. Scegli una delle seguenti opzioni:
    • Distanza L2: l2
    • Prodotto scalare: dot_product
    • Distanza coseno: cosine
  • NUM_LEAVES_VALUE: numero di partizioni da applicare a questo indice. Imposta un valore compreso tra 1 e 30 milioni. Per ulteriori informazioni su come scegliere questo valore, vedi Ottimizzare un indice ScaNN.
  • QUANTIZER: tipo di quantizzatore da utilizzare. Tieni presente che l'indice ScaNN può essere caricato nel motore colonnare per accelerare ulteriormente la ricerca vettoriale. Scegli una delle seguenti opzioni:
    • (Predefinito) SQ8: offre un equilibrio tra le prestazioni delle query con una perdita minima di richiamo. In genere, questa percentuale è inferiore all'1-2%.
    • Anteprima AH: l'hashing asimmetrico (AH) è fino a 4 volte più compresso rispetto a SQ8. Per un potenziale miglioramento delle prestazioni delle query quando il motore colonnare è abilitato e i dati di indice e tabella vengono inseriti nel motore colonnare, prendi in considerazione questa opzione per un potenziale miglioramento delle prestazioni delle query. Per saperne di più, consulta le best practice per l'ottimizzazione di ScaNN.
    • FLAT: fornisce il richiamo più elevato, pari al 99% o superiore, a scapito delle prestazioni di ricerca.

Convertire un indice ottimizzato manualmente in un indice ottimizzato automaticamente

Per convertire un indice ottimizzato manualmente in un indice ottimizzato automaticamente, completa i seguenti passaggi:

  1. Reimposta tutti parametri di ricerca definiti per l'indice ottimizzato manualmente.

    ALTER INDEX INDEX_NAME RESET (PARAMETER_NAME);
    

    Sostituisci le seguenti variabili:

    • INDEX_NAME: il nome dell'indice che vuoi convertire. Ad esempio, my_scann_index. I nomi degli indici sono condivisi nel database. Verifica che ogni nome di indice sia univoco per ogni tabella del database.

    • PARAMETER_NAME: un elenco separato da virgole contenente i nomi dei parametri di ricerca che vuoi reimpostare. Ad esempio, num_leaves, quantization.

      Tieni presente che devi reimpostare tutti gli altri parametri di ricerca prima di reimpostare num_leaves.

  2. Reindicizza l'indice ottimizzato manualmente per convertirlo in un indice ottimizzato automaticamente.

    REINDEX INDEX CONCURRENTLY INDEX_NAME;
    

Crea un indice ScaNN per i tipi di dati real[]

Per creare un indice per una colonna di incorporamento che utilizza il tipo di dati real[] anziché vector, esegui il cast della colonna nel tipo di dati vector:

CREATE INDEX INDEX_NAME ON TABLE
USING scann (CAST(EMBEDDING_COLUMN AS vector(DIMENSIONS)) DISTANCE_FUNCTION)

Sostituisci quanto segue:

  • INDEX_NAME: il nome dell'indice che vuoi creare. Ad esempio, my_scann_index. I nomi degli indici sono condivisi nel database. Verifica che ogni nome di indice sia univoco per ogni tabella del database.

  • TABLE: la tabella a cui aggiungere l'indice.

  • EMBEDDING_COLUMN: colonna che memorizza i dati vector.

  • DISTANCE_FUNCTION: funzione di distanza da utilizzare con questo indice. Scegli una delle opzioni seguenti:

    • Distanza L2: l2

    • Prodotto scalare: dot_product

    • Distanza coseno: cosine

Visualizzare l'avanzamento dell'indicizzazione

Per visualizzare l'avanzamento dell'indicizzazione, utilizza la visualizzazione pg_stat_progress_create_index:

SELECT * FROM pg_stat_progress_create_index;

La colonna phase mostra lo stato attuale della creazione dell'indice. Una volta completata la fase di creazione dell'indice, la riga dell'indice non è visibile.

Crea un indice differito per tabelle vuote o con un numero insufficiente di righe

Per impostazione predefinita, non puoi creare un indice ScaNN su una tabella vuota o con un numero di righe inferiore al valore dell'opzione di indice num_leaves.

Per aggirare questa limitazione, attiva la creazione differita dell'indice per consentire ad AlloyDB di posticipare la creazione dell'indice fino a quando il numero di righe nella tabella non raggiunge la soglia definita da num_leaves. Una volta raggiunto il limite, AlloyDB avvia la creazione dell'indice in background.

Questa operazione differita è un processo non bloccante, che consente ad altre operazioni del database, come letture e scritture, di continuare senza interruzioni. Poiché la ricompilazione dell'indice avviene in background, la creazione differita dell'indice è adatta quando le tabelle inseriscono righe di dati in piccoli batch. La ricompilazione dell'indice viene attivata automaticamente quando il numero di righe raggiunge la soglia.

Tuttavia, se prevedi di inserire un numero elevato di righe nella tabella in una singola transazione, ti consigliamo di dividere la transazione in più transazioni o di generare un indice ScaNN senza attivare la creazione differita dell'indice.

Abilita la creazione di indici posticipata

Per attivare la creazione differita dell'indice:

  1. Attiva il flag scann.enable_index_maintenance (attivo per impostazione predefinita) e il flag scann.enable_preview_features. Il flag scann.enable_preview_features attiva anche altre funzionalità di anteprima.

    gcloud alloydb instances update INSTANCE_ID \
       --database-flags scann.enable_index_maintenance=on \
       --database-flags scann.enable_preview_features=on \
       --region=REGION_ID \
       --cluster=CLUSTER_ID \
       --project=PROJECT_ID
    

    Sostituisci quanto segue:

    • INSTANCE_ID: l'ID dell'istanza.
    • REGION_ID: la regione in cui si trova l'istanza, ad esempio us-central1.
    • CLUSTER_ID: l'ID del cluster in cui si trova l'istanza.
    • PROJECT_ID: l'ID del progetto in cui si trova il cluster.
  2. Crea un indice ScaNN. Se crei un indice in modalità manuale, assicurati che il parametro auto_maintenance sia impostato su on. Per saperne di più, consulta Creare un indice ottimizzato manualmente.

Limitazioni

  • Il processo in background di creazione automatica dell'indice utilizza i valori dei flag a livello di database. Anche se imposti flag a livello di sessione utilizzando il comando SET LOCAL, il processo considera il valore del flag impostato a livello di database.
  • Se prevedi di inserire collettivamente una grande quantità di dati in una tabella vuota in una singola transazione, ti consigliamo di eseguire la singola transazione di inserimento e poi creare un indice ScaNN.

Forzare la creazione dell'indice su tabelle vuote o piccole

AlloyDB utilizza le convalide per impedire la creazione di un indice ScaNN su una tabella vuota o con pochissime righe per i seguenti motivi:

  • L'indice ScaNN viene addestrato su dati insufficienti. Ciò può comportare un richiamo scarso per le ricerche di similarità vettoriale.

  • Le prestazioni di scrittura nel database potrebbero peggiorare.

Ti consigliamo di posticipare la creazione dell'indice per evitare prestazioni non ottimali.

Tuttavia, in alcuni scenari di sviluppo o test, potrebbe essere necessario creare un indice su una tabella vuota o di piccole dimensioni. In questi casi, puoi forzare la creazione dell'indice. Tieni presente che l'applicazione forzata della creazione dell'indice richiede privilegi SUPERUSER.

Per forzare la creazione dell'indice, completa i seguenti passaggi:

  1. Imposta il parametro a livello di sessione scann.allow_blocked_operations creation su true nel database:

    SET scann.allow_blocked_operations = true;
    
  2. Se l'utente che utilizzi per eseguire queste query non dispone dei privilegi SUPERUSER, assegnali:

    CREATE USER USERNAME WITH SUPERUSER PASSWORD PASSWORD;
    

    Sostituisci le seguenti variabili:

    • USERNAME: il nome dell'utente a cui vuoi concedere i privilegi SUPERUSER.
    • PASSWORD: la password dell'utente.

Crea indici in parallelo

Per creare l'indice più rapidamente, AlloyDB potrebbe generare automaticamente più worker paralleli a seconda del set di dati e del tipo di indice scelto. Questo si verifica spesso quando crei un indice ScaNN a tre o quattro livelli o se il set di dati supera i 100 milioni di righe.

Sebbene AlloyDB ottimizzi automaticamente il numero di worker paralleli, puoi ottimizzarli utilizzando i seguenti parametri di pianificazione delle query PostgreSQL:

Per evitare problemi di memoria insufficiente durante la creazione dell'indice ScaNN, assicurati che i flag di database maintenance_work_mem e shared_buffers siano impostati su un valore inferiore alla memoria totale della macchina.

Esegui una query

Dopo aver archiviato e indicizzato gli incorporamenti nel database, puoi iniziare a eseguire query sui dati. Non puoi eseguire query di ricerca collettive utilizzando l'estensione alloydb_scann.

Per trovare i vicini semantici più vicini per una stringa di testo, puoi utilizzare la funzione google_ml.embedding() per tradurre il testo in un vettore.

Poiché google_ml.embedding() restituisce un array reale, devi eseguire il cast esplicito della chiamata di funzione a vector prima di applicarla a uno degli operatori di ricerca dei vicini più prossimi, ad esempio <-> per la distanza L2. Questi operatori possono quindi utilizzare l'indice ScaNN per trovare le righe del database con gli incorporamenti semanticamente più simili.

SELECT * FROM TABLE
ORDER BY EMBEDDING_COLUMN DISTANCE_FUNCTION_QUERY
  google_ml.embedding(
      model_id => 'MODEL_ID',
      content => 'CONTENT')::vector
LIMIT ROW_COUNT

Sostituisci le seguenti variabili:

  • TABLE: tabella contenente l'embedding a cui confrontare il testo.

  • INDEX_NAME: il nome dell'indice che vuoi utilizzare. Ad esempio, my_scann_index.

  • EMBEDDING_COLUMN: colonna contenente gli embedding archiviati.

  • DISTANCE_FUNCTION_QUERY: funzione di distanza da utilizzare con questa query. Scegli l'equivalente della query per la funzione di distanza quando hai creato l'indice:

    • Distanza L2: <->

    • Prodotto interno: <#>

    • Distanza coseno: <=>

  • MODEL_ID: l'ID del modello di incorporamento registrato che vuoi utilizzare.

  • CONTENT: la stringa di testo che vuoi tradurre in un embedding e cercare.

  • ROW_COUNT: numero di righe da restituire. Ad esempio, specifica 1 se vuoi la corrispondenza singola migliore.

Passaggi successivi