Utilizar campos de matriz
Esta guía explica cómo utilizar los campos de array, como insertar valores de array, crear índices en campos de vector y array, así como buscar y consultar en campos de array con operadores básicos y avanzados.
Requisitos previos
Asegúrese de tener lo siguiente:
- Milvus instalado y en ejecución. Para obtener información sobre cómo instalar Milvus, consulte Instalar Milvus.
- Uno de los SDK de Milvus instalado en su entorno. Para más detalles, consulte Instalar SDKs.
Preparar datos con un campo array
Milvus soporta arrays como uno de los tipos de datos de campo. Un array en una colección Milvus debe tener siempre elementos del mismo tipo de datos, y el tipo de datos para los elementos del array puede ser cualquiera de los tipos de datos soportados en Milvus. Para obtener una lista de los tipos de datos admitidos, consulte Tipos de datos admitidos.
El siguiente fragmento de código genera un conjunto de datos aleatorio que contiene un campo array llamado color_coord
, con todos los elementos del tipo de datos interger.
import random
colors = ["green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey"]
data = []
for i in range(1000):
current_color = random.choice(colors)
current_tag = random.randint(1000, 9999)
current_coord = [ random.randint(0, 40) for _ in range(random.randint(3, 5)) ]
data.append({
"id": i,
"vector": [ random.uniform(-1, 1) for _ in range(5) ],
"color": current_color,
"color_tag": current_tag,
"color_coord": current_coord,
})
print(data[0])
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<1000; i++) {
Random rand = new Random();
String current_color = colors.get(rand.nextInt(colors.size()-1));
Long current_tag = rand.nextLong(8999L) + 1000L;
// Generate an random-sized array
Long capacity = rand.nextLong(5L) + 1L;
List<Long> current_coord = new ArrayList<>();
current_coord.add(rand.nextLong(40L) + 1L);
current_coord.add(rand.nextLong(40L) + 1L);
for (int j=3; j<capacity; j++) {
current_coord.add(rand.nextLong(40L) + 1L);
}
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", current_color);
row.put("color_tag", current_tag);
row.put("color_coord", current_coord);
data.add(row);
}
System.out.println(JSONObject.toJSON(data.get(0)));
const colors = ["green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey"];
let data = [];
for (let i = 0; i < 1000; i++) {
const current_color = colors[Math.floor(Math.random() * colors.length)];
const current_tag = Math.floor(Math.random() * 8999 + 1000);
const current_coord = Array(Math.floor(Math.random() * 5 + 1)).fill(0).map(() => Math.floor(Math.random() * 40));
data.push({
id: i,
vector: Array(5).fill(0).map(() => Math.random()),
color: current_color,
color_tag: current_tag,
color_coord: current_coord,
});
}
console.log(data[0]);
Este fragmento de código prepara una lista de colores aleatorios y genera un conjunto de datos que contiene 1.000 entidades. Cada entidad tiene un ID, un vector de cinco números en coma flotante, un color, una etiqueta de color y un campo de matriz color_coord
que contiene entre 3 y 5 valores enteros. Los datos de muestra se imprimen para verificar su estructura.
Estructura de salida:
{
id: 0,
vector: [
0.0338537420906162,
0.6844108238358322,
0.28410588909961754,
0.09752595400212116,
0.22671013058761114
],
color: 'orange',
color_tag: 5677,
color_coord: [ 3, 0, 18, 29 ]
}
Configurar MilvusClient
Para interactuar con Milvus, configure el cliente Milvus especificando la dirección del servidor.
from pymilvus import MilvusClient, DataType
SERVER_ADDR = "http://localhost:19530"
client = MilvusClient(uri=SERVER_ADDR)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
String SERVER_ADDR = "http://localhost:19530";
// 1. Connect to Milvus server
ConnectConfig connectConfig = ConnectConfig.builder()
.uri(SERVER_ADDR)
.build();
MilvusClientV2 client = new MilvusClientV2(connectConfig);
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
// Connect to Milvus server
const address = "http://localhost:19530";
const milvusClient = new MilvusClient({address: address});
Crear una colección con un campo array
Definir el esquema de la colección
Un esquema define la estructura de la colección, incluidos los campos y sus tipos de datos. El siguiente ejemplo define un esquema de colección que coincide con los datos de ejemplo generados en la sección anterior.
Para configurar un campo de matriz en una colección:
- Establezca el
datatype
: Configúrelo comoDataType.ARRAY
. - Especifique el
element_type
: Elija el tipo de datos para los elementos del array. Los elementos de un campo de matriz deben tener todos el mismo tipo de datos. En este ejemplo, elelement_type
se configura comoDataType.INT64
. - Defina el
max_capacity
: Configure este parámetro para especificar el número máximo de elementos que puede contener el campo array.
- Defina el
dataType
: Configúrelo comoDataType.Array
. - Especifique el
elementType
: Elija el tipo de datos para los elementos del array. Los elementos de un campo de matriz deben tener todos el mismo tipo de datos. En este ejemplo, elelementType
se configura comoDataType.Int64
. - Defina el
maxCapacity
: Configure este parámetro para especificar el número máximo de elementos que puede contener el campo array.
- Defina el
data_type
: Configúrelo comoDataType.Array
. - Especifique el
element_type
: Elija el tipo de datos para los elementos del array. Los elementos de un campo de matriz deben tener todos el mismo tipo de datos. En este ejemplo, elelement_type
se configura comoDataType.Int64
. - Defina el
max_capacity
: Establezca este parámetro para especificar el número máximo de elementos que puede contener el campo de matriz.
El siguiente código de ejemplo define el esquema de la colección con un campo array color_coord
, con un máximo de 5 elementos y cada elemento del tipo de datos entero.
schema = client.create_schema(auto_id=False, enable_dynamic_field=False)
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5)
schema.add_field(field_name="color", datatype=DataType.VARCHAR, max_length=512)
schema.add_field(field_name="color_tag", datatype=DataType.INT64)
schema.add_field(field_name="color_coord", datatype=DataType.ARRAY, element_type=DataType.INT64, max_capacity=5)
// Create schema
CreateCollectionReq.CollectionSchema schema = client.createSchema();
// Add fields to schema
schema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.autoID(false)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("vector")
.dataType(DataType.FloatVector)
.dimension(5)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("color")
.dataType(DataType.VarChar)
.maxLength(512)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("color_tag")
.dataType(DataType.Int64)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("color_coord")
.dataType(DataType.Array)
.elementType(DataType.Int64)
.maxCapacity(5)
.build());
const fields = [
{
name: "id",
data_type: DataType.Int64,
is_primary_key: true,
auto_id: false
},
{
name: "vector",
data_type: DataType.FloatVector,
dim: 5
},
{
name: "color",
data_type: DataType.VarChar,
max_length: 512
},
{
name: "color_tag",
data_type: DataType.Int64,
},
{
name: "color_coord",
data_type: DataType.Array,
element_type: DataType.Int64,
max_capacity: 5
}
];
Para más información sobre métodos y parámetros, consulte create_schema y add_field.
Para más información sobre métodos y parámetros, consulte createSchema y addField.
Para más información sobre métodos y parámetros, consulta createCollection.
Crear la colección
A continuación, crea la colección utilizando el esquema definido.
client.create_collection(collection_name="test_collection", schema=schema)
client.list_collections()
# Output:
# ['test_collection']
CreateCollectionReq customizedSetupReq = CreateCollectionReq.builder()
.collectionName("test_collection")
.collectionSchema(schema)
.build();
client.createCollection(customizedSetupReq);
await client.createCollection({
collection_name: "test_collection",
fields: fields
});
const res = await client.listCollections({collection_name: "test_collection"});
console.log("Existing collections: " + res.collection_names);
// Output:
// Existing collections: test_collection
Para más información sobre métodos y parámetros, consulte create_collection y list_collections.
Para más información sobre métodos y parámetros, consulte createCollection.
Para más información sobre métodos y parámetros, consulta createCollection y listCollections.
Crear índices
Los índices mejoran el rendimiento de las operaciones de búsqueda y consulta. En Milvus, puede crear índices tanto en campos vectoriales como en campos escalares. En este ejemplo, crearemos un índice IVF_FLAT
en el campo vectorial vector
y un índice INVERTED
en el campo escalar color_coord
. Para más información sobre índices, consulta Indexar campos vectoriales e Indexar campos escalares.
Campo vectorial indexado
La creación de un índice en un campo vectorial puede mejorar el rendimiento de la búsqueda de similitud vectorial, que es necesaria para cada operación de búsqueda.
El siguiente ejemplo crea un índice de tipo IVF_FLAT
en el campo vectorial vector
.
index_params = client.prepare_index_params()
index_params.add_index(
field_name="vector",
metric_type="COSINE",
index_type="IVF_FLAT",
index_name="vector_index",
params={"nlist": 128}
)
client.create_index(collection_name="test_collection", index_params=index_params)
client.describe_index(collection_name="test_collection", index_name="vector_index")
# Output:
# {'nlist': '128',
# 'index_type': 'IVF_FLAT',
# 'metric_type': 'COSINE',
# 'field_name': 'vector',
# 'index_name': 'vector_index'}
IndexParam indexParam = IndexParam.builder()
.metricType(IndexParam.MetricType.COSINE)
.indexType(IndexParam.IndexType.IVF_FLAT)
.fieldName("vector")
.indexName("vector_index")
.build();
CreateIndexReq createIndexReq = CreateIndexReq.builder()
.collectionName("test_collection")
.indexParams(Collections.singletonList(indexParam))
.build();
client.createIndex(createIndexReq);
await client.createIndex({
collection_name: "test_collection",
field_name: "vector",
index_type: "IVF_FLAT",
metric_type: "COSINE",
index_name: "vector_index",
params: { "nlist": 128 }
});
res = await client.describeIndex({
collection_name: "test_collection",
index_name: "vector_index"
});
console.log("Vector index description: " + JSON.stringify(res));
// Output:
// Vector index description: {"index_descriptions":[{"params":[{"key":"params","value":"{\"nlist\":128}"},{"key":"index_type","value":"IVF_FLAT"},{"key":"metric_type","value":"COSINE"}],"index_name":"vector_index","indexID":"451543183233666062","field_name":"vector","indexed_rows":"0","total_rows":"0","state":"Finished","index_state_fail_reason":"","pending_index_rows":"0"}],"status":{"extra_info":{},"error_code":"Success","reason":"","code":0,"retriable":false,"detail":""}}
Para obtener más información sobre métodos y parámetros, consulte prepare_index_params, create_index y describe_index.
Para más información sobre métodos y parámetros, consulte IndexParam y createIndex.
Para obtener más información sobre métodos y parámetros, consulta createIndex y describeIndex.
Campo escalar de índice
La creación de un índice en un campo escalar puede mejorar el rendimiento de recuperación de las consultas en ese campo, lo cual es opcional pero recomendable para grandes conjuntos de datos.
En este ejemplo, crearemos un índice invertido en el campo de matriz color_coord
. Esto nos permitirá acelerar el filtrado basado en este campo. El índice invertido muestra un rendimiento general excelente, superando significativamente al filtrado por fuerza bruta que utiliza datos sin procesar cuando los datos no se recuperan con frecuencia, y manteniendo un rendimiento comparable con operaciones de recuperación frecuentes. Para obtener más información sobre los índices invertidos, consulte Índice escalar.
index_params = client.prepare_index_params()
index_params.add_index(
field_name="color_coord",
index_type="INVERTED",
index_name="inverted_index"
)
client.create_index(collection_name="test_collection", index_params=index_params)
client.describe_index(collection_name="test_collection", index_name="inverted_index")
# Output:
# {'index_type': 'INVERTED',
# 'field_name': 'color_coord',
# 'index_name': 'inverted_index'}
IndexParam indexParam = IndexParam.builder()
.indexType(IndexParam.IndexType.INVERTED)
.fieldName("color_coord")
.indexName("inverted_index")
.build();
CreateIndexReq createIndexReq = CreateIndexReq.builder()
.collectionName("test_collection")
.indexParams(Collections.singletonList(indexParam))
.build();
client.createIndex(createIndexReq);
await client.createIndex({
collection_name: "test_collection",
field_name: "color_coord",
index_type: "INVERTED",
index_name: "inverted_index"
});
res = await client.describeIndex({
collection_name: "test_collection",
index_name: "inverted_index"
});
console.log("Array index description: " + JSON.stringify(res));
// Output:
// Array index description: {"index_descriptions":[{"params":[{"key":"index_type","value":"INVERTED"}],"index_name":"inverted_index","indexID":"451543183233667243","field_name":"color_coord","indexed_rows":"0","total_rows":"0","state":"Finished","index_state_fail_reason":"","pending_index_rows":"0"}],"status":{"extra_info":{},"error_code":"Success","reason":"","code":0,"retriable":false,"detail":""}}
Para obtener más información sobre métodos y parámetros, consulte prepare_index_params, create_index y describe_index.
Para obtener más información sobre métodos y parámetros, consulte IndexParam y createIndex.
Para más información sobre métodos y parámetros, consulta createIndex y describeIndex.
Insertar datos
Una vez creados la colección y los índices, podemos insertar los datos en la colección. Este paso inserta 1.000 entidades en test_collection
.
res = client.insert(collection_name="test_collection", data=data)
print(res)
# Output:
# {'insert_count': 1000, 'ids': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999], 'cost': 0}
InsertReq insertReq = InsertReq.builder()
.collectionName("test_collection")
.data(data)
.build();
InsertResp insertResp = client.insert(insertReq);
res = await client.insert({
collection_name: "test_collection",
data: data
});
console.log(`Inserted ${res.insert_cnt} entities`);
// Output:
// Inserted 1000 entities
Cargar la colección
Después de insertar los datos, tenemos que cargar la colección para que esté disponible para las operaciones de búsqueda y consulta.
client.load_collection('test_collection')
LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
.collectionName("test_collection")
.build();
client.loadCollection(loadCollectionReq);
await client.loadCollection({
collection_name: "test_collection"
});
res = await client.getLoadState({
collection_name: "test_collection"
});
console.log("Collection load state: " + res.state);
// Output:
// Collection load state: LoadStateLoaded
Filtrado escalar básico
Una vez añadidos todos los datos, puede realizar búsquedas y consultas utilizando los elementos del campo de matriz del mismo modo que lo haría con un campo escalar estándar.
Para obtener más información sobre los parámetros, consulte search()
en la referencia del SDK.
Para obtener más información sobre los parámetros, consulte search()
en la referencia del SDK.
Para obtener más información sobre los parámetros, consulte search()
en la referencia del SDK.
# 4. Basic search with the array field
query_vectors = [ [ random.uniform(-1, 1) for _ in range(5) ]]
res = client.search(
collection_name="test_collection",
data=query_vectors,
filter="color_coord[0] < 10",
search_params={
"metric_type": "COSINE",
"params": {"nprobe": 16}
},
output_fields=["id", "color", "color_tag", "color_coord"],
limit=3
)
print(res)
# Output:
# data: ["[{'id': 918, 'distance': 0.974249541759491, 'entity': {'color_coord': [4, 34, 9, 18, 29], 'id': 918, 'color': 'purple', 'color_tag': 2940}}, {'id': 822, 'distance': 0.9177230000495911, 'entity': {'color_coord': [7, 36, 32], 'id': 822, 'color': 'red', 'color_tag': 8519}}, {'id': 981, 'distance': 0.9116519689559937, 'entity': {'color_coord': [7, 16, 40, 32, 32], 'id': 981, 'color': 'pink', 'color_tag': 2992}}]"] , extra_info: {'cost': 0}
// 4. Basic search with an Array field
QueryReq queryReq = QueryReq.builder()
.collectionName("test_collection")
.filter("color_coord[0] in [7, 8, 9]")
.outputFields(Arrays.asList("id", "color", "color_tag", "color_coord"))
.limit(3L)
.build();
QueryResp queryResp = client.query(queryReq);
System.out.println(JSONObject.toJSON(queryResp));
// Output:
// {"queryResults": [
// {"entity": {
// "color": "orange",
// "color_tag": 2464,
// "id": 18,
// "color_coord": [
// 9,
// 30
// ]
// }},
// {"entity": {
// "color": "pink",
// "color_tag": 2602,
// "id": 22,
// "color_coord": [
// 8,
// 34,
// 16
// ]
// }},
// {"entity": {
// "color": "pink",
// "color_tag": 1243,
// "id": 42,
// "color_coord": [
// 9,
// 20
// ]
// }}
// ]}
const query_vectors = [Array(5).fill(0).map(() => Math.random())];
res = await client.search({
collection_name: "test_collection",
data: query_vectors,
filter: "color_coord[0] < 10",
output_fields: ["id", "color", "color_tag", "color_coord"],
limit: 3,
metric_type: "COSINE"
});
console.log("Search result: " + JSON.stringify(res));
// Output:
// Search result: [
// {
// "score": 0.9969238042831421,
// "id": "212",
// "color": "green",
// "color_tag": "5603",
// "color_coord": [
// "9",
// "14",
// "22",
// "4",
// "35"
// ]
// },
// {
// "score": 0.9952742457389832,
// "id": "339",
// "color": "yellow",
// "color_tag": "8867",
// "color_coord": [
// "8",
// "0",
// "6",
// "19",
// "23"
// ]
// },
// {
// "score": 0.9944050312042236,
// "id": "24",
// "color": "red",
// "color_tag": "7686",
// "color_coord": [
// "6",
// "17",
// "6",
// "32"
// ]
// }
// ]
Filtrado avanzado
Como lo que tenemos en un campo JSON, Milvus también proporciona operadores avanzados de filtrado para arrays, a saber ARRAY_CONTAINS
, ARRAY_CONTAINS_ALL
, ARRAY_CONTAINS_ANY
, y ARRAY_LENGTH
. Para más información sobre los operadores, consulte Referencia sobre filtros de matrices.
Filtra todas las entidades que tienen un
10
en sus valorescolor_coord
.# 5. Advanced query within the array field res = client.query( collection_name="test_collection", filter="ARRAY_CONTAINS(color_coord, 10)", output_fields=["id", "color", "color_tag", "color_coord"], limit=3 ) print(res) # Output: # data: ["{'id': 2, 'color': 'green', 'color_tag': 3676, 'color_coord': [26, 37, 30, 10]}", "{'id': 28, 'color': 'red', 'color_tag': 4735, 'color_coord': [30, 10, 40, 34]}", "{'id': 32, 'color': 'green', 'color_tag': 8816, 'color_coord': [10, 9, 24, 39]}"] , extra_info: {'cost': 0}
// 5. Advanced query within an Array field queryReq = QueryReq.builder() .collectionName("test_collection") .filter("ARRAY_CONTAINS(color_coord, 10)") .outputFields(Arrays.asList("id", "color", "color_tag", "color_coord")) .limit(3) .build(); queryResp = client.query(queryReq); System.out.println(JSONObject.toJSON(queryResp)); // Output: // {"queryResults": [ // {"entity": { // "color": "blue", // "color_tag": 4337, // "id": 17, // "color_coord": [ // 11, // 33, // 10, // 20 // ] // }}, // {"entity": { // "color": "white", // "color_tag": 5219, // "id": 25, // "color_coord": [ // 10, // 15 // ] // }}, // {"entity": { // "color": "red", // "color_tag": 7120, // "id": 35, // "color_coord": [ // 19, // 10, // 10, // 14 // ] // }} // ]}
// 5. Advanced search within the array field res = await client.search({ collection_name: "test_collection", data: query_vectors, filter: "ARRAY_CONTAINS(color_coord, 10)", output_fields: ["id", "color", "color_tag", "color_coord"], limit: 3 }) console.log(JSON.stringify(res.results, null, 4)) // Output // // [ // { // "score": 1.7962548732757568, // "id": "696", // "color": "red", // "color_tag": "1798", // "color_coord": [ // "33", // "10", // "37" // ] // }, // { // "score": 1.7126177549362183, // "id": "770", // "color": "red", // "color_tag": "1962", // "color_coord": [ // "21", // "23", // "10" // ] // }, // { // "score": 1.6707111597061157, // "id": "981", // "color": "yellow", // "color_tag": "3100", // "color_coord": [ // "28", // "39", // "10", // "6" // ] // } // ] //
Filtra todas las entidades que tienen un
7
y un8
en sus valorescolor_coord
.res = client.query( collection_name="test_collection", filter="ARRAY_CONTAINS_ALL(color_coord, [7, 8])", output_fields=["id", "color", "color_tag", "color_coord"], limit=3 ) print(res) # Output: # data: ["{'id': 147, 'color': 'brown', 'color_tag': 1287, 'color_coord': [7, 8, 11, 0]}", "{'id': 257, 'color': 'white', 'color_tag': 3641, 'color_coord': [2, 8, 31, 7]}", "{'id': 280, 'color': 'orange', 'color_tag': 1072, 'color_coord': [22, 7, 8]}"] , extra_info: {'cost': 0}
queryReq = QueryReq.builder() .collectionName("test_collection") .filter("ARRAY_CONTAINS_ALL(color_coord, [7, 8, 9])") .outputFields(Arrays.asList("id", "color", "color_tag", "color_coord")) .limit(3) .build(); queryResp = client.query(queryReq); System.out.println(JSONObject.toJSON(queryResp)); // Output: // {"queryResults": [{"entity": { // "color": "red", // "color_tag": 6986, // "id": 423, // "color_coord": [ // 26, // 7, // 8, // 9 // ] // }}]}
res = await client.search({ collection_name: "test_collection", data: query_vectors, filter: "ARRAY_CONTAINS_ALL(color_coord, [7, 8])", output_fields: ["id", "color", "color_tag", "color_coord"], limit: 3 }) console.log(JSON.stringify(res.results, null, 4)) // Output // // [ // { // "score": 0.8267516493797302, // "id": "913", // "color": "brown", // "color_tag": "8897", // "color_coord": [ // "39", // "31", // "8", // "29", // "7" // ] // }, // { // "score": 0.6889009475708008, // "id": "826", // "color": "blue", // "color_tag": "4903", // "color_coord": [ // "7", // "25", // "5", // "12", // "8" // ] // }, // { // "score": 0.5851659774780273, // "id": "167", // "color": "blue", // "color_tag": "1550", // "color_coord": [ // "8", // "27", // "7" // ] // } // ] //
Filtra todas las entidades que tienen 7, 8 o 9 en sus valores
color_coord
.res = client.query( collection_name="test_collection", filter="ARRAY_CONTAINS_ANY(color_coord, [7, 8, 9])", output_fields=["id", "color", "color_tag", "color_coord"], limit=3 ) print(res) # Output: # data: ["{'id': 0, 'color': 'white', 'color_tag': 2081, 'color_coord': [16, 7, 35, 5, 25]}", "{'id': 1, 'color': 'purple', 'color_tag': 4669, 'color_coord': [11, 9, 15, 38, 21]}", "{'id': 3, 'color': 'yellow', 'color_tag': 2612, 'color_coord': [0, 12, 22, 7]}"] , extra_info: {'cost': 0}
queryReq = QueryReq.builder() .collectionName("test_collection") .filter("ARRAY_CONTAINS_ANY(color_coord, [7, 8, 9])") .outputFields(Arrays.asList("id", "color", "color_tag", "color_coord")) .limit(3) .build(); queryResp = client.query(queryReq); System.out.println(JSONObject.toJSON(queryResp)); // Output: // {"queryResults": [ // {"entity": { // "color": "orange", // "color_tag": 2464, // "id": 18, // "color_coord": [ // 9, // 30 // ] // }}, // {"entity": { // "color": "pink", // "color_tag": 2602, // "id": 22, // "color_coord": [ // 8, // 34, // 16 // ] // }}, // {"entity": { // "color": "pink", // "color_tag": 1243, // "id": 42, // "color_coord": [ // 9, // 20 // ] // }} // ]}
res = await client.search({ collection_name: "test_collection", data: query_vectors, filter: "ARRAY_CONTAINS_ANY(color_coord, [7, 8, 9])", output_fields: ["id", "color", "color_tag", "color_coord"], limit: 3 }) console.log(JSON.stringify(res.results, null, 4)) // Output // // [ // { // "score": 2.015894889831543, // "id": "260", // "color": "green", // "color_tag": "5320", // "color_coord": [ // "1", // "7", // "33", // "13", // "23" // ] // }, // { // "score": 1.783075213432312, // "id": "593", // "color": "orange", // "color_tag": "4079", // "color_coord": [ // "8", // "19" // ] // }, // { // "score": 1.7713876962661743, // "id": "874", // "color": "blue", // "color_tag": "7029", // "color_coord": [ // "14", // "8", // "15" // ] // } // ] //
Filtra las entidades que tienen exactamente cuatro elementos.
res = client.query( collection_name="test_collection", filter="ARRAY_LENGTH(color_coord) == 4", output_fields=["id", "color", "color_tag", "color_coord"], limit=3 ) print(res) # Output: # data: ["{'id': 2, 'color': 'green', 'color_tag': 3676, 'color_coord': [26, 37, 30, 10]}", "{'id': 3, 'color': 'yellow', 'color_tag': 2612, 'color_coord': [0, 12, 22, 7]}", "{'id': 4, 'color': 'green', 'color_tag': 6912, 'color_coord': [4, 5, 19, 28]}"] , extra_info: {'cost': 0}
queryReq = QueryReq.builder() .collectionName("test_collection") .filter("ARRAY_LENGTH(color_coord) == 4") .outputFields(Arrays.asList("id", "color", "color_tag", "color_coord")) .limit(3) .build(); queryResp = client.query(queryReq); System.out.println(JSONObject.toJSON(queryResp)); // Output: // {"queryResults": [ // {"entity": { // "color": "green", // "color_tag": 2984, // "id": 2, // "color_coord": [ // 27, // 31, // 23, // 29 // ] // }}, // {"entity": { // "color": "black", // "color_tag": 6867, // "id": 4, // "color_coord": [ // 37, // 3, // 30, // 33 // ] // }}, // {"entity": { // "color": "brown", // "color_tag": 3464, // "id": 10, // "color_coord": [ // 31, // 38, // 21, // 28 // ] // }} // ]}
res = await client.search({ collection_name: "test_collection", data: query_vectors, filter: "ARRAY_LENGTH(color_coord) == 4", output_fields: ["id", "color", "color_tag", "color_coord"], limit: 3 }) console.log(JSON.stringify(res.results, null, 4)) // Output // // [ // { // "score": 2.0404388904571533, // "id": "439", // "color": "orange", // "color_tag": "7096", // "color_coord": [ // "27", // "34", // "26", // "39" // ] // }, // { // "score": 1.9059759378433228, // "id": "918", // "color": "purple", // "color_tag": "2903", // "color_coord": [ // "28", // "19", // "36", // "35" // ] // }, // { // "score": 1.8385567665100098, // "id": "92", // "color": "yellow", // "color_tag": "4693", // "color_coord": [ // "1", // "23", // "2", // "3" // ] // } // ] //
Límites
Los elementos de un campo ARRAY deben ser del mismo tipo de datos, especificado en
element_type
. Cualquier tipo de datos válido disponible para campos escalares en Milvus puede utilizarse comoelement_type
. Para obtener una lista de los tipos de datos admitidos, consulte Tipos de datos admitidos.El número de elementos de un campo ARRAY debe ser menor o igual que la capacidad máxima del campo array, especificada por
max_capacity
.
Referencia sobre filtros de matrices
Cuando trabaje con campos array, puede encerrar un valor de cadena entre comillas dobles ("") o simples (''). Es importante tener en cuenta que Milvus almacena los valores de cadena en el campo de matriz tal cual, sin realizar escapes semánticos ni conversiones. Por ejemplo, 'a " b ', "a'b", 'a'b' y "a "b" se guardarán tal cual, mientras que 'a'b' y "a "b" se tratarán como valores no válidos.
Supongamos que se han definido dos campos de matriz int_array
y var_array
. En la siguiente tabla se describen las expresiones booleanas admitidas que se pueden utilizar en expr
al realizar búsquedas con campos de matriz.
Operador | Ejemplos | Observaciones |
---|---|---|
< | ‘int_array[0] < 3’ | Esta expresión se evalúa como verdadero si el valor de int_array[0] es menor que 3. |
> | ‘int_array[0] > 5’ | Esta expresión es verdadera si el valor de int_array[0] es mayor que 5. |
== | ‘int_array[0] == 0’ | Esta expresión es verdadera si el valor de int_array[0] es igual a 0. |
!= | ‘var_array[0] != "a"’ | Esta expresión es verdadera si el valor de var_array[0] no es igual a “a” . |
<= | ‘int_array[0] <= 3’ | Esta expresión es verdadera si el valor de int_array[0] es menor o igual que 3. |
>= | ‘int_array[0] >= 10’ | Esta expresión es verdadera si el valor de int_array[0] es mayor o igual que 10. |
en | 'var_array[0] in ["str1", “str2”]' | Esta expresión es verdadera si el valor de var_array[0] es “str1” o “str2” . |
no en | 'int_array[0] not in [1, 2, 3]' | Esta expresión es verdadera si el valor de int_array[0] no es 1, 2 ó 3. |
+, -, *, /, %, ** | ‘int_array[0] + 100 > 200’ | Esta expresión es verdadera si el valor de int_array[0] + 100 es mayor que 200. |
como (LIKE) | ‘var_array[0] like "prefix%"’ | Esta expresión es verdadera si el valor de var_array[0] tiene como prefijo “prefix” . |
y (&&) | ‘var_array[0] like “prefix%” && int_array[0] <= 100’ | Esta expresión es verdadera si el valor de var_array[0] tiene como prefijo “prefix” y el valor de int_array[0] es menor o igual que 100. |
o (||) | ‘var_array[0] like “prefix%” || int_array[0] <= 100’ | Esta expresión se evalúa como verdadera si el valor de var_array[0] tiene como prefijo “prefix” , o el valor de int_array[0] es menor o igual que 100. |
array_contains (ARRAY_CONTAINS) | 'array_contains(int_array, 100)' | Esta expresión se evalúa como verdadero si int_array contiene el elemento 100 . |
array_contains_all (ARRAY_CONTAINS_ALL) | 'array_contains_all(int_array, [1, 2, 3])' | Esta expresión es verdadera si int_array contiene todos los elementos 1 , 2 , y 3 . |
array_contains_any (ARRAY_CONTAINS_ANY) | 'array_contains_any(var_array, ["a", "b", “c”])' | Esta expresión se evalúa como verdadera si var_array contiene cualquier elemento de “a” , “b” , y “c” . |
longitud_de_array | ‘array_length(int_array) == 10’ | Esta expresión es verdadera si int_array contiene exactamente 10 elementos. |