milvus-logo
LFAI
Home
  • Guide de l'utilisateur

Activer le champ dynamique

Cette page explique comment utiliser le champ dynamique dans une collection pour une insertion et une extraction flexibles des données.

Vue d'ensemble

Milvus vous permet de définir le schéma d'une collection en définissant le nom et le type de données de chaque champ spécifique afin que vous puissiez créer des index dans ces champs pour améliorer les performances de recherche.

Une fois qu'un champ est défini, vous devez l'inclure lorsque vous insérez des données. Que faire si certains champs ne sont pas toujours présents dans toutes vos entrées de données ? C'est là qu'intervient le champ dynamique.

Le champ dynamique d'une collection est un champ JSON réservé appelé $meta. Il peut contenir des champs non définis par le schéma et leurs valeurs sous forme de paires clé-valeur. En utilisant le champ dynamique, vous pouvez effectuer des recherches et des requêtes à la fois sur les champs définis par le schéma et sur les champs non définis par le schéma qu'ils peuvent contenir.

Activer le champ dynamique

Lorsque vous définissez un schéma pour une collection, vous pouvez définir enable_dynamic_field sur True pour activer le champ dynamique réservé, ce qui indique que tous les champs non définis par le schéma et leurs valeurs insérés ultérieurement seront enregistrés sous forme de paires clé-valeur dans le champ dynamique réservé.

L'extrait suivant crée une collection avec deux champs définis par le schéma, à savoir id et vector, et active le champ dynamique.

Pour plus d'informations sur les paramètres, voir create_collection() dans la référence du SDK.

Pour plus d'informations sur les paramètres, voir createCollection() dans la référence du SDK.

Pour plus d'informations sur les paramètres, voir createCollection() dans la référence du SDK.

import random, time
from pymilvus import connections, MilvusClient, DataType

SERVER_ADDR = "http://localhost:19530"

# 1. Set up a Milvus client
client = MilvusClient(
    uri=SERVER_ADDR
)

# 2. Create a collection
schema = MilvusClient.create_schema(
    auto_id=False,
    enable_dynamic_field=True,
)

schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5)

index_params = MilvusClient.prepare_index_params()

index_params.add_index(
    field_name="id",
    index_type="STL_SORT"
)

index_params.add_index(
    field_name="vector",
    index_type="IVF_FLAT",
    metric_type="L2",
    params={"nlist": 1024}
)

client.create_collection(
    collection_name="test_collection",
    schema=schema,
    index_params=index_params
)

res = client.get_load_state(
    collection_name="test_collection"
)

print(res)

# Output
#
# {
#     "state": "<LoadState: Loaded>"
# }
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.common.DataType;
import io.milvus.v2.common.IndexParam;
import io.milvus.v2.service.collection.request.*;
import io.milvus.v2.service.vector.request.*;
import io.milvus.v2.service.vector.request.data.*;
import io.milvus.v2.service.vector.response.*;

import java.util.*;

String CLUSTER_ENDPOINT = "http://localhost:19530";

// 1. Connect to Milvus server
ConnectConfig connectConfig = ConnectConfig.builder()
        .uri(CLUSTER_ENDPOINT)
        .build();

MilvusClientV2 client = new MilvusClientV2(connectConfig);

// 2. Create a collection in customized setup mode

// 2.1 Create schema
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.setEnableDynamicField(true);

// 2.2 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());

// 2.3 Prepare index parameters
IndexParam indexParamForIdField = IndexParam.builder()
        .fieldName("id")
        .indexType(IndexParam.IndexType.STL_SORT)
        .build();

Map<String, Object> params = new HashMap<>();
params.put("nlist", 1024);
IndexParam indexParamForVectorField = IndexParam.builder()
        .fieldName("vector")
        .indexType(IndexParam.IndexType.IVF_FLAT)
        .metricType(IndexParam.MetricType.IP)
        .extraParams(params)
        .build();

List<IndexParam> indexParams = new ArrayList<>();
indexParams.add(indexParamForIdField);
indexParams.add(indexParamForVectorField);

// 2.4 Create a collection with schema and index parameters
CreateCollectionReq customizedSetupReq = CreateCollectionReq.builder()
        .collectionName("customized_setup")
        .collectionSchema(schema)
        .indexParams(indexParams)
        .build();

