milvus-logo
LFAI
Home
  • Benutzerhandbuch

Sparsamer Vektor

Sparse Vectors sind eine wichtige Methode der Datendarstellung im Information Retrieval und der Verarbeitung natürlicher Sprache. Während dichte Vektoren wegen ihrer ausgezeichneten semantischen Verständnisfähigkeiten beliebt sind, liefern spärliche Vektoren oft genauere Ergebnisse, wenn es um Anwendungen geht, die eine präzise Übereinstimmung von Schlüsselwörtern oder Phrasen erfordern.

Überblick

Ein spärlicher Vektor ist eine spezielle Darstellung hochdimensionaler Vektoren, bei der die meisten Elemente Null sind und nur einige wenige Dimensionen Werte ungleich Null haben. Diese Eigenschaft macht Sparse-Vektoren besonders effektiv bei der Verarbeitung großer, hochdimensionaler, aber spärlicher Daten. Zu den üblichen Anwendungen gehören.

  • Textanalyse: Darstellung von Dokumenten als Bag-of-Words-Vektoren, bei denen jede Dimension einem Wort entspricht und nur Wörter, die in dem Dokument vorkommen, Werte ungleich Null haben.

  • Empfehlungssysteme: Benutzer-Element-Interaktionsmatrizen, bei denen jede Dimension die Bewertung eines Benutzers für ein bestimmtes Element darstellt, wobei die meisten Benutzer nur mit einigen wenigen Elementen interagieren.

  • Bildverarbeitung: Lokale Merkmalsdarstellung, die sich nur auf Schlüsselpunkte im Bild konzentriert, was zu hochdimensionalen spärlichen Vektoren führt.

Wie im folgenden Diagramm dargestellt, werden dichte Vektoren in der Regel als kontinuierliche Arrays dargestellt, bei denen jede Position einen Wert hat (z. B. [0.3, 0.8, 0.2, 0.3, 0.1]). Im Gegensatz dazu werden in spärlichen Vektoren nur Nicht-Null-Elemente und ihre Indizes gespeichert, die oft als Schlüssel-Wert-Paare dargestellt werden (z. B. [{2: 0.2}, ..., {9997: 0.5}, {9999: 0.7}]). Diese Darstellung reduziert den Speicherplatz erheblich und erhöht die Recheneffizienz, insbesondere bei extrem hochdimensionalen Daten (z. B. 10.000 Dimensionen).

Spare vector representation Ersatzvektor-Darstellung

Sparse Vektoren können mit verschiedenen Methoden erzeugt werden, wie z.B. TF-IDF (Term Frequency-Inverse Document Frequency) und BM25 in der Textverarbeitung. Darüber hinaus bietet Milvus komfortable Methoden, um spärliche Vektoren zu erzeugen und zu verarbeiten. Details hierzu finden Sie unter Einbettungen.

Für Textdaten bietet Milvus auch Volltextsuchfunktionen, die es Ihnen ermöglichen, Vektorsuchen direkt auf rohen Textdaten durchzuführen, ohne externe Einbettungsmodelle zur Erzeugung von Sparse-Vektoren zu verwenden. Weitere Informationen finden Sie unter Volltextsuche.

Nach der Vektorisierung können die Daten in Milvus zur Verwaltung und zum Abruf der Vektoren gespeichert werden. Das folgende Diagramm veranschaulicht den grundlegenden Prozess.

Use sparse vector in Milvus Verwendung von Sparse-Vektoren in Milvus

Neben spärlichen Vektoren unterstützt Milvus auch dichte Vektoren und binäre Vektoren. Dichte Vektoren sind ideal für die Erfassung tiefer semantischer Beziehungen, während binäre Vektoren sich in Szenarien wie schnellen Ähnlichkeitsvergleichen und der Deduplizierung von Inhalten auszeichnen. Weitere Informationen finden Sie unter Dense-Vektoren und binäre Vektoren.

Spärliche Vektoren in Milvus verwenden

Milvus unterstützt die Darstellung spärlicher Vektoren in einem der folgenden Formate.

  • Sparse Matrix (unter Verwendung der Klasse 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)
    
    
  • Liste von Wörterbüchern (formatiert als {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);
    
    
  • Liste von Tupel-Iteratoren (formatiert als [(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)]]
    
    

Vektorfeld hinzufügen

Um spärliche Vektoren in Milvus zu verwenden, müssen Sie bei der Erstellung einer Sammlung ein Feld für die Speicherung spärlicher Vektoren definieren. Dieser Prozess beinhaltet.

  1. Einstellen von datatype auf den unterstützten Sparse-Vector-Datentyp, SPARSE_FLOAT_VECTOR.

  2. Die Dimension muss nicht angegeben werden.

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 diesem Beispiel wird ein Vektorfeld mit dem Namen sparse_vector zum Speichern von spärlichen Vektoren hinzugefügt. Der Datentyp dieses Feldes ist SPARSE_FLOAT_VECTOR.

Index-Parameter für das Vektorfeld festlegen

Der Prozess der Erstellung eines Index für spärliche Vektoren ähnelt dem für dichte Vektoren, jedoch mit Unterschieden im angegebenen Indextyp (index_type), der Distanzmetrik (metric_type) und den Indexparametern (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}
        }
    ]'

