Spärlicher Vektor
Sparse Vectors stellen Wörter oder Phrasen mithilfe von Vektoreinbettungen dar, bei denen die meisten Elemente Null sind und nur ein Element, das nicht Null ist, das Vorhandensein eines bestimmten Wortes anzeigt. Modelle mit spärlichen Vektoren, wie SPLADEv2, übertreffen dichte Modelle bei der Suche nach Wissen außerhalb der Domäne, der Kenntnis von Schlüsselwörtern und der Interpretierbarkeit. Sie sind besonders nützlich im Information Retrieval, in der natürlichen Sprachverarbeitung und in Empfehlungssystemen, wo die Kombination von spärlichen Vektoren für den Abruf mit einem großen Modell für das Ranking die Retrieval-Ergebnisse erheblich verbessern kann.
In Milvus folgt die Verwendung von spärlichen Vektoren einem ähnlichen Arbeitsablauf wie der von dichten Vektoren. Er umfasst das Erstellen einer Sammlung mit einer Spalte für spärliche Vektoren, das Einfügen von Daten, das Erstellen eines Indexes und das Durchführen von Ähnlichkeitssuchen und skalaren Abfragen.
In diesem Tutorial werden Sie lernen, wie man:
- Sparse-Vektor-Einbettungen vorbereiten;
- eine Sammlung mit einem Sparse-Vektor-Feld erstellen;
- Einfügen von Entitäten mit spärlichen Vektoreinbettungen;
- Indizieren der Sammlung und Durchführen einer ANN-Suche auf spärlichen Vektoren.
Um spärliche Vektoren in Aktion zu sehen, siehe hello_sparse.py.
Hinweise
Derzeit ist die Unterstützung für spärliche Vektoren ein Beta-Feature in 2.4.0, mit Plänen, es in 3.0.0 allgemein verfügbar zu machen.Sparse-Vektor-Einbettungen vorbereiten
Um spärliche Vektoren in Milvus zu verwenden, bereiten Sie Vektoreinbettungen in einem der unterstützten Formate vor:
Sparse Matrices: Verwenden Sie die scipy.sparse Klassenfamilie, um Ihre sparse Einbettungen darzustellen. Diese Methode ist effizient für den Umgang mit großen, hochdimensionalen Daten.
Liste von Wörterbüchern: Stellen Sie jede Sparse-Einbettung als Wörterbuch dar, strukturiert als
{dimension_index: value, ...}
, wobei jedes Schlüssel-Wert-Paar den Dimensionsindex und den entsprechenden Wert darstellt.Beispiel:
{2: 0.33, 98: 0.72, ...}
Liste von Iterablen von Tupeln: Ähnlich wie eine Liste von Wörterbüchern, aber Verwendung einer Iterable von Tupeln,
[(dimension_index, value)]
, um nur die Nicht-Null-Dimensionen und ihre Werte anzugeben.Beispiel:
[(2, 0.33), (98, 0.72), ...]
Das folgende Beispiel bereitet Sparse Embeddings vor, indem es eine zufällige Sparse-Matrix für 10.000 Entitäten mit jeweils 10.000 Dimensionen und einer Sparsity-Dichte von 0,005 erzeugt.
# Prepare entities with sparse vector representation
import numpy as np
import random
rng = np.random.default_rng()
num_entities, dim = 10000, 10000
# Generate random sparse rows with an average of 25 non-zero elements per row
entities = [
{
"scalar_field": rng.random(),
# To represent a single sparse vector row, you can use:
# - Any of the scipy.sparse sparse matrices class family with shape[0] == 1
# - Dict[int, float]
# - Iterable[Tuple[int, float]]
"sparse_vector": {
d: rng.random() for d in random.sample(range(dim), random.randint(20, 30))
},
}
for _ in range(num_entities)
]
# print the first entity to check the representation
print(entities[0])
# Output:
# {
# 'scalar_field': 0.520821523849214,
# 'sparse_vector': {
# 5263: 0.2639375518635271,
# 3573: 0.34701499565746674,
# 9637: 0.30856525997853057,
# 4399: 0.19771651149001523,
# 6959: 0.31025067641541815,
# 1729: 0.8265339135915016,
# 1220: 0.15303302147479103,
# 7335: 0.9436728846033107,
# 6167: 0.19929870545596562,
# 5891: 0.8214617920371853,
# 2245: 0.7852255053773395,
# 2886: 0.8787982039149889,
# 8966: 0.9000606703940665,
# 4910: 0.3001170013981104,
# 17: 0.00875671667413136,
# 3279: 0.7003425473001098,
# 2622: 0.7571360018373428,
# 4962: 0.3901879090102064,
# 4698: 0.22589525720196246,
# 3290: 0.5510228492587324,
# 6185: 0.4508413201390492
# }
# }
Hinweise
Die Vektordimensionen müssen vom Typ Python int
oder numpy.integer
sein, und die Werte müssen vom Typ Python float
oder numpy.floating
sein.
Zum Erzeugen von Einbettungen können Sie auch das in der PyMilvus-Bibliothek enthaltene Paket model
verwenden, das eine Reihe von Einbettungsfunktionen bietet. Einzelheiten finden Sie unter Einbettungen.
Erstellen einer Sammlung mit einem spärlichen Vektorfeld
Um eine Sammlung mit einem spärlichen Vektorfeld zu erstellen, setzen Sie den Datentyp des spärlichen Vektorfeldes auf DataType.SPARSE_FLOAT_VECTOR. Im Gegensatz zu dichten Vektoren muss für Sparse-Vektoren keine Dimension angegeben werden.
from pymilvus import MilvusClient, DataType
# Create a MilvusClient instance
client = MilvusClient(uri="http://localhost:19530")
# Create a collection with a sparse vector field
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="scalar_field", datatype=DataType.DOUBLE)
# For sparse vector, no need to specify dimension
schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR) # set `datatype` to `SPARSE_FLOAT_VECTOR`
client.create_collection(collection_name="test_sparse_vector", schema=schema)
Einzelheiten zu den üblichen Sammlungsparametern finden Sie unter create_collection() .
Einfügen von Entitäten mit spärlichen Vektoreinbettungen
Um Entitäten mit spärlichen Vektoreinbettungen einzufügen, übergeben Sie einfach die Liste der Entitäten an die insert()
Methode.
# Insert entities
client.insert(collection_name="test_sparse_vector", data=entities)
Indizieren der Sammlung
Bevor Sie Ähnlichkeitssuchen durchführen, erstellen Sie einen Index für die Sammlung. Weitere Informationen über Index-Typen und -Parameter finden Sie unter add_index() und create_index().
# Index the collection
# Prepare index 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", # the type of index to be created. set to `SPARSE_INVERTED_INDEX` or `SPARSE_WAND`.
metric_type="IP", # the metric type to be used for the index. Currently, only `IP` (Inner Product) is supported.
params={"drop_ratio_build": 0.2}, # the ratio of small vector values to be dropped during indexing.
)
# Create index
client.create_index(collection_name="test_sparse_vector", index_params=index_params)
Für die Indexerstellung auf spärlichen Vektoren ist folgendes zu beachten:
index_type
: Der Typ des zu erstellenden Index. Mögliche Optionen für spärliche Vektoren:SPARSE_INVERTED_INDEX
: Ein invertierter Index, der jede Dimension auf ihre Nicht-Null-Vektoren abbildet und so den direkten Zugriff auf relevante Daten bei der Suche erleichtert. Ideal für Datensätze mit spärlichen, aber hochdimensionalen Daten.SPARSE_WAND
: Verwendet den Weak-AND-Algorithmus (WAND), um unwahrscheinliche Kandidaten schnell zu umgehen und die Bewertung auf diejenigen mit höherem Rangpotenzial zu konzentrieren. Behandelt Dimensionen als Begriffe und Vektoren als Dokumente, um die Suche in großen, spärlichen Datensätzen zu beschleunigen.
metric_type
: Nur dieIP
(Inner Product) Distanzmetrik wird für spärliche Vektoren unterstützt.params.drop_ratio_build
: Der Index-Parameter, der speziell für spärliche Vektoren verwendet wird. Er steuert den Anteil der kleinen Vektorwerte, die während des Indizierungsprozesses ausgeschlossen werden. Dieser Parameter ermöglicht eine Feinabstimmung des Kompromisses zwischen Effizienz und Genauigkeit, indem kleine Werte bei der Indexerstellung außer Acht gelassen werden. Wenn beispielsweisedrop_ratio_build = 0.3
gewählt wird, werden während der Indexerstellung alle Werte aus allen spärlichen Vektoren gesammelt und sortiert. Die kleinsten 30 % dieser Werte werden nicht in den Index aufgenommen, wodurch die Rechenlast bei der Suche verringert wird.
Weitere Informationen finden Sie unter In-Memory-Index.
ANN-Suche durchführen
Nachdem die Sammlung indiziert und in den Speicher geladen wurde, verwenden Sie die search()
Methode, um die relevanten Dokumente auf der Grundlage der Abfrage abzurufen.
# Load the collection into memory
client.load_collection(collection_name="test_sparse_vector")
# Perform ANN search on sparse vectors
# for demo purpose we search for the last inserted vector
query_vector = entities[-1]["sparse_vector"]
search_params = {
"metric_type": "IP",
"params": {"drop_ratio_search": 0.2}, # the ratio of small vector values to be dropped during search.
}
search_res = client.search(
collection_name="test_sparse_vector",
data=[query_vector],
limit=3,
output_fields=["pk", "scalar_field"],
search_params=search_params,
)
for hits in search_res:
for hit in hits:
print(f"hit: {hit}")
# Output:
# hit: {'id': '448458373272710786', 'distance': 7.220192909240723, 'entity': {'pk': '448458373272710786', 'scalar_field': 0.46767865218233806}}
# hit: {'id': '448458373272708317', 'distance': 1.2287548780441284, 'entity': {'pk': '448458373272708317', 'scalar_field': 0.7315987515699472}}
# hit: {'id': '448458373272702005', 'distance': 0.9848432540893555, 'entity': {'pk': '448458373272702005', 'scalar_field': 0.9871869181562156}}
Beachten Sie bei der Konfiguration der Suchparameter die folgenden Punkte:
params.drop_ratio_search
: Der Suchparameter, der speziell für spärliche Vektoren verwendet wird. Diese Option ermöglicht eine Feinabstimmung des Suchprozesses, indem sie das Verhältnis der kleinsten Werte im Abfragevektor angibt, die ignoriert werden sollen. Sie hilft, ein Gleichgewicht zwischen Suchgenauigkeit und Leistung herzustellen. Je kleiner der Wert fürdrop_ratio_search
eingestellt wird, desto weniger tragen diese kleinen Werte zur endgültigen Bewertung bei. Durch das Ignorieren einiger kleiner Werte kann die Suchleistung mit minimalen Auswirkungen auf die Genauigkeit verbessert werden.
Skalare Abfragen durchführen
Zusätzlich zur ANN-Suche unterstützt Milvus auch skalare Abfragen auf spärlichen Vektoren. Mit diesen Abfragen können Sie Dokumente auf der Grundlage eines mit dem Sparse-Vektor verbundenen Skalarwerts abrufen. Weitere Informationen zu den Parametern finden Sie in query().
Filtert Entitäten mit scalar_field größer als 3:
# Perform a query by specifying filter expr
filter_query_res = client.query(
collection_name="test_sparse_vector",
filter="scalar_field > 0.999",
)
print(filter_query_res[:2])
# Output:
# [{'pk': '448458373272701862', 'scalar_field': 0.9994093623822689, 'sparse_vector': {173: 0.35266244411468506, 400: 0.49995484948158264, 480: 0.8757831454277039, 661: 0.9931875467300415, 1040: 0.0965644046664238, 1728: 0.7478245496749878, 2365: 0.4351981580257416, 2923: 0.5505295395851135, 3181: 0.7396837472915649, 3848: 0.4428485333919525, 4701: 0.39119353890419006, 5199: 0.790219783782959, 5798: 0.9623121619224548, 6213: 0.453134149312973, 6341: 0.745091438293457, 6775: 0.27766478061676025, 6875: 0.017947908490896225, 8093: 0.11834774166345596, 8617: 0.2289179265499115, 8991: 0.36600416898727417, 9346: 0.5502803921699524}}, {'pk': '448458373272702421', 'scalar_field': 0.9990218525410719, 'sparse_vector': {448: 0.587817907333374, 1866: 0.0994109958410263, 2438: 0.8672442436218262, 2533: 0.8063794374465942, 2595: 0.02122959867119789, 2828: 0.33827054500579834, 2871: 0.1984412521123886, 2938: 0.09674275666475296, 3154: 0.21552987396717072, 3662: 0.5236313343048096, 3711: 0.6463911533355713, 4029: 0.4041993021965027, 7143: 0.7370485663414001, 7589: 0.37588241696357727, 7776: 0.436136394739151, 7962: 0.06377989053726196, 8385: 0.5808192491531372, 8592: 0.8865005970001221, 8648: 0.05727503448724747, 9071: 0.9450633525848389, 9161: 0.146037295460701, 9358: 0.1903032660484314, 9679: 0.3146636486053467, 9974: 0.8561339378356934, 9991: 0.15841573476791382}}]
Filtert Entitäten nach dem Primärschlüssel:
# primary keys of entities that satisfy the filter
pks = [ret["pk"] for ret in filter_query_res]
# Perform a query by primary key
pk_query_res = client.query(
collection_name="test_sparse_vector", filter=f"pk == '{pks[0]}'"
)
print(pk_query_res)
# Output:
# [{'scalar_field': 0.9994093623822689, 'sparse_vector': {173: 0.35266244411468506, 400: 0.49995484948158264, 480: 0.8757831454277039, 661: 0.9931875467300415, 1040: 0.0965644046664238, 1728: 0.7478245496749878, 2365: 0.4351981580257416, 2923: 0.5505295395851135, 3181: 0.7396837472915649, 3848: 0.4428485333919525, 4701: 0.39119353890419006, 5199: 0.790219783782959, 5798: 0.9623121619224548, 6213: 0.453134149312973, 6341: 0.745091438293457, 6775: 0.27766478061676025, 6875: 0.017947908490896225, 8093: 0.11834774166345596, 8617: 0.2289179265499115, 8991: 0.36600416898727417, 9346: 0.5502803921699524}, 'pk': '448458373272701862'}]
Begrenzt
Bei der Verwendung von Sparse Vectors in Milvus sind die folgenden Einschränkungen zu beachten:
Derzeit wird nur die IP-Distanzmetrik für Sparse-Vektoren unterstützt.
Für spärliche Vektorfelder werden nur die Indexarten SPARSE_INVERTED_INDEX und SPARSE_WAND unterstützt.
Derzeit werden Bereichssuche, Gruppierungssuche und Such-Iterator für spärliche Vektoren nicht unterstützt.
FAQ
Welche Abstandsmetrik wird für spärliche Vektoren unterstützt?
Sparse Vektoren unterstützen nur die Distanzmetrik Inneres Produkt (IP) aufgrund der hohen Dimensionalität von Sparse Vektoren, die L2-Distanz und Kosinusdistanz unpraktisch macht.
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 herkömmlicher 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.
Welche Datentypen werden für Sparse Embeddings unterstützt?
Der Dimensionsteil muss eine vorzeichenlose 32-Bit-Ganzzahl sein, und der Werteteil kann eine nicht-negative 32-Bit-Gleitkommazahl sein.
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 mehrerer Vektortypen können Sie Sammlungen mit sowohl spärlichen als auch dichten Vektorspalten erstellen und eine hybride Suche durchführen.
Welche Voraussetzungen müssen erfüllt sein, damit Sparse Embeddings eingefügt oder durchsucht werden können?
Sparse Embeddings müssen mindestens einen Wert ungleich Null haben, und Vektorindizes müssen nicht negativ sein.