client.createCollection(customizedSetupReq);

Thread.sleep(5000);

// 2.5 Get load state of the collection
GetLoadStateReq customSetupLoadStateReq1 = GetLoadStateReq.builder()
        .collectionName("customized_setup")
        .build();

boolean res = client.getLoadState(customSetupLoadStateReq1);

System.out.println(res);

// Output:
// true
const { MilvusClient, DataType, sleep } = require("@zilliz/milvus2-sdk-node")

const address = "http://localhost:19530"

async function main() {
// 1. Set up a Milvus Client
client = new MilvusClient({address}); 

// 2. Create a collection
// 2.1 Define fields
const fields = [
    {
        name: "id",
        data_type: DataType.Int64,
        is_primary_key: true,
        auto_id: false
    },
    {
        name: "vector",
        data_type: DataType.FloatVector,
        dim: 5
    },
]

// 2.2 Prepare index parameters
const index_params = [{
    field_name: "id",
    index_type: "STL_SORT"
},{
    field_name: "vector",
    index_type: "IVF_FLAT",
    metric_type: "IP",
    params: { nlist: 1024}
}]

// 2.3 Create a collection with fields and index parameters
res = await client.createCollection({
    collection_name: "test_collection",
    fields: fields, 
    index_params: index_params,
    enable_dynamic_field: true
})

console.log(res.error_code)

// Output
// 
// Success
// 

res = await client.getLoadState({
    collection_name: "test_collection",
})  

console.log(res.state)

// Output
// 
// LoadStateLoaded
// 

Insérer des données dynamiques

Une fois la collection créée, vous pouvez commencer à insérer des données, y compris des données dynamiques, dans la collection.

Préparer les données

Dans cette section, vous devez préparer des données générées de manière aléatoire en vue de leur insertion ultérieure.

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)
    data.append({
        "id": i,
        "vector": [ random.uniform(-1, 1) for _ in range(5) ],
        "color": current_color,
        "tag": current_tag,
        "color_tag": f"{current_color}_{str(current_tag)}"
    })

print(data[0])
List<String> colors = Arrays.asList("green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey");
List<JsonObject> data = new ArrayList<>();
Gson gson = new Gson();
Random rand = new Random();
for (int i=0; i<1000; i++) {
    String current_color = colors.get(rand.nextInt(colors.size()-1));
    int current_tag = rand.nextInt(8999) + 1000;
    JsonObject row = new JsonObject();
    row.addProperty("id", (long) i);
    row.add("vector", gson.toJsonTree(Arrays.asList(rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat())));
    row.addProperty("color", current_color);
    row.addProperty("tag", current_tag);
    row.addProperty("color_tag", current_color + "_" + (rand.nextInt(8999) + 1000));
    data.add(row);
}

System.out.println(data.get(0).toString());
const colors = ["green", "blue", "yellow", "red", "black", "white", "purple", "pink", "orange", "brown", "grey"]
var 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)
    data.push({
        id: i,
        vector: [Math.random(), Math.random(), Math.random(), Math.random(), Math.random()],
        color: current_color,
        tag: current_tag,
        color_tag: `${current_color}_${current_tag}`
    })
}

console.log(data[0])

Vous pouvez visualiser la structure des données générées en vérifiant leur première entrée.

{
    id: 0,
    vector: [
        0.1275656405044483,
        0.47417858592773277,
        0.13858264437643286,
        0.2390904907020377,
        0.8447862593689635
    ],
    color: 'blue',
    tag: 2064,
    color_tag: 'blue_2064'
}

Insérer les données

Vous pouvez ensuite insérer les données dans la collection en toute sécurité.

Pour plus d'informations sur les paramètres, reportez-vous à insert() dans la référence SDK.

Pour plus d'informations sur les paramètres, voir insert() dans la référence du SDK.

Pour plus d'informations sur les paramètres, voir insert() dans la référence du SDK.

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,
#         "(990 more items hidden)"
#     ]
# }

time.sleep(5)
// 3.1 Insert data into the collection
InsertReq insertReq = InsertReq.builder()
        .collectionName("customized_setup")
        .data(data)
        .build();

