milvus-logo
LFAI
Home
  • Guide de l'utilisateur

Champ JSON

JSON (JavaScript Object Notation) est un format d'échange de données léger qui offre un moyen souple de stocker et d'interroger des structures de données complexes. Dans Milvus, vous pouvez stocker des informations structurées supplémentaires avec des données vectorielles à l'aide de champs JSON, ce qui permet d'effectuer des recherches et des requêtes avancées combinant la similarité vectorielle et le filtrage structuré.

Les champs JSON sont idéaux pour les applications qui nécessitent des métadonnées afin d'optimiser les résultats de recherche. Par exemple, dans le commerce électronique, les vecteurs de produits peuvent être enrichis d'attributs tels que la catégorie, le prix et la marque. Dans les systèmes de recommandation, les vecteurs d'utilisateurs peuvent être combinés avec des préférences et des informations démographiques. Vous trouverez ci-dessous un exemple de champ JSON typique.

{
  "category": "electronics",
  "price": 99.99,
  "brand": "BrandA"
}

Ajouter un champ JSON

Pour utiliser des champs JSON dans Milvus, définissez le type de champ approprié dans le schéma de la collection, en définissant datatype sur le type JSON pris en charge, c'est-à-dire JSON.

Voici comment définir un schéma de collecte qui inclut un champ JSON.

from pymilvus import MilvusClient, DataType

client = MilvusClient(uri="http://localhost:19530")

schema = client.create_schema(
    auto_id=False,
    enable_dynamic_fields=True,
)

schema.add_field(field_name="metadata", datatype=DataType.JSON)
schema.add_field(field_name="pk", datatype=DataType.INT64, is_primary=True)
schema.add_field(field_name="embedding", datatype=DataType.FLOAT_VECTOR, dim=3)

import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;

import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;

MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
        .uri("http://localhost:19530")
        .build());
        
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.setEnableDynamicField(true);

schema.addField(AddFieldReq.builder()
        .fieldName("metadata")
        .dataType(DataType.JSON)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("pk")
        .dataType(DataType.Int64)
        .isPrimaryKey(true)
        .build());

schema.addField(AddFieldReq.builder()
        .fieldName("embedding")
        .dataType(DataType.FloatVector)
        .dimension(3)
        .build());

import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const schema = [
  {
    name: "metadata",
    data_type: DataType.JSON,
  },
  {
    name: "pk",
    data_type: DataType.Int64,
    is_primary_key: true,
  },
  {
    name: "embedding",
    data_type: DataType.FloatVector,
    dim: 3,
  },
];

export jsonField='{
    "fieldName": "metadata",
    "dataType": "JSON"
}'

export pkField='{
    "fieldName": "pk",
    "dataType": "Int64",
    "isPrimary": true
}'

export vectorField='{
    "fieldName": "embedding",
    "dataType": "FloatVector",
    "elementTypeParams": {
        "dim": 3
    }
}'

export schema="{
    \"autoID\": false,
    \"fields\": [
        $jsonField,
        $pkField,
        $vectorField
    ]
}"

Dans cet exemple, nous ajoutons un champ JSON appelé metadata pour stocker des métadonnées supplémentaires liées aux données vectorielles, telles que la catégorie de produit, le prix et les informations sur la marque.

Le champ primaire et le champ vectoriel sont obligatoires lorsque vous créez une collection. Le champ primaire identifie chaque entité de manière unique, tandis que le champ vectoriel est essentiel pour la recherche de similarités. Pour plus de détails, reportez-vous aux sections Champ primaire et AutoID, Vecteur dense, Vecteur binaire ou Vecteur épars.

Créer une collection

Lors de la création d'une collection, vous devez créer un index pour le champ vectoriel afin de garantir les performances de recherche. Dans cet exemple, nous utilisons AUTOINDEX pour simplifier la configuration de l'index. Pour plus de détails, reportez-vous à la section AUTOINDEX.


index_params = client.prepare_index_params()

index_params.add_index(
    field_name="embedding",
    index_type="AUTOINDEX",
    metric_type="COSINE"
)

import io.milvus.v2.common.IndexParam;
import java.util.*;

List<IndexParam> indexes = new ArrayList<>();
indexes.add(IndexParam.builder()
        .fieldName("embedding")
        .indexType(IndexParam.IndexType.AUTOINDEX)
        .metricType(IndexParam.MetricType.COSINE)
        .build());

const indexParams = {
    index_name: 'embedding_index',
    field_name: 'embedding',
    metricType: MetricType.CONSINE,
    index_type: IndexType.AUTOINDEX,
);

export indexParams='[
        {
            "fieldName": "embedding",
            "metricType": "COSINE",
            "indexType": "AUTOINDEX"
        }
    ]'

Utilisez le schéma défini et les paramètres d'index pour créer une collection.

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

CreateCollectionReq requestCreate = CreateCollectionReq.builder()
        .collectionName("my_json_collection")
        .collectionSchema(schema)
        .indexParams(indexes)
        .build();