Im obigen Beispiel.

  • Für den Sparse-Vektor wird ein Index vom Typ SPARSE_INVERTED_INDEX erstellt. Für spärliche Vektoren können Sie SPARSE_INVERTED_INDEX oder SPARSE_WAND angeben. Details finden Sie unter Sparse Vector Indexes.

  • Für spärliche Vektoren unterstützt metric_type nur IP (Inneres Produkt), das zur Messung der Ähnlichkeit zwischen zwei spärlichen Vektoren verwendet wird. Weitere Informationen zur Ähnlichkeit finden Sie unter Metrische Typen.

  • drop_ratio_build ist ein optionaler Indexparameter speziell für spärliche Vektoren. Er steuert den Anteil der kleinen Vektorwerte, die bei der Indexerstellung ausgeschlossen werden. Bei {"drop_ratio_build": 0.2} werden beispielsweise die kleinsten 20% der Vektorwerte bei der Indexerstellung ausgeschlossen, was den Rechenaufwand bei der Suche verringert.

Sammlung erstellen

Sobald die Einstellungen für spärliche Vektoren und Indizes abgeschlossen sind, können Sie eine Sammlung erstellen, die spärliche Vektoren enthält. Das folgende Beispiel verwendet die create_collection Methode, um eine Sammlung mit dem Namen my_sparse_collection zu erstellen.

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
}"

Daten einfügen

Fügen Sie nach dem Erstellen der Sammlung Daten ein, die spärliche Vektoren enthalten.

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"]}}

Um eine Ähnlichkeitssuche mit spärlichen Vektoren durchzuführen, bereiten Sie den Abfragevektor und die Suchparameter vor.

# 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 diesem Beispiel ist drop_ratio_search ein optionaler Parameter speziell für spärliche Vektoren, der die Feinabstimmung kleiner Werte im Abfragevektor während der Suche ermöglicht. Mit {"drop_ratio_search": 0.2} werden beispielsweise die kleinsten 20% der Werte im Abfragevektor bei der Suche ignoriert.

Führen Sie dann die Ähnlichkeitssuche mit der Methode search aus.

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"}]}

Weitere Informationen zu den Parametern der Ähnlichkeitssuche finden Sie unter Grundlegende ANN-Suche.

Begrenzungen

Bei der Verwendung von spärlichen Vektoren in Milvus sind die folgenden Grenzen zu beachten:

  • Derzeit wird nur die IP-Distanzmetrik für spärliche Vektoren unterstützt. Die hohe Dimensionalität von spärlichen Vektoren macht L2 und Kosinusabstand unpraktisch.

  • Für spärliche Vektorfelder werden nur die Indextypen SPARSE_INVERTED_INDEX und SPARSE_WAND unterstützt.

  • Die für spärliche Vektoren unterstützten Datentypen:

    • Der Dimensionsteil muss eine 32-Bit-Ganzzahl ohne Vorzeichen sein;
    • Der Wertteil kann eine nicht-negative 32-Bit-Gleitkommazahl sein.
  • Sparse Vectors müssen die folgenden Anforderungen für das Einfügen und Suchen erfüllen:

    • Mindestens ein Wert im Vektor ist ungleich Null;
    • Vektorindizes sind nicht-negativ.

FAQ

  • Können Sie den Unterschied zwischen SPARSE_INVERTED_INDEX und SPARSE_WAND erklären, und wie wähle ich zwischen ihnen?

    SPARSE_INVERTED_INDEX ist ein traditioneller invertierter Index, während SPARSE_WAND den Weak-AND-Algorithmus verwendet, um die Anzahl der vollständigen IP-Abstandsauswertungen während der Suche zu reduzieren. SPARSE_WAND ist in der Regel schneller, aber seine Leistung kann mit zunehmender Vektordichte abnehmen. Um zwischen den beiden Algorithmen zu wählen, führen Sie Experimente und Benchmarks durch, die auf Ihrem spezifischen Datensatz und Anwendungsfall basieren.

  • Wie sollte ich die Parameter drop_ratio_build und drop_ratio_search wählen?

    Die Wahl von drop_ratio_build und drop_ratio_search hängt von den Eigenschaften Ihrer Daten und Ihren Anforderungen an Suchlatenz/Durchsatz und Genauigkeit ab.

  • Kann die Dimension einer Sparse-Einbettung ein beliebiger diskreter Wert innerhalb des uint32-Raums sein?

    Ja, mit einer Ausnahme. Die Dimension einer spärlichen Einbettung kann ein beliebiger Wert im Bereich von [0, maximum of uint32) sein. Das bedeutet, dass Sie nicht den Maximalwert von uint32 verwenden können.

  • Wird die Suche nach wachsenden Segmenten über einen Index oder mit roher Gewalt durchgeführt?

    Die Suche nach wachsenden Segmenten wird über einen Index desselben Typs wie der Index des versiegelten Segments durchgeführt. Für neue wachsende Segmente, bevor der Index aufgebaut ist, wird eine Brute-Force-Suche verwendet.

  • Ist es möglich, sowohl spärliche als auch dichte Vektoren in einer einzigen Sammlung zu haben?

    Ja, mit der Unterstützung für mehrere Vektortypen können Sie Sammlungen mit sowohl spärlichen als auch dichten Vektorspalten erstellen und hybride Suchvorgänge mit ihnen durchführen.

Übersetzt vonDeepL

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started
Feedback

War diese Seite hilfreich?