InsertResp insertResp = client.insert(insertReq);

System.out.println(insertResp.getInsertCnt());

// Output:
// 1000

Thread.sleep(5000);
res = await client.insert({
    collection_name: "test_collection",
    data: data,
})

console.log(res.insert_cnt)

// Output
// 
// 1000
// 

await sleep(5000)

Recherche avec des champs dynamiques

Si vous avez créé la collection avec le champ dynamique activé et inséré des champs non définis par le schéma, vous pouvez utiliser ces champs dans l'expression de filtre d'une recherche ou d'une requête comme suit.

Pour plus d'informations sur les paramètres, voir search() dans la référence SDK.

Pour plus d'informations sur les paramètres, voir search() dans la référence du SDK.

Pour plus d'informations sur les paramètres, voir search() dans la référence du SDK.

# 4. Search with dynamic fields
query_vectors = [[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]]

res = client.search(
    collection_name="test_collection",
    data=query_vectors,
    filter="color in [\"red\", \"green\"]",
    search_params={"metric_type": "L2", "params": {"nprobe": 10}},
    limit=3
)

print(res)

# Output
#
# [
#     [
#         {
#             "id": 863,
#             "distance": 0.188413605093956,
#             "entity": {
#                 "id": 863,
#                 "color_tag": "red_2371"
#             }
#         },
#         {
#             "id": 799,
#             "distance": 0.29188022017478943,
#             "entity": {
#                 "id": 799,
#                 "color_tag": "red_2235"
#             }
#         },
#         {
#             "id": 564,
#             "distance": 0.3492690920829773,
#             "entity": {
#                 "id": 564,
#                 "color_tag": "red_9186"
#             }
#         }
#     ]
# ]
// 4. Search with non-schema-defined fields
List<BaseVector> queryVectors = Collections.singletonList(new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f}));

SearchReq searchReq = SearchReq.builder()
        .collectionName("customized_setup")
        .data(queryVectors)
        .filter("$meta[\"color\"] in [\"red\", \"green\"]")
        .outputFields(Arrays.asList("id", "color_tag"))
        .topK(3)
        .build();

SearchResp searchResp = client.search(searchReq);

List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
    System.out.println("TopK results:");
    for (SearchResp.SearchResult result : results) {
        System.out.println(result);
    }
}

// Output:
// SearchResp.SearchResult(entity={color_tag=green_2205, id=556}, score=1.134007, id=556)
// SearchResp.SearchResult(entity={color_tag=red_2786, id=310}, score=0.9072295, id=310)
// SearchResp.SearchResult(entity={color_tag=red_9493, id=215}, score=0.8819287, id=215)
// 4. Search with non-schema-defined fields
const query_vectors = [[0.1, 0.2, 0.3, 0.4, 0.5]]

res = await client.search({
    collection_name: "test_collection",
    data: query_vectors,
    filter: "color in [\"red\", \"green\"]",
    output_fields: ["color_tag"],
    limit: 3
})

console.log(res.results)

// Output
// 
// [
//   { score: 1.2284551858901978, id: '301', color_tag: 'red_1270' },
//   { score: 1.2195171117782593, id: '205', color_tag: 'red_2780' },
//   { score: 1.2055039405822754, id: '487', color_tag: 'red_6653' }
// ]
// 

Récapitulatif

Il convient de noter que color, tag et color_tag ne sont pas présents lorsque vous définissez le schéma de la collection, mais vous pouvez les utiliser en tant que champs définis par le schéma lorsque vous effectuez des recherches et des requêtes.

Si le nom d'un champ non défini par le schéma contient des caractères autres que des chiffres, des lettres et des traits de soulignement, tels que des signes plus (+), des astérisques (*) ou des signes dollar ($), vous devez inclure la clé dans $meta[], comme le montre l'extrait de code suivant, lorsque vous l'utilisez dans une expression booléenne ou que vous l'incluez dans les champs de sortie.

... 
filter='$meta["$key"] in ["a", "b", "c"]', 
output_fields='$meta["$key"]'  
...

Traduit parDeepL

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started
Feedback

Cette page a-t - elle été utile ?