Vectores dispersos
Los vectores dispersos representan palabras o frases mediante incrustaciones vectoriales en las que la mayoría de los elementos son cero, y sólo un elemento distinto de cero indica la presencia de una palabra específica. Los modelos de vectores dispersos, como SPLADEv2, superan a los modelos densos en la búsqueda de conocimiento fuera del dominio, el conocimiento de palabras clave y la interpretabilidad. Son especialmente útiles en la recuperación de información, el procesamiento del lenguaje natural y los sistemas de recomendación, donde la combinación de vectores dispersos para la recuperación con un modelo denso para la clasificación puede mejorar significativamente los resultados de la recuperación.
En Milvus, el uso de vectores dispersos sigue un flujo de trabajo similar al de los vectores densos. Implica crear una colección con una columna de vectores dispersos, insertar datos, crear un índice y realizar búsquedas de similitud y consultas escalares.
En este tutorial, aprenderá a:
- Preparar incrustaciones de vectores dispersos;
- Crear una colección con un campo de vectores dispersos;
- Insertar entidades con incrustaciones de vectores dispersos;
- Indexar la colección y realizar búsquedas RNA en vectores dispersos.
Para ver vectores dispersos en acción, consulte hello_sparse.py.
notas
Actualmente, el soporte para vectores dispersos es una característica beta en 2.4.0, con planes para que esté disponible de forma general en 3.0.0.Preparar incrustaciones de vectores dispersos
Para utilizar vectores dispersos en Milvus, prepare incrustaciones de vectores en uno de los formatos soportados:
Matrices dispersas: Utilice la familia de clases scipy.sparse para representar sus incrustaciones dispersas. Este método es eficiente para manejar datos a gran escala y de alta dimensión.
Lista de diccionarios: Represente cada incrustación dispersa como un diccionario, estructurado como
{dimension_index: value, ...}
, donde cada par clave-valor representa el índice de dimensión y su valor correspondiente.Ejemplo:
{2: 0.33, 98: 0.72, ...}
Lista de Iterables de Tuplas: Similar a la lista de diccionarios, pero utilizando un iterable de tuplas,
[(dimension_index, value)]
, para especificar sólo las dimensiones distintas de cero y sus valores.Ejemplo:
[(2, 0.33), (98, 0.72), ...]
El siguiente ejemplo prepara incrustaciones dispersas generando una matriz dispersa aleatoria para 10.000 entidades, cada una de ellas con 10.000 dimensiones y una densidad de dispersión de 0,005.
# 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
# }
# }
notas
Las dimensiones del vector deben ser del tipo Python int
o numpy.integer
, y los valores deben ser del tipo Python float
o numpy.floating
.
Para generar incrustaciones, también puede utilizar el paquete model
integrado en la biblioteca PyMilvus, que ofrece una serie de funciones de incrustación. Para más detalles, consulte Embeddings.
Crear una colección con un campo vectorial disperso
Para crear una colección con un campo vectorial disperso, establece el tipo de datos del campo vectorial disperso a DataType.SPARSE_FLOAT_VECTOR. A diferencia de los vectores densos, no es necesario especificar una dimensión para los vectores dispersos.
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)
Para obtener más información sobre los parámetros comunes de las colecciones, consulte create_collection() .
Insertar entidades con incrustaciones de vectores dispersos
Para insertar entidades con incrustaciones de vectores dispersos, basta con pasar la lista de entidades al método insert()
al método
# Insert entities
client.insert(collection_name="test_sparse_vector", data=entities)
Indexar la colección
Antes de realizar búsquedas de similitud, cree un índice para la colección. Para más información sobre tipos de índices y parámetros, consulte add_index() y 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)
Para la creación de índices en vectores dispersos, tenga en cuenta lo siguiente:
index_type
: El tipo de índice que se va a crear. Opciones posibles para vectores dispersos:SPARSE_INVERTED_INDEX
: Un índice invertido que asigna cada dimensión a sus vectores distintos de cero, lo que facilita el acceso directo a los datos relevantes durante las búsquedas. Ideal para conjuntos de datos con datos dispersos pero de alta dimensión.SPARSE_WAND
: Utiliza el algoritmo Weak-AND (WAND) para evitar rápidamente los candidatos poco probables, centrando la evaluación en aquellos con mayor potencial de clasificación. Trata las dimensiones como términos y los vectores como documentos, lo que acelera las búsquedas en conjuntos de datos grandes y dispersos.
metric_type
: Sólo se admite la métrica de distanciaIP
(producto interior) para vectores dispersos.params.drop_ratio_build
: El parámetro de índice utilizado específicamente para vectores dispersos. Controla la proporción de valores de vectores pequeños que se excluyen durante el proceso de indexación. Este parámetro permite ajustar con precisión la relación entre eficacia y precisión, descartando los valores pequeños al construir el índice. Por ejemplo, sidrop_ratio_build = 0.3
, durante la construcción del índice se reúnen y ordenan todos los valores de todos los vectores dispersos. El 30% más pequeño de estos valores no se incluye en el índice, lo que reduce la carga de trabajo computacional durante la búsqueda.
Para más información, consulte Índice en memoria.
Realizar la búsqueda RNA
Una vez indexada la colección y cargada en memoria, utilice el método search()
para recuperar los documentos pertinentes en función de la consulta.
# 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}}
Al configurar los parámetros de búsqueda, tenga en cuenta lo siguiente:
params.drop_ratio_search
: El parámetro de búsqueda utilizado específicamente para vectores dispersos. Esta opción permite ajustar el proceso de búsqueda especificando la proporción de los valores más pequeños del vector de consulta que deben ignorarse. Ayuda a equilibrar la precisión y el rendimiento de la búsqueda. Cuanto menor sea el valor establecido paradrop_ratio_search
, menos contribuirán estos valores pequeños a la puntuación final. Al ignorar algunos valores pequeños, se puede mejorar el rendimiento de la búsqueda con un impacto mínimo en la precisión.
Realizar consultas escalares
Además de la búsqueda RNA, Milvus también admite consultas escalares en vectores dispersos. Estas consultas le permiten recuperar documentos basándose en un valor escalar asociado al vector disperso. Para más información sobre los parámetros, consulte query().
Filtrar entidades con campo_escalar mayor que 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}}]
Filtra entidades por clave primaria:
# 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'}]
Límites
Cuando utilice vectores dispersos en Milvus, tenga en cuenta los siguientes límites:
Actualmente, sólo se admite la métrica de distancia IP para vectores dispersos.
Para los campos de vectores dispersos, sólo se admiten los tipos de índice SPARSE_INVERTED_INDEX y SPARSE_WAND.
Actualmente, la búsqueda de rango, la búsqueda de agrupación y el iterador de búsqueda no son compatibles con los vectores dispersos.
PREGUNTAS FRECUENTES
¿Qué métrica de distancia admiten los vectores dispersos?
Los vectores dispersos sólo admiten la métrica de distancia producto interior (IP) debido a la alta dimensionalidad de los vectores dispersos, que hace que la distancia L2 y la distancia coseno sean poco prácticas.
¿Puede explicar la diferencia entre SPARSE_INVERTED_INDEX y SPARSE_WAND, y cómo puedo elegir entre ellos?
SPARSE_INVERTED_INDEX es un índice invertido tradicional, mientras que SPARSE_WAND utiliza el algoritmo Weak-AND para reducir el número de evaluaciones de distancia IP completa durante la búsqueda. SPARSE_WAND suele ser más rápido, pero su rendimiento puede disminuir al aumentar la densidad del vector. Para elegir entre ellos, realice experimentos y pruebas comparativas basadas en su conjunto de datos y caso de uso específicos.
¿Cómo debo elegir los parámetros drop_ratio_build y drop_ratio_search?
La elección de drop_ratio_build y drop_ratio_search depende de las características de los datos y de los requisitos de latencia/rendimiento y precisión de la búsqueda.
¿Qué tipos de datos se admiten para las incrustaciones dispersas?
La parte de dimensión debe ser un entero de 32 bits sin signo, y la parte de valor puede ser un número de coma flotante de 32 bits no negativo.
¿Puede la dimensión de una incrustación dispersa ser cualquier valor discreto dentro del espacio uint32?
Sí, con una excepción. La dimensión de una incrustación dispersa puede ser cualquier valor dentro del intervalo de
[0, maximum of uint32)
. Esto significa que no se puede utilizar el valor máximo de uint32.¿Las búsquedas en segmentos crecientes se realizan a través de un índice o por fuerza bruta?
Las búsquedas en segmentos crecientes se realizan a través de un índice del mismo tipo que el índice de segmento sellado. Para nuevos segmentos crecientes antes de que se construya el índice, se utiliza una búsqueda por fuerza bruta.
¿Es posible tener vectores dispersos y densos en una misma colección?
Sí, con el soporte de tipos de vectores múltiples, puede crear colecciones con columnas de vectores tanto dispersos como densos y realizar búsquedas híbridas en ellas.
¿Cuáles son los requisitos para insertar o buscar incrustaciones dispersas?
Las incrustaciones dispersas deben tener al menos un valor distinto de cero, y los índices de los vectores deben ser no negativos.