Con iteradores
Milvus proporciona iteradores de búsqueda y consulta para iterar resultados con un gran volumen de entidades. Dado que Milvus limita TopK a 16384, los usuarios pueden utilizar iteradores para devolver grandes números o incluso entidades enteras en una colección en modo por lotes.
Visión general
Los iteradores son potentes herramientas que le ayudan a iterar a través de un gran volumen de datos o de todos los datos de una colección utilizando valores de clave primaria y expresiones booleanas. Esto puede mejorar significativamente la forma de recuperar datos. A diferencia del uso tradicional de parámetros de desplazamiento y límite, que pueden perder eficacia con el tiempo, los iteradores ofrecen una solución más escalable.
Ventajas del uso de iteradores
Simplicidad: Elimina los complejos parámetros offset y limit.
Eficacia: Proporciona una recuperación de datos escalable al obtener sólo los datos necesarios.
Coherencia: Garantiza un tamaño coherente del conjunto de datos con filtros booleanos.
notas
- Esta función está disponible para Milvus 2.3.x o posterior.
Preparativos
Los siguientes pasos reutilizan el código para conectarse a Milvus, configurar rápidamente una colección e insertar más de 10.000 entidades generadas aleatoriamente en la colección.
Paso 1: Crear una colección
Utilice MilvusClient
para conectarse al servidor Milvus y create_collection()
para crear una colección.
Utilice MilvusClientV2
para conectarse al servidor Milvus y createCollection()
para crear una colección.
from pymilvus import MilvusClient
# 1. Set up a Milvus client
client = MilvusClient(
uri="http://localhost:19530"
)
# 2. Create a collection
client.create_collection(
collection_name="quick_setup",
dimension=5,
)
import io.milvus.client.MilvusServiceClient;
import io.milvus.param.ConnectParam;
import io.milvus.param.highlevel.collection.CreateSimpleCollectionParam;
String CLUSTER_ENDPOINT = "http://localhost:19530";
// 1. Connect to Milvus server
ConnectParam connectParam = ConnectParam.newBuilder()
.withUri(CLUSTER_ENDPOINT)
.build();
MilvusServiceClient client = new MilvusServiceClient(connectParam);
// 2. Create a collection
CreateSimpleCollectionParam createCollectionParam = CreateSimpleCollectionParam.newBuilder()
.withCollectionName("quick_setup")
.withDimension(5)
.build();
client.createCollection(createCollectionParam);
Paso 2: Insertar entidades generadas aleatoriamente
Utilice insert()
para insertar entidades en la colección.
Utilice insert()
para insertar entidades en la colección.
# 3. Insert randomly generated vectors
colors = ["green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey"]
data = []
for i in range(10000):
current_color = random.choice(colors)
current_tag = random.randint(1000, 9999)
data.append({
"id": i,
"vector": [ random.uniform(-1, 1) for _ in range(5) ],
"color": current_color,
"tag": current_tag,
"color_tag": f"{current_color}_{str(current_tag)}"
})
print(data[0])
# Output
#
# {
# "id": 0,
# "vector": [
# -0.5705990742218152,
# 0.39844925120642083,
# -0.8791287928610869,
# 0.024163154953680932,
# 0.6837669917169638
# ],
# "color": "purple",
# "tag": 7774,
# "color_tag": "purple_7774"
# }
res = client.insert(
collection_name="quick_setup",
data=data,
)
print(res)
# Output
#
# {
# "insert_count": 10000,
# "ids": [
# 0,
# 1,
# 2,
# 3,
# 4,
# 5,
# 6,
# 7,
# 8,
# 9,
# "(9990 more items hidden)"
# ]
# }
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import com.alibaba.fastjson.JSONObject;
import io.milvus.param.R;
import io.milvus.param.dml.InsertParam;
import io.milvus.response.MutationResultWrapper;
import io.milvus.grpc.MutationResult;
// 3. Insert randomly generated vectors into the collection
List<String> colors = Arrays.asList("green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey");
List<JSONObject> data = new ArrayList<>();
for (int i=0; i<10000; i++) {
Random rand = new Random();
String current_color = colors.get(rand.nextInt(colors.size()-1));
JSONObject row = new JSONObject();
row.put("id", Long.valueOf(i));
row.put("vector", Arrays.asList(rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat()));
row.put("color_tag", current_color + "_" + String.valueOf(rand.nextInt(8999) + 1000));
data.add(row);
}
InsertParam insertParam = InsertParam.newBuilder()
.withCollectionName("quick_setup")
.withRows(data)
.build();
R<MutationResult> insertRes = client.insert(insertParam);
if (insertRes.getStatus() != R.Status.Success.getCode()) {
System.err.println(insertRes.getMessage());
}
MutationResultWrapper wrapper = new MutationResultWrapper(insertRes.getData());
System.out.println(wrapper.getInsertCount());
Búsqueda con iterador
Los iteradores hacen que las búsquedas por similitud sean más escalables.
Para buscar con un iterador, llama al método search_iterator():
Para buscar con un iterador, llame al método searchIterator():
Inicialice el iterador de búsqueda para definir los parámetros de búsqueda y los campos de salida.
Utilice el método next() dentro de un bucle para paginar los resultados de la búsqueda.
Si el método devuelve un array vacío, el bucle finaliza y no hay más páginas disponibles.
Todos los resultados llevan los campos de salida especificados.
Llame manualmente al método close() para cerrar el iterador una vez que se hayan recuperado todos los datos.
from pymilvus import Collection
# 4. Search with iterator
connections.connect(host="127.0.0.1", port=19530)
collection = Collection("quick_setup")
query_vectors = [[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]]
search_params = {
"metric_type": "IP",
"params": {"nprobe": 10}
}
iterator = collection.search_iterator(
data=query_vectors,
anns_field="vector",
batch_size=10,
param=search_params,
output_fields=["color_tag"],
limit=3
)
results = []
while True:
result = iterator.next()
if not result:
iterator.close()
break
results.extend(result)
for hit in result:
results.append(hit.to_dict())
print(results)
# Output
#
# [
# {
# "id": 1756,
# "distance": 2.0642056465148926,
# "entity": {
# "color_tag": "black_9109"
# }
# },
# {
# "id": 6488,
# "distance": 1.9437453746795654,
# "entity": {
# "color_tag": "purple_8164"
# }
# },
# {
# "id": 3338,
# "distance": 1.9107104539871216,
# "entity": {
# "color_tag": "brown_8121"
# }
# }
# ]
import io.milvus.param.dml.QueryIteratorParam;
import io.milvus.param.dml.SearchIteratorParam;
import io.milvus.response.QueryResultsWrapper;
import io.milvus.orm.iterator.SearchIterator;
// 4. Search with iterators
SearchIteratorParam iteratorParam = SearchIteratorParam.newBuilder()
.withCollectionName("quick_setup")
.withVectorFieldName("vector")
// Use withFloatVectors() in clusters compatible with Milvus 2.4.x
.withVectors(Arrays.asList(0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f))
.withBatchSize(10L)
.withParams("{\"metric_type\": \"COSINE\", \"params\": {\"level\": 1}}")
.build();
R<SearchIterator> searchIteratorRes = client.searchIterator(iteratorParam);
if (searchIteratorRes.getStatus() != R.Status.Success.getCode()) {
System.err.println(searchIteratorRes.getMessage());
}
SearchIterator searchIterator = searchIteratorRes.getData();
List<QueryResultsWrapper.RowRecord> results = new ArrayList<>();
while (true) {
List<QueryResultsWrapper.RowRecord> batchResults = searchIterator.next();
if (batchResults.isEmpty()) {
searchIterator.close();
break;
}
for (QueryResultsWrapper.RowRecord rowRecord : batchResults) {
results.add(rowRecord);
}
}
System.out.println(results.size());
Parámetro | Descripción |
---|---|
data |
Una lista de incrustaciones vectoriales. Milvus busca las incrustaciones vectoriales más similares a las especificadas. |
anns_field |
El nombre del campo vectorial en la colección actual. |
batch_size |
El número de entidades a devolver cada vez que se llama a next() sobre el iterador actual.El valor por defecto es 1000. Ajústelo a un valor adecuado para controlar el número de entidades a devolver por iteración. |
param |
Los parámetros específicos de esta operación.
|
output_fields |
Una lista de nombres de campo para incluir en cada entidad devuelta. El valor por defecto es None. Si no se especifica, sólo se incluye el campo principal. |
limit |
El número total de entidades que se devolverán. El valor predeterminado es -1, lo que indica que se devolverán todas las entidades coincidentes. |
Parámetro | Descripción |
---|---|
withCollectionName |
Establece el nombre de la colección. El nombre de la colección no puede estar vacío ni ser nulo. |
withVectorFieldName |
Establezca el nombre del campo del vector de destino. El nombre del campo no puede estar vacío ni ser nulo. |
withVectors |
Defina los vectores de destino. Se permiten hasta 16384 vectores. |
withBatchSize |
El número de entidades a devolver cada vez que se llama a next() en el iterador actual.El valor por defecto es 1000. Establézcalo a un valor apropiado para controlar el número de entidades a devolver por iteración. |
withParams |
Especifica los parámetros de búsqueda en formato JSON. Para más información, consulte searchIterator(). |
Consulta con un iterador
Para consultar con un iterador, llame al método query_iterator():
Para buscar con un iterador, llame al método queryIterator():
# 6. Query with iterator
iterator = collection.query_iterator(
batch_size=10, # Controls the size of the return each time you call next()
expr="color_tag like \"brown_8\"",
output_fields=["color_tag"]
)
results = []
while True:
result = iterator.next()
if not result:
iterator.close()
break
results.extend(result)
# 8. Check the search results
print(len(results))
print(results[:3])
# Output
#
# [
# {
# "color_tag": "brown_8785",
# "id": 94
# },
# {
# "color_tag": "brown_8568",
# "id": 176
# },
# {
# "color_tag": "brown_8721",
# "id": 289
# }
# ]
import io.milvus.param.dml.QueryIteratorParam;
import io.milvus.orm.iterator.QueryIterator;
// 5. Query with iterators
try {
Files.write(Path.of("results.json"), JSON.toJSONString(new ArrayList<>()).getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
QueryIteratorParam queryIteratorParam = QueryIteratorParam.newBuilder()
.withCollectionName("quick_setup")
.withExpr("color_tag like \"brown_8%\"")
.withBatchSize(50L)
.addOutField("vector")
.addOutField("color_tag")
.build();
R<QueryIterator> queryIteratRes = client.queryIterator(queryIteratorParam);
if (queryIteratRes.getStatus() != R.Status.Success.getCode()) {
System.err.println(queryIteratRes.getMessage());
}
QueryIterator queryIterator = queryIteratRes.getData();
while (true) {
List<QueryResultsWrapper.RowRecord> batchResults = queryIterator.next();
if (batchResults.isEmpty()) {
queryIterator.close();
break;
}
String jsonString = "";
List<JSONObject> jsonObject = new ArrayList<>();
try {
jsonString = Files.readString(Path.of("results.json"));
jsonObject = JSON.parseArray(jsonString).toJavaList(null);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (QueryResultsWrapper.RowRecord queryResult : batchResults) {
JSONObject row = new JSONObject();
row.put("id", queryResult.get("id"));
row.put("vector", queryResult.get("vector"));
row.put("color_tag", queryResult.get("color_tag"));
jsonObject.add(row);
}
try {
Files.write(Path.of("results.json"), JSON.toJSONString(jsonObject).getBytes(), StandardOpenOption.WRITE);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Parámetro | Descripción |
---|---|
batch_size |
El número de entidades a devolver cada vez que se llama a next() en el iterador actual.El valor por defecto es 1000. Establézcalo a un valor apropiado para controlar el número de entidades a devolver por iteración. |
expr |
Una condición de filtrado escalar para filtrar las entidades coincidentes. El valor predeterminado es None, lo que indica que se ignora el filtrado escalar. Para crear una condición de filtrado escalar, consulte Reglas de expresión booleana. |
output_fields |
Una lista de nombres de campo para incluir en cada entidad devuelta. El valor por defecto es Ninguno. Si no se especifica, sólo se incluye el campo principal. |
limit |
El número total de entidades que se devolverán. El valor predeterminado es -1, lo que indica que se devolverán todas las entidades coincidentes. |
Parámetro | Descripción |
---|---|
withCollectionName |
Establece el nombre de la colección. El nombre de la colección no puede estar vacío ni ser nulo. |
withExpr |
Establezca la expresión para consultar las entidades. Para crear una condición de filtrado escalar, consulte Reglas de expresión booleana. |
withBatchSize |
El número de entidades a devolver cada vez que se llama a next() en el iterador actual.El valor por defecto es 1000. Establézcalo a un valor apropiado para controlar el número de entidades a devolver por iteración. |
addOutField |
Especifica un campo escalar de salida (Opcional). |