Utilizar campos de matriz
Este guia explica como utilizar os campos de matriz, tais como a inserção de valores de matriz, a criação de índices em campos de vetor e matriz, bem como a pesquisa e consulta em campos de matriz com operadores básicos e avançados.
Pré-requisitos
Certifique-se de que tem o seguinte:
- Milvus instalado e em execução. Para obter informações sobre como instalar o Milvus, consulte Instalar o Milvus.
- Um dos SDKs do Milvus instalado no seu ambiente. Para obter detalhes, consulte Instalar SDKs.
Preparar dados com um campo de matriz
O Milvus suporta arrays como um dos tipos de dados de campo. Uma matriz numa coleção Milvus deve ter sempre elementos do mesmo tipo de dados, e o tipo de dados para os elementos da matriz pode ser qualquer um dos tipos de dados suportados em Milvus. Para obter uma lista dos tipos de dados suportados, consulte Tipos de dados suportados.
O seguinte trecho de código gera um conjunto de dados aleatório contendo um campo de matriz chamado color_coord
, com todos os elementos do tipo de dados 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 trecho de código prepara uma lista de cores aleatórias e gera um conjunto de dados contendo 1.000 entidades. Cada entidade tem um ID, um vetor de cinco números de vírgula flutuante, uma cor, uma etiqueta de cor e um campo de matriz color_coord
contendo entre 3 a 5 valores inteiros. Os dados de amostra são impressos para verificar a sua estrutura.
Estrutura de saída:
{
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 o MilvusClient
Para interagir com o Milvus, configure o cliente Milvus especificando o endereço do 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});
Criar uma coleção com um campo de matriz
Definir o esquema da coleção
Um esquema define a estrutura da coleção, incluindo os campos e os respectivos tipos de dados. O exemplo abaixo define um esquema de coleção que corresponde aos dados de amostra gerados na secção anterior.
Para configurar um campo de matriz numa coleção:
- Defina o
datatype
: Configure-o comoDataType.ARRAY
. - Especifique o
element_type
: Escolha o tipo de dados para os elementos da matriz. Os elementos de um campo de matriz devem ter todos o mesmo tipo de dados. Neste exemplo, oelement_type
é definido comoDataType.INT64
. - Definir o
max_capacity
: Defina este parâmetro para especificar o número máximo de elementos que o campo de matriz pode conter.
- Definir o
dataType
: Configure-o comoDataType.Array
. - Especificar o
elementType
: Escolha o tipo de dados para os elementos da matriz. Os elementos de um campo de matriz devem ter todos o mesmo tipo de dados. Neste exemplo, oelementType
é definido comoDataType.Int64
. - Definir o
maxCapacity
: Defina este parâmetro para especificar o número máximo de elementos que o campo de matriz pode conter.
- Definir o
data_type
: Configure-o comoDataType.Array
. - Especificar o
element_type
: Escolha o tipo de dados para os elementos da matriz. Os elementos de um campo de matriz devem ter todos o mesmo tipo de dados. Neste exemplo, oelement_type
é definido comoDataType.Int64
. - Defina o
max_capacity
: Defina este parâmetro para especificar o número máximo de elementos que o campo de matriz pode conter.
O código de exemplo abaixo define o esquema de coleção com um campo de matriz color_coord
, com um máximo de 5 elementos e cada elemento do tipo de dados integer.
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 obter mais informações sobre métodos e parâmetros, consulte create_schema e add_field.
Para mais informações sobre métodos e parâmetros, consulte createSchema e addField.
Para mais informações sobre métodos e parâmetros, consulte createCollection.
Criar a coleção
Em seguida, crie a coleção utilizando o 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 mais informações sobre os métodos e parâmetros, consultar create_collection e list_collections.
Para mais informações sobre métodos e parâmetros, consultar createCollection.
Para mais informações sobre métodos e parâmetros, consulte createCollection e listCollections.
Criar índices
Os índices melhoram o desempenho das operações de pesquisa e consulta. No Milvus, é possível criar índices em campos vectoriais e em campos escalares. Neste exemplo, vamos criar um índice IVF_FLAT
no campo de vetor vector
e um índice INVERTED
no campo de matriz color_coord
. Para obter mais informações sobre índices, consulte Indexar campos vectoriais e Indexar campos escalares.
Indexar campo vetorial
A criação de um índice num campo de vetor pode melhorar o desempenho da pesquisa de semelhança de vectores, que é necessária para cada operação de pesquisa.
O exemplo abaixo cria um índice do tipo IVF_FLAT
no campo de vetor 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 obter mais informações sobre métodos e parâmetros, consulte prepare_index_params, create_index e describe_index.
Para mais informações sobre métodos e parâmetros, consulte IndexParam e createIndex.
Para mais informações sobre métodos e parâmetros, consulte createIndex e describeIndex.
Campo de matriz de índices
A criação de um índice num campo escalar pode melhorar o desempenho da recuperação de consultas nesse campo, o que é opcional mas recomendado para grandes conjuntos de dados.
Neste exemplo, vamos criar um índice invertido no campo da matriz color_coord
. Isto permitir-nos-á acelerar a filtragem com base neste campo. O índice invertido demonstra um excelente desempenho geral, superando significativamente a filtragem de força bruta utilizando dados brutos quando os dados não são recuperados frequentemente e mantendo um desempenho comparável com operações de recuperação frequentes. Para obter mais informações sobre í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 obter mais informações sobre métodos e parâmetros, consulte prepare_index_params, create_index e describe_index.
Para mais informações sobre métodos e parâmetros, consulte IndexParam e createIndex.
Para mais informações sobre métodos e parâmetros, consulte createIndex e describeIndex.
Inserir dados
Assim que a coleção e os índices forem criados, podemos inserir os dados na coleção. Esta etapa insere 1.000 entidades no site 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
Carregar a coleção
Depois de inserir os dados, precisamos de carregar a coleção para a tornar disponível para operações de pesquisa e 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
Filtragem escalar básica
Depois de todos os dados terem sido adicionados, pode efetuar pesquisas e consultas utilizando os elementos do campo de matriz da mesma forma que faria com um campo escalar padrão.
Para mais informações sobre parâmetros, consulte search()
na referência do SDK.
Para obter mais informações sobre parâmetros, consulte search()
na referência do SDK.
Para obter mais informações sobre parâmetros, consulte search()
na referência do 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"
// ]
// }
// ]
Filtragem avançada
À semelhança do que acontece com um campo JSON, o Milvus também fornece operadores de filtragem avançados para arrays, nomeadamente ARRAY_CONTAINS
, ARRAY_CONTAINS_ALL
, ARRAY_CONTAINS_ANY
e ARRAY_LENGTH
. Para mais informações sobre os operadores, consulte a Referência sobre filtros de matrizes.
Filtra todas as entidades com um
10
nos seus 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 as entidades com um
7
e um8
nos seus 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 as entidades com 7, 8 ou 9 nos seus 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 entidades que têm exatamente quatro 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" // ] // } // ] //
Limites
Os elementos de um campo ARRAY devem ter o mesmo tipo de dados, especificado por
element_type
. Qualquer tipo de dados válido disponível para campos escalares em Milvus pode ser utilizado comoelement_type
. Para obter uma lista dos tipos de dados suportados, consulte Tipos de dados suportados.O número de elementos num campo ARRAY deve ser inferior ou igual à capacidade máxima do campo array, especificada em
max_capacity
.
Referência sobre filtros de matriz
Ao trabalhar com campos de matriz, pode colocar um valor de cadeia de caracteres entre aspas duplas ("") ou aspas simples (''). É importante notar que o Milvus armazena os valores das cadeias de caracteres no campo da matriz tal como estão, sem efetuar a fuga semântica ou a conversão. Por exemplo, 'a "b', "a'b", 'a'b' e "a "b" serão guardados tal como estão, enquanto que 'a'b' e "a "b" serão tratados como valores inválidos.
Suponha que foram definidos dois campos de matriz int_array
e var_array
. A tabela seguinte descreve as expressões booleanas suportadas que pode utilizar em expr
ao pesquisar com campos de matriz.
Operador | Exemplos | Observações |
---|---|---|
< | ‘int_array[0] < 3’ | Esta expressão é avaliada como verdadeira se o valor de int_array[0] for inferior a 3. |
> | ‘int_array[0] > 5’ | Essa expressão será avaliada como verdadeira se o valor de int_array[0] for maior que 5. |
== | ‘int_array[0] == 0’ | Esta expressão é avaliada como verdadeira se o valor de int_array[0] for igual a 0. |
!= | ‘var_array[0] != "a"’ | Esta expressão é avaliada como verdadeira se o valor de var_array[0] não for igual a “a” . |
<= | ‘int_array[0] <= 3’ | Esta expressão é avaliada como verdadeira se o valor de int_array[0] for menor ou igual a 3. |
>= | ‘int_array[0] >= 10’ | Esta expressão é avaliada como verdadeira se o valor de int_array[0] for maior ou igual a 10. |
em | 'var_array[0] in ["str1", “str2”]' | Esta expressão é avaliada como verdadeira se o valor de var_array[0] for “str1” ou “str2” . |
not in | 'int_array[0] not in [1, 2, 3]' | Esta expressão é avaliada como verdadeira se o valor de int_array[0] não for 1, 2 ou 3. |
+, -, *, /, %, ** | ‘int_array[0] + 100 > 200’ | Esta expressão é avaliada como verdadeira se o valor de int_array[0] + 100 for superior a 200. |
like (LIKE) | ‘var_array[0] like "prefix%"’ | Esta expressão é avaliada como verdadeira se o valor de var_array[0] for prefixado com “prefix” . |
and (&&) | ‘var_array[0] like “prefix%” && int_array[0] <= 100’ | Esta expressão é avaliada como verdadeira se o valor de var_array[0] for prefixado com “prefix” , e o valor de int_array[0] for menor ou igual a 100. |
or (||) | ‘var_array[0] like “prefix%” || int_array[0] <= 100’ | Esta expressão é avaliada como verdadeira se o valor de var_array[0] for prefixado com “prefix” , ou se o valor de int_array[0] for menor ou igual a 100. |
array_contains (ARRAY_CONTAINS) | 'array_contains(int_array, 100)' | Esta expressão é avaliada como verdadeira se int_array contiver o elemento 100 . |
array_contains_all (ARRAY_CONTAINS_ALL) | 'array_contains_all(int_array, [1, 2, 3])' | Esta expressão é avaliada como verdadeira se int_array contiver todos os elementos 1 , 2 , e 3 . |
array_contains_any (ARRAY_CONTAINS_ANY) | 'array_contains_any(var_array, ["a", "b", “c”])' | Esta expressão é avaliada como verdadeira se var_array contiver qualquer elemento de “a” , “b” , e “c” . |
array_length | ‘array_length(int_array) == 10’ | Esta expressão é avaliada como verdadeira se int_array contiver exatamente 10 elementos. |