Archiviare i vettori in Database di Azure per PostgreSQL

Completato

Tenere presente che per eseguire una ricerca semantica sono necessari vettori di incorporamento archiviati in un database vettoriale. Il server flessibile di Database di Azure per PostgreSQL può essere usato come database vettoriale con l'estensione vector .

Diagramma di un server flessibile di Database di Azure per PostgreSQL e dell'estensione denominata

Introduzione a vector

L'estensione open source vector fornisce archiviazione vettoriale, query di somiglianza e altre operazioni vettoriali per PostgreSQL. Dopo l'abilitazione, è possibile creare colonne vector per archiviare incorporamenti (o altri vettori) insieme ad altre colonne.

/* Enable the extension. */
CREATE EXTENSION vector;

/* Create a table containing a 3d vector. */
CREATE TABLE documents (id bigserial PRIMARY KEY, embedding vector(3));

/* Create some sample data. */
INSERT INTO documents (embedding) VALUES
('[1,2,3]'),
('[2,1,3]'),
('[4,5,6]');

Alle tabelle esistenti è possibile aggiungere colonne di vettore:

ALTER TABLE documents ADD COLUMN embedding vector(3);

Una volta ottenuti alcuni dati vettore, è possibile visualizzarli insieme ai normali dati della tabella:

# SELECT * FROM documents;
 id | embedding
----+-----------
 1 | [1,2,3]
 2 | [2,1,3]
 3 | [4,5,6]

L'estensione vector supporta diversi linguaggi, ad esempio .NET, Python, Java e molti altri. Per altre informazioni, vedere repository GitHub.

Per inserire un documento con vettore [1, 2, 3] usando Npgsql in C#, eseguire codice simile al seguente:

var sql = "INSERT INTO documents (embedding) VALUES ($1)";
await using (var cmd = new NpgsqlCommand(sql, conn))
{
  var embedding = new Vector(new float[] { 1, 2, 3 });
  cmd.Parameters.AddWithValue(embedding);
  await cmd.ExecuteNonQueryAsync();
}

Inserire e aggiornare i vettori

Una volta che una tabella disponga di una colonna vettore, è possibile aggiungere righe con valori vettoriali, come indicato in precedenza.

INSERT INTO documents (embedding) VALUES ('[1,2,3]');

È anche possibile caricare vettori in blocco usando l'istruzione (vedere COPY completo in Python):

COPY documents (embedding) FROM STDIN WITH (FORMAT BINARY);

Le colonne vettoriali possono essere aggiornate come le colonne standard:

UPDATE documents SET embedding = '[1,1,1]' where id = 1;

L'estensione vector fornisce l'operatore v1 <=> v2 per calcolare la distanza del coseno tra i vettori v1 e v2. Il risultato è un numero compreso tra 0 e 2, dove 0 indica "semanticamente identico" (nessuna distanza) e due significa "semanticamente opposto" (distanza massima).

È possibile visualizzare i termini distanza coseno e somiglianza. Ricorda che la similarità del coseno è compresa tra -1 e 1, dove -1 significa "semanticamente opposto" e 1 significa "semanticamente identico." Nota similarity = 1 - distance.

Il risultato finale è che una query ordinata per distanza crescente restituisce prima i risultati meno distanti (più simili), mentre una query ordinata per similarità decrescente restituisce prima i risultati più simili (meno distanti).

Qui sono alcuni vettori con le relative distanze e similarità per illustrare i concetti. È possibile eseguire questo calcolo manualmente eseguendo un'operazione del tipo:

SELECT '[1,1]' <=> '[-1,-1]';

Considerare questi vettori:

Grafico 2D che mostra i vettori (1,1), (1,0), (0,1) e (0,0).

Le rispettive similarità e distanze sono:

v1 V2 distanza somiglianza
[1, 1] [1, 1] 0 1
[1, 1] [-1, -1] 2 -1
[1, 0] [0, 1] 1 0

Per ottenere i documenti in ordine di vicinanza al vettore [2, 3, 4], eseguire la query:

SELECT
  *,
  embedding <=> '[2,3,4]' AS distance
FROM documents
ORDER BY distance;

Risultati:

 id | embedding |   distance
----+-----------+-----------------------
 3 | [4,5,6] | 0.0053884541273605535
 1 | [1,2,3] | 0.007416666029069763
 2 | [2,1,3] | 0.05704583272761632

Il documento con id=3 è il più simile alla query, seguito a breve da id=1 e infine da id=2.

Aggiungere una clausola LIMIT N alla query SELECT per restituire i primi N documenti più simili. Ad esempio, per ottenere il documento più simile:

SELECT
  *,
  embedding <=> '[2,3,4]' AS distance
FROM documents
ORDER BY distance
LIMIT 1;

Risultati:

 id | embedding |   distance
----+-----------+-----------------------
 3 | [4,5,6] | 0.0053884541273605535