client.createCollection(requestCreate);

client.create_collection({
    collection_name: "my_json_collection",
    schema: schema,
    index_params: indexParams
})

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d "{
    \"collectionName\": \"my_json_collection\",
    \"schema\": $schema,
    \"indexParams\": $indexParams
}"

Insérer des données

Après avoir créé la collection, vous pouvez insérer des données comprenant des champs JSON.

# Data to be inserted
data = [
  {
      "metadata": {"category": "electronics", "price": 99.99, "brand": "BrandA"},
      "pk": 1,
      "embedding": [0.12, 0.34, 0.56]
  },
  {
      "metadata": {"category": "home_appliances", "price": 249.99, "brand": "BrandB"},
      "pk": 2,
      "embedding": [0.56, 0.78, 0.90]
  },
  {
      "metadata": {"category": "furniture", "price": 399.99, "brand": "BrandC"},
      "pk": 3,
      "embedding": [0.91, 0.18, 0.23]
  }
]

# Insert data into the collection
client.insert(
    collection_name="your_collection_name",
    data=data
)

import com.google.gson.Gson;
import com.google.gson.JsonObject;

import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.response.InsertResp;

List<JsonObject> rows = new ArrayList<>();
Gson gson = new Gson();
rows.add(gson.fromJson("{\"metadata\": {\"category\": \"electronics\", \"price\": 99.99, \"brand\": \"BrandA\"}, \"pk\": 1, \"embedding\": [0.1, 0.2, 0.3]}", JsonObject.class));
rows.add(gson.fromJson("{\"metadata\": {\"category\": \"home_appliances\", \"price\": 249.99, \"brand\": \"BrandB\"}, \"pk\": 2, \"embedding\": [0.4, 0.5, 0.6]}", JsonObject.class));
rows.add(gson.fromJson("{\"metadata\": {\"category\": \"furniture\", \"price\": 399.99, \"brand\": \"BrandC\"}, \"pk\": 3, \"embedding\": [0.7, 0.8, 0.9]}", JsonObject.class));

InsertResp insertR = client.insert(InsertReq.builder()
        .collectionName("my_json_collection")
        .data(rows)
        .build());

const data = [
  {
      "metadata": {"category": "electronics", "price": 99.99, "brand": "BrandA"},
      "pk": 1,
      "embedding": [0.12, 0.34, 0.56]
  },
  {
      "metadata": {"category": "home_appliances", "price": 249.99, "brand": "BrandB"},
      "pk": 2,
      "embedding": [0.56, 0.78, 0.90]
  },
  {
      "metadata": {"category": "furniture", "price": 399.99, "brand": "BrandC"},
      "pk": 3,
      "embedding": [0.91, 0.18, 0.23]
  }
]

