Utilizzare i campi array
Questa guida spiega come utilizzare i campi array, ad esempio inserendo valori di array, creando indici su campi vettoriali e array, nonché eseguendo ricerche e query nei campi array con operatori di base e avanzati.
Prerequisiti
Assicurarsi di disporre di quanto segue:
- Milvus sia installato e funzionante. Per informazioni su come installare Milvus, consultare la sezione Installazione di Milvus.
- Uno degli SDK di Milvus installato nel vostro ambiente. Per i dettagli, consultare la sezione Installazione degli SDK.
Preparare i dati con un campo array
Milvus supporta gli array come uno dei tipi di dati del campo. Un array in una collezione Milvus deve sempre avere elementi dello stesso tipo di dati e il tipo di dati per gli elementi dell'array può essere uno qualsiasi dei tipi di dati supportati in Milvus. Per un elenco dei tipi di dati supportati, consultare la sezione Tipi di dati supportati.
Il seguente frammento di codice genera un set di dati casuale contenente un campo array denominato color_coord
, con tutti gli elementi di tipo 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]);
Questo frammento di codice prepara un elenco di colori casuali e genera un set di dati contenente 1.000 entità. Ogni entità ha un ID, un vettore di cinque numeri in virgola mobile, un colore, un tag colore e un campo array color_coord
contenente da 3 a 5 valori interi. I dati di esempio vengono stampati per verificarne la struttura.
Struttura dell'output:
{
id: 0,
vector: [
0.0338537420906162,
0.6844108238358322,
0.28410588909961754,
0.09752595400212116,
0.22671013058761114
],
color: 'orange',
color_tag: 5677,
color_coord: [ 3, 0, 18, 29 ]
}
Configurazione di MilvusClient
Per interagire con Milvus, impostare il client Milvus specificando l'indirizzo del server.
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});
Creare una collezione con un campo array
Definire lo schema dell'insieme
Uno schema definisce la struttura dell'insieme, compresi i campi e i loro tipi di dati. L'esempio seguente definisce uno schema di raccolta che corrisponde ai dati di esempio generati nella sezione precedente.
Per configurare un campo array in una raccolta:
- Impostare il campo
datatype
: Configurarlo comeDataType.ARRAY
. - Specificare
element_type
: Scegliere il tipo di dati per gli elementi della matrice. Gli elementi di una matrice devono avere tutti lo stesso tipo di dati. In questo esempio,element_type
è impostato suDataType.INT64
. - Definire il parametro
max_capacity
: Impostare questo parametro per specificare il numero massimo di elementi che il campo matrice può contenere.
- Impostare il parametro
dataType
: configurarlo comeDataType.Array
. - Specificare
elementType
: scegliere il tipo di dati per gli elementi della matrice. Gli elementi di una matrice devono avere tutti lo stesso tipo di dati. In questo esempio,elementType
è impostato suDataType.Int64
. - Definire il parametro
maxCapacity
: Impostare questo parametro per specificare il numero massimo di elementi che il campo matrice può contenere.
- Impostare il parametro
data_type
: configurarlo comeDataType.Array
. - Specificare
element_type
: scegliere il tipo di dati per gli elementi della matrice. Gli elementi di una matrice devono avere tutti lo stesso tipo di dati. In questo esempio,element_type
è impostato suDataType.Int64
. - Definire
max_capacity
: impostare questo parametro per specificare il numero massimo di elementi che il campo della matrice può contenere.
L'esempio di codice seguente definisce lo schema della collezione con un campo array color_coord
, con un massimo di 5 elementi e ogni elemento di tipo intero.
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
}
];
Per ulteriori informazioni sui metodi e sui parametri, fare riferimento a create_schema e add_field.
Per ulteriori informazioni sui metodi e i parametri, fare riferimento a createSchema e addField.
Per ulteriori informazioni sui metodi e i parametri, consultare createCollection.
Creare la collezione
Quindi, creare la collezione utilizzando lo schema definito.
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
Per ulteriori informazioni sui metodi e sui parametri, consultare create_collection e list_collections.
Per ulteriori informazioni sui metodi e i parametri, fare riferimento a createCollection.
Per ulteriori informazioni sui metodi e i parametri, fare riferimento a createCollection e listCollections.
Creare indici
Gli indici migliorano le prestazioni delle operazioni di ricerca e di interrogazione. In Milvus è possibile creare indici sia su campi vettoriali che su campi scalari. In questo esempio, creeremo un indice IVF_FLAT
sul campo vettoriale vector
e un indice INVERTED
sul campo scalare color_coord
. Per ulteriori informazioni sugli indici, consultare le sezioni Indicizzazione dei campi vettoriali e Indicizzazione dei campi scalari.
Indice di un campo vettoriale
La creazione di un indice su un campo vettoriale può migliorare le prestazioni della ricerca per similarità vettoriale, necessaria per ogni operazione di ricerca.
L'esempio seguente crea un indice di tipo IVF_FLAT
sul campo vettoriale 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":""}}
Per ulteriori informazioni sui metodi e sui parametri, fare riferimento a prepare_index_params, create_index e describe_index.
Per ulteriori informazioni sui metodi e i parametri, consultare IndexParam e createIndex.
Per ulteriori informazioni sui metodi e i parametri, fare riferimento a createIndex e describeIndex.
Indice di un campo scalare
La creazione di un indice su un campo scalare può migliorare le prestazioni di recupero delle query su quel campo; si tratta di un'operazione facoltativa, ma consigliata per gli insiemi di dati di grandi dimensioni.
In questo esempio, creeremo un indice invertito sul campo array color_coord
. Questo ci permetterà di velocizzare il filtraggio basato su questo campo. L'indice invertito dimostra prestazioni complessive eccellenti, superando in modo significativo il filtraggio a forza bruta utilizzando i dati grezzi quando i dati non vengono recuperati frequentemente e mantenendo prestazioni comparabili con operazioni di recupero frequenti. Per ulteriori informazioni sugli indici invertiti, consultare Scalar Index.
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":""}}
Per ulteriori informazioni sui metodi e sui parametri, fare riferimento a prepare_index_params, create_index e describe_index.
Per ulteriori informazioni sui metodi e i parametri, consultare IndexParam e createIndex.
Per ulteriori informazioni sui metodi e i parametri, fare riferimento a createIndex e describeIndex.
Inserire i dati
Una volta creati l'insieme e gli indici, è possibile inserire i dati nell'insieme. Questo passo inserisce 1.000 entità in 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
Caricare l'insieme
Dopo aver inserito i dati, è necessario caricare l'insieme per renderlo disponibile per le operazioni di ricerca e di interrogazione.
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
Filtraggio scalare di base
Una volta aggiunti tutti i dati, è possibile effettuare ricerche e interrogazioni utilizzando gli elementi del campo array come si farebbe con un campo scalare standard.
Per ulteriori informazioni sui parametri, consultare la sezione search()
nel riferimento dell'SDK.
Per ulteriori informazioni sui parametri, fare riferimento a search()
nel riferimento al programma SDK.
Per ulteriori informazioni sui parametri, fare riferimento a search()
nel riferimento all'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"
// ]
// }
// ]
Filtraggio avanzato
Come per i campi JSON, Milvus fornisce anche operatori di filtraggio avanzato per gli array, ovvero ARRAY_CONTAINS
, ARRAY_CONTAINS_ALL
, ARRAY_CONTAINS_ANY
e ARRAY_LENGTH
. Per maggiori informazioni sugli operatori, consultare la sezione Riferimento ai filtri degli array.
Filtra tutte le entità che hanno un
10
nei loro valoricolor_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 tutte le entità che hanno un
7
e un8
nei loro valoricolor_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 tutte le entità che hanno 7, 8 o 9 nei loro valori
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 le entità che hanno esattamente quattro elementi.
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" // ] // } // ] //
Limiti
Gli elementi di un campo ARRAY devono essere dello stesso tipo di dati, specificato da
element_type
. Qualsiasi tipo di dati valido disponibile per i campi scalari in Milvus può essere usato comeelement_type
. Per un elenco dei tipi di dati supportati, consultare Tipi di dati supportati.Il numero di elementi in un campo ARRAY deve essere inferiore o uguale alla capacità massima del campo array, specificata da
max_capacity
.
Riferimento ai filtri di matrice
Quando si lavora con i campi array, è possibile racchiudere un valore stringa con virgolette doppie ("") o virgolette singole (''). È importante notare che Milvus memorizza i valori stringa nel campo array così come sono, senza eseguire l'escape semantico o la conversione. Ad esempio, "a "b", "a'b", "a'b" e "a "b" saranno salvati così come sono, mentre "a'b" e "a "b" saranno trattati come valori non validi.
Si supponga che siano stati definiti due campi array int_array
e var_array
. La tabella seguente descrive le espressioni booleane supportate che possono essere utilizzate in expr
per effettuare ricerche con i campi della matrice.
Operatore | Esempi | Osservazioni |
---|---|---|
< | ‘int_array[0] < 3’ | Questa espressione dà esito positivo se il valore di int_array[0] è inferiore a 3. |
> | ‘int_array[0] > 5’ | Questa espressione ha valore vero se il valore di int_array[0] è maggiore di 5. |
== | ‘int_array[0] == 0’ | Questa espressione è vera se il valore di int_array[0] è uguale a 0. |
!= | ‘var_array[0] != "a"’ | Questa espressione è vera se il valore di var_array[0] non è uguale a “a” . |
<= | ‘int_array[0] <= 3’ | Questa espressione ha valore vero se il valore di int_array[0] è minore o uguale a 3. |
>= | ‘int_array[0] >= 10’ | Questa espressione ha valore vero se il valore di int_array[0] è maggiore o uguale a 10. |
in | 'var_array[0] in ["str1", “str2”]' | Questa espressione ha valore vero se il valore di var_array[0] è “str1” o “str2” . |
non in | 'int_array[0] not in [1, 2, 3]' | Questa espressione dà esito positivo se il valore di int_array[0] non è 1, 2 o 3. |
+, -, *, /, %, ** | ‘int_array[0] + 100 > 200’ | Questa espressione dà esito positivo se il valore di int_array[0] + 100 è superiore a 200. |
come (LIKE) | ‘var_array[0] like "prefix%"’ | Questa espressione ha valore vero se il valore di var_array[0] è preceduto da “prefix” . |
e (&&) | ‘var_array[0] like “prefix%” && int_array[0] <= 100’ | Questa espressione ha valore vero se il valore di var_array[0] è preceduto da “prefix” e il valore di int_array[0] è minore o uguale a 100. |
o (||) | ‘var_array[0] like “prefix%” || int_array[0] <= 100’ | Questa espressione ha valore vero se il valore di var_array[0] è preceduto da “prefix” , o se il valore di int_array[0] è minore o uguale a 100. |
array_contains (ARRAY_CONTAINS) | 'array_contains(int_array, 100)' | Questa espressione dà esito positivo se int_array contiene l'elemento 100 . |
array_contains_all (ARRAY_CONTAINS_ALL) | 'array_contains_all(int_array, [1, 2, 3])' | Questa espressione dà come risultato vero che int_array contiene tutti gli elementi 1 , 2 e 3 . |
array_contains_any (ARRAY_CONTAINS_ANY) | 'array_contains_any(var_array, ["a", "b", “c”])' | Questa espressione dà come risultato vero che var_array contiene qualsiasi elemento di “a” , “b” e “c” . |
lunghezza_array | ‘array_length(int_array) == 10’ | Questa espressione ha valore vero se int_array contiene esattamente 10 elementi. |