Vettore sparso
I vettori sparsi sono un metodo importante di rappresentazione dei dati nell'information retrieval e nell'elaborazione del linguaggio naturale. Mentre i vettori densi sono popolari per le loro eccellenti capacità di comprensione semantica, i vettori sparsi spesso forniscono risultati più accurati quando si tratta di applicazioni che richiedono una corrispondenza precisa di parole o frasi chiave.
Panoramica
Un vettore rado è una rappresentazione speciale di vettori ad alta dimensione in cui la maggior parte degli elementi è pari a zero e solo alcune dimensioni hanno valori non nulli. Questa caratteristica rende i vettori sparsi particolarmente efficaci nella gestione di dati su larga scala, altamente dimensionali ma scarsi. Le applicazioni più comuni includono.
Analisi del testo: Rappresentazione di documenti come vettori bag-of-words, dove ogni dimensione corrisponde a una parola e solo le parole che compaiono nel documento hanno valori non nulli.
Sistemi di raccomandazione: Matrici di interazione utente-elemento, in cui ogni dimensione rappresenta la valutazione di un utente per un particolare elemento, con la maggior parte degli utenti che interagiscono solo con alcuni elementi.
Elaborazione di immagini: Rappresentazione locale delle caratteristiche, che si concentra solo sui punti chiave dell'immagine, dando luogo a vettori sparsi ad alta dimensione.
Come mostrato nel diagramma seguente, i vettori densi sono tipicamente rappresentati come array continui in cui ogni posizione ha un valore (ad esempio, [0.3, 0.8, 0.2, 0.3, 0.1]
). Al contrario, i vettori sparsi memorizzano solo gli elementi non nulli e i loro indici, spesso rappresentati come coppie chiave-valore (ad esempio, [{2: 0.2}, ..., {9997: 0.5}, {9999: 0.7}]
). Questa rappresentazione riduce significativamente lo spazio di archiviazione e aumenta l'efficienza computazionale, soprattutto quando si tratta di dati ad altissima dimensionalità (ad esempio, 10.000 dimensioni).
Rappresentazione vettoriale sparsa
I vettori sparsi possono essere generati utilizzando vari metodi, come TF-IDF (Term Frequency-Inverse Document Frequency) e BM25 nell'elaborazione dei testi. Inoltre, Milvus offre metodi pratici per aiutare a generare ed elaborare vettori sparsi. Per maggiori dettagli, consultare Embeddings.
Per i dati di testo, Milvus offre anche funzionalità di ricerca full-text, che consentono di eseguire ricerche vettoriali direttamente sui dati di testo grezzi senza utilizzare modelli di incorporamento esterni per generare vettori sparsi. Per ulteriori informazioni, consultare la sezione Ricerca a testo completo.
Dopo la vettorizzazione, i dati possono essere archiviati in Milvus per la gestione e il recupero dei vettori. Il diagramma seguente illustra il processo di base.
Utilizzo di vettori sparsi in Milvus
Oltre ai vettori sparsi, Milvus supporta anche vettori densi e vettori binari. I vettori densi sono ideali per catturare relazioni semantiche profonde, mentre i vettori binari eccellono in scenari come il confronto rapido delle somiglianze e la deduplicazione dei contenuti. Per ulteriori informazioni, consultare Vettori densi e vettori binari.
Utilizzare vettori sparsi in Milvus
Milvus supporta la rappresentazione di vettori sparsi in uno dei seguenti formati.
Matrice sparsa (usando la classe
scipy.sparse
)from scipy.sparse import csr_matrix # Create a sparse matrix row = [0, 0, 1, 2, 2, 2] col = [0, 2, 2, 0, 1, 2] data = [1, 2, 3, 4, 5, 6] sparse_matrix = csr_matrix((data, (row, col)), shape=(3, 3)) # Represent sparse vector using the sparse matrix sparse_vector = sparse_matrix.getrow(0)
Elenco di dizionari (formattato come
{dimension_index: value, ...}
)# Represent sparse vector using a dictionary sparse_vector = [{1: 0.5, 100: 0.3, 500: 0.8, 1024: 0.2, 5000: 0.6}]
SortedMap<Long, Float> sparseVector = new TreeMap<>(); sparseVector.put(1L, 0.5f); sparseVector.put(100L, 0.3f); sparseVector.put(500L, 0.8f); sparseVector.put(1024L, 0.2f); sparseVector.put(5000L, 0.6f);
Elenco di iteratori di tuple (formattato come
[(dimension_index, value)]
)# Represent sparse vector using a list of tuples sparse_vector = [[(1, 0.5), (100, 0.3), (500, 0.8), (1024, 0.2), (5000, 0.6)]]
Aggiungere un campo vettoriale
Per utilizzare i vettori sparsi in Milvus, definire un campo per la memorizzazione dei vettori sparsi quando si crea una collezione. Questo processo comprende.
Impostare
datatype
sul tipo di dati vettoriale sparse supportato,SPARSE_FLOAT_VECTOR
.Non è necessario specificare la dimensione.
from pymilvus import MilvusClient, DataType
client = MilvusClient(uri="http://localhost:19530")
client.drop_collection(collection_name="my_sparse_collection")
schema = client.create_schema(
auto_id=True,
enable_dynamic_fields=True,
)
schema.add_field(field_name="pk", datatype=DataType.VARCHAR, is_primary=True, max_length=100)
schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("http://localhost:19530")
.build());
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.setEnableDynamicField(true);
schema.addField(AddFieldReq.builder()
.fieldName("pk")
.dataType(DataType.VarChar)
.isPrimaryKey(true)
.autoID(true)
.maxLength(100)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("sparse_vector")
.dataType(DataType.SparseFloatVector)
.build());
import { DataType } from "@zilliz/milvus2-sdk-node";
const schema = [
{
name: "metadata",
data_type: DataType.JSON,
},
{
name: "pk",
data_type: DataType.Int64,
is_primary_key: true,
},
{
name: "sparse_vector",
data_type: DataType.SparseFloatVector,
}
];
export primaryField='{
"fieldName": "pk",
"dataType": "VarChar",
"isPrimary": true,
"elementTypeParams": {
"max_length": 100
}
}'
export vectorField='{
"fieldName": "sparse_vector",
"dataType": "SparseFloatVector"
}'
export schema="{
\"autoID\": true,
\"fields\": [
$primaryField,
$vectorField
]
}"
In questo esempio, viene aggiunto un campo vettoriale chiamato sparse_vector
per memorizzare vettori sparsi. Il tipo di dati di questo campo è SPARSE_FLOAT_VECTOR
.
Impostare i parametri dell'indice per il campo vettoriale
Il processo di creazione di un indice per i vettori sparsi è simile a quello dei vettori densi, ma con differenze nel tipo di indice specificato (index_type
), nella metrica della distanza (metric_type
) e nei parametri dell'indice (params
).
index_params = client.prepare_index_params()
index_params.add_index(
field_name="sparse_vector",
index_name="sparse_inverted_index",
index_type="SPARSE_INVERTED_INDEX",
metric_type="IP",
params={"drop_ratio_build": 0.2},
)
import io.milvus.v2.common.IndexParam;
import java.util.*;
List<IndexParam> indexes = new ArrayList<>();
Map<String,Object> extraParams = new HashMap<>();
extraParams.put("drop_ratio_build", 0.2);
indexes.add(IndexParam.builder()
.fieldName("sparse_vector")
.indexName("sparse_inverted_index")
.indexType(IndexParam.IndexType.SPARSE_INVERTED_INDEX)
.metricType(IndexParam.MetricType.IP)
.extraParams(extraParams)
.build());
const indexParams = await client.createIndex({
index_name: 'sparse_inverted_index',
field_name: 'sparse_vector',
metric_type: MetricType.IP,
index_type: IndexType.SPARSE_WAND,
params: {
drop_ratio_build: 0.2,
},
});
export indexParams='[
{
"fieldName": "sparse_vector",
"metricType": "IP",
"indexName": "sparse_inverted_index",
"indexType": "SPARSE_INVERTED_INDEX",
"params":{"drop_ratio_build": 0.2}
}
]'
Nell'esempio precedente.
Per il vettore sparse viene creato un indice di tipo
SPARSE_INVERTED_INDEX
. Per i vettori sparsi, è possibile specificareSPARSE_INVERTED_INDEX
oSPARSE_WAND
. Per maggiori dettagli, consultare la sezione Indici di vettori sparsi.Per i vettori sparsi,
metric_type
supporta soloIP
(Prodotto interno), usato per misurare la somiglianza tra due vettori sparsi. Per ulteriori informazioni sulla somiglianza, fare riferimento a Tipi di metriche.drop_ratio_build
è un parametro indice opzionale specifico per i vettori sparsi. Controlla la percentuale di valori piccoli del vettore esclusi durante la costruzione dell'indice. Ad esempio, con{"drop_ratio_build": 0.2}
, il 20% più piccolo dei valori vettoriali sarà escluso durante la creazione dell'indice, riducendo lo sforzo computazionale durante le ricerche.
Creare la collezione
Una volta completate le impostazioni dei vettori sparsi e dell'indice, è possibile creare una raccolta che contenga vettori sparsi. L'esempio seguente utilizza il metodo create_collection
per creare un insieme chiamato my_sparse_collection
.
client.create_collection(
collection_name="my_sparse_collection",
schema=schema,
index_params=index_params
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("http://localhost:19530")
.build());
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
.collectionName("my_sparse_collection")
.collectionSchema(schema)
.indexParams(indexes)
.build();
client.createCollection(requestCreate);
import { MilvusClient } from "@zilliz/milvus2-sdk-node";
const client = new MilvusClient({
address: 'http://localhost:19530'
});
await client.createCollection({
collection_name: 'my_sparse_collection',
schema: schema,
index_params: indexParams
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
\"collectionName\": \"my_sparse_collection\",
\"schema\": $schema,
\"indexParams\": $indexParams
}"
Inserire i dati
Dopo aver creato la collezione, inserire i dati contenenti vettori sparsi.
sparse_vectors = [
{"sparse_vector": {1: 0.5, 100: 0.3, 500: 0.8}},
{"sparse_vector": {10: 0.1, 200: 0.7, 1000: 0.9}},
]
client.insert(
collection_name="my_sparse_collection",
data=sparse_vectors
)
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.response.InsertResp;
List<JsonObject> rows = new ArrayList<>();
Gson gson = new Gson();
{
JsonObject row = new JsonObject();
SortedMap<Long, Float> sparse = new TreeMap<>();
sparse.put(1L, 0.5f);
sparse.put(100L, 0.3f);
sparse.put(500L, 0.8f);
row.add("sparse_vector", gson.toJsonTree(sparse));
rows.add(row);
}
{
JsonObject row = new JsonObject();
SortedMap<Long, Float> sparse = new TreeMap<>();
sparse.put(10L, 0.1f);
sparse.put(200L, 0.7f);
sparse.put(1000L, 0.9f);
row.add("sparse_vector", gson.toJsonTree(sparse));
rows.add(row);
}
InsertResp insertR = client.insert(InsertReq.builder()
.collectionName("my_sparse_collection")
.data(rows)
.build());
const data = [
{ sparse_vector: { "1": 0.5, "100": 0.3, "500": 0.8 } },
{ sparse_vector: { "10": 0.1, "200": 0.7, "1000": 0.9 } },
];
client.insert({
collection_name: "my_sparse_collection",
data: data,
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"data": [
{"sparse_vector": {"1": 0.5, "100": 0.3, "500": 0.8}},
{"sparse_vector": {"10": 0.1, "200": 0.7, "1000": 0.9}}
],
"collectionName": "my_sparse_collection"
}'
## {"code":0,"cost":0,"data":{"insertCount":2,"insertIds":["453577185629572534","453577185629572535"]}}
Eseguire la ricerca di similarità
Per eseguire una ricerca di similarità utilizzando vettori sparsi, preparare il vettore di interrogazione e i parametri di ricerca.
# Prepare search parameters
search_params = {
"params": {"drop_ratio_search": 0.2}, # Additional optional search parameters
}
# Prepare the query vector
query_vector = [{1: 0.2, 50: 0.4, 1000: 0.7}]
In questo esempio, drop_ratio_search
è un parametro opzionale specifico per i vettori sparsi, che consente di regolare con precisione i piccoli valori del vettore di interrogazione durante la ricerca. Ad esempio, con {"drop_ratio_search": 0.2}
, il 20% più piccolo dei valori nel vettore di interrogazione sarà ignorato durante la ricerca.
Quindi, eseguire la ricerca di similarità con il metodo search
.
res = client.search(
collection_name="my_sparse_collection",
data=query_vector,
limit=3,
output_fields=["pk"],
search_params=search_params,
)
print(res)
# Output
# data: ["[{'id': '453718927992172266', 'distance': 0.6299999952316284, 'entity': {'pk': '453718927992172266'}}, {'id': '453718927992172265', 'distance': 0.10000000149011612, 'entity': {'pk': '453718927992172265'}}]"]
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.SparseFloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
Map<String,Object> searchParams = new HashMap<>();
searchParams.put("drop_ratio_search", 0.2);
SortedMap<Long, Float> sparse = new TreeMap<>();
sparse.put(10L, 0.1f);
sparse.put(200L, 0.7f);
sparse.put(1000L, 0.9f);
SparseFloatVec queryVector = new SparseFloatVec(sparse);
SearchResp searchR = client.search(SearchReq.builder()
.collectionName("my_sparse_collection")
.data(Collections.singletonList(queryVector))
.annsField("sparse_vector")
.searchParams(searchParams)
.topK(3)
.outputFields(Collections.singletonList("pk"))
.build());
System.out.println(searchR.getSearchResults());
// Output
//
// [[SearchResp.SearchResult(entity={pk=453444327741536759}, score=1.31, id=453444327741536759), SearchResp.SearchResult(entity={pk=453444327741536756}, score=1.31, id=453444327741536756), SearchResp.SearchResult(entity={pk=453444327741536753}, score=1.31, id=453444327741536753)]]
client.search({
collection_name: 'my_sparse_collection',
data: {1: 0.2, 50: 0.4, 1000: 0.7},
limit: 3,
output_fields: ['pk'],
params: {
drop_ratio_search: 0.2
}
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_sparse_collection",
"data": [
{"1": 0.2, "50": 0.4, "1000": 0.7}
],
"annsField": "sparse_vector",
"limit": 3,
"searchParams":{
"params":{"drop_ratio_search": 0.2}
},
"outputFields": ["pk"]
}'
## {"code":0,"cost":0,"data":[{"distance":0.63,"id":"453577185629572535","pk":"453577185629572535"},{"distance":0.1,"id":"453577185629572534","pk":"453577185629572534"}]}
Per ulteriori informazioni sui parametri di ricerca per similarità, consultare la sezione Ricerca di base di RNA.
Limiti
Quando si utilizzano vettori sparsi in Milvus, si devono considerare i seguenti limiti:
Attualmente, per i vettori sparsi è supportata solo la metrica della distanza IP. L'elevata dimensionalità dei vettori sparsi rende impraticabili le distanze L2 e coseno.
Per i campi vettoriali sparsi sono supportati solo i tipi di indice SPARSE_INVERTED_INDEX e SPARSE_WAND.
I tipi di dati supportati per i vettori sparsi:
- La parte della dimensione deve essere un intero a 32 bit senza segno;
- La parte del valore può essere un numero non negativo a 32 bit in virgola mobile.
I vettori sparsi devono soddisfare i seguenti requisiti per l'inserimento e la ricerca:
- Almeno un valore del vettore è diverso da zero;
- Gli indici del vettore sono non negativi.
DOMANDE FREQUENTI
Potete spiegare la differenza tra SPARSE_INVERTED_INDEX e SPARSE_WAND e come posso scegliere tra i due?
SPARSE_INVERTED_INDEX è un indice invertito tradizionale, mentre SPARSE_WAND utilizza l'algoritmo Weak-AND per ridurre il numero di valutazioni della distanza IP completa durante la ricerca. SPARSE_WAND è in genere più veloce, ma le sue prestazioni possono diminuire con l'aumentare della densità dei vettori. Per scegliere, è necessario condurre esperimenti e benchmark in base al set di dati e al caso d'uso specifici.
Come scegliere i parametri drop_ratio_build e drop_ratio_search?
La scelta di drop_ratio_build e drop_ratio_search dipende dalle caratteristiche dei dati e dai requisiti di latenza/throughput e precisione della ricerca.
La dimensione di un incorporamento rado può essere un qualsiasi valore discreto all'interno dello spazio uint32?
Sì, con un'eccezione. La dimensione di un incorporamento sparse può essere qualsiasi valore nell'intervallo
[0, maximum of uint32)
. Ciò significa che non è possibile utilizzare il valore massimo di uint32.Le ricerche sui segmenti crescenti sono condotte attraverso un indice o con la forza bruta?
Le ricerche sui segmenti crescenti vengono condotte attraverso un indice dello stesso tipo dell'indice del segmento sigillato. Per i nuovi segmenti crescenti prima che l'indice sia costruito, si usa una ricerca a forza bruta.
È possibile avere vettori sparsi e densi in un'unica collezione?
Sì, grazie al supporto di più tipi di vettore, è possibile creare collezioni con colonne di vettori sia sparse che dense ed eseguire ricerche ibride su di esse.