client.insert({
    collection_name: "my_json_collection",
    data: data
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "data": [
        {
            "metadata": {"category": "electronics", "price": 99.99, "brand": "BrandA"},
            "pk": 1,
            "embedding": [0.12, 0.34, 0.56]
        },
        {
            "metadata": {"category": "home_appliances", "price": 249.99, "brand": "BrandB"},
            "pk": 2,
            "embedding": [0.56, 0.78, 0.90]
        },
        {
            "metadata": {"category": "furniture", "price": 399.99, "brand": "BrandC"},
            "pk": 3,
            "embedding": [0.91, 0.18, 0.23]
        }       
    ],
    "collectionName": "my_json_collection"
}'

Dans cet exemple.

  • Chaque entrée de données comprend un champ primaire (pk), metadata en tant que champ JSON pour stocker des informations telles que la catégorie de produit, le prix et la marque.

  • embedding est un champ vectoriel tridimensionnel utilisé pour la recherche de similarités vectorielles.

Recherche et interrogation

Les champs JSON permettent un filtrage scalaire pendant les recherches, ce qui améliore les capacités de recherche vectorielle de Milvus. Vous pouvez effectuer des requêtes basées sur les propriétés JSON ainsi que sur la similarité vectorielle.

Filtrer les requêtes

Vous pouvez filtrer les données en fonction des propriétés JSON, par exemple en faisant correspondre des valeurs spécifiques ou en vérifiant si un nombre se situe dans une certaine plage.

filter = 'metadata["category"] == "electronics" and metadata["price"] < 150'

res = client.query(
    collection_name="my_json_collection",
    filter=filter,
    output_fields=["metadata"]
)

print(res)

# Output
# data: ["{'metadata': {'category': 'electronics', 'price': 99.99, 'brand': 'BrandA'}, 'pk': 1}"] 

import io.milvus.v2.service.vector.request.QueryReq;
import io.milvus.v2.service.vector.response.QueryResp;

String filter = "metadata[\"category\"] == \"electronics\" and metadata[\"price\"] < 150";
QueryResp resp = client.query(QueryReq.builder()
        .collectionName("my_json_collection")
        .filter(filter)
        .outputFields(Collections.singletonList("metadata"))
        .build());

System.out.println(resp.getQueryResults());

// Output
//
// [QueryResp.QueryResult(entity={metadata={"category":"electronics","price":99.99,"brand":"BrandA"}, pk=1})]

client.query({
    collection_name: 'my_scalar_collection',
    filter: 'metadata["category"] == "electronics" and metadata["price"] < 150',
    output_fields: ['metadata']
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "my_json_collection",
    "filter": "metadata[\"category\"] == \"electronics\" and metadata[\"price\"] < 150",
    "outputFields": ["metadata"]
}'
{"code":0,"cost":0,"data":[{"metadata":"{\"category\": \"electronics\", \"price\": 99.99, \"brand\": \"BrandA\"}","pk":1}]}

Dans la requête ci-dessus, Milvus filtre les entités dont le champ metadata a une catégorie de "electronics" et un prix inférieur à 150, en renvoyant les entités qui correspondent à ces critères.

Recherche vectorielle avec filtrage JSON

En combinant la similarité vectorielle avec le filtrage JSON, vous pouvez vous assurer que les données extraites correspondent non seulement à la sémantique, mais qu'elles répondent également à des conditions commerciales spécifiques, ce qui rend les résultats de la recherche plus précis et alignés sur les besoins de l'utilisateur.

filter = 'metadata["brand"] == "BrandA"'

res = client.search(
    collection_name="my_json_collection",
    data=[[0.3, -0.6, 0.1]],
    limit=5,
    search_params={"params": {"nprobe": 10}},
    output_fields=["metadata"],
    filter=filter
)

print(res)

# Output
# data: ["[{'id': 1, 'distance': -0.2479381263256073, 'entity': {'metadata': {'category': 'electronics', 'price': 99.99, 'brand': 'BrandA'}}}]"] 

import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.response.SearchResp;

String filter = "metadata[\"brand\"] == \"BrandA\"";
SearchResp resp = client.search(SearchReq.builder()
        .collectionName("my_json_collection")
        .annsField("embedding")
        .data(Collections.singletonList(new FloatVec(new float[]{0.3f, -0.6f, 0.1f})))
        .topK(5)
        .outputFields(Collections.singletonList("metadata"))
        .filter(filter)
        .build());

System.out.println(resp.getSearchResults());

// Output
//
// [[SearchResp.SearchResult(entity={metadata={"category":"electronics","price":99.99,"brand":"BrandA"}}, score=-0.2364331, id=1)]]

client.search({
    collection_name: 'my_json_collection',
    data: [0.3, -0.6, 0.1],
    limit: 5,
    output_fields: ['metadata'],
    filter: 'metadata["category"] == "electronics" and metadata["price"] < 150',
});

curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
    "collectionName": "my_json_collection",
    "data": [
        [0.3, -0.6, 0.1]
    ],
    "annsField": "embedding",
    "limit": 5,
    "searchParams":{
        "params":{"nprobe":10}
    },
    "outputFields": ["metadata"],
    "filter": "metadata[\"brand\"] == \"BrandA\""
}'

## {"code":0,"cost":0,"data":[{"distance":-0.24793813,"id":1,"metadata":"{\"category\": \"electronics\", \"price\": 99.99, \"brand\": \"BrandA\"}"}]}

Dans cet exemple, Milvus renvoie les 5 entités les plus similaires au vecteur de la requête, le champ metadata contenant une marque de "BrandA".

En outre, Milvus prend en charge des opérateurs de filtrage JSON avancés tels que JSON_CONTAINS, JSON_CONTAINS_ALL, et JSON_CONTAINS_ANY, qui permettent d'améliorer encore les capacités de requête. Pour plus de détails, voir Filtrage des métadonnées.

Limites

  • Limites de l'indexation: En raison de la complexité des structures de données, l'indexation des champs JSON n'est pas prise en charge.

  • Correspondance des types de données: si la valeur clé d'un champ JSON est un nombre entier ou un nombre à virgule flottante, elle ne peut être comparée qu'à une autre clé entière ou flottante ou aux champs INT32/64 ou FLOAT32/64. Si la valeur de la clé est une chaîne de caractères (VARCHAR), elle ne peut être comparée qu'à une autre clé de type chaîne de caractères.

  • Restrictions de dénomination: Pour nommer les clés JSON, il est recommandé de n'utiliser que des lettres, des caractères numériques et des traits de soulignement, car les autres caractères peuvent poser des problèmes lors du filtrage ou de la recherche.

  • Traitement des valeurs de chaîne: Pour les valeurs de chaîne (VARCHAR), Milvus stocke les chaînes de champ JSON telles quelles sans conversion sémantique. Par exemple, Milvus stocke les chaînes de champ JSON telles quelles, sans conversion sémantique : 'a"b' "a'b" , 'a\\'b' et "a\\"b" sont stockés tels qu'ils ont été saisis, mais 'a'b' et "a"b" sont considérés comme non valides.

  • Traitement des dictionnaires imbriqués: Tous les dictionnaires imbriqués dans les valeurs des champs JSON sont traités comme des chaînes.

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 ?