Champ de nombres
Les champs numériques sont utilisés pour stocker des données numériques non vectorielles dans Milvus. Ces champs sont généralement utilisés pour décrire des informations supplémentaires liées aux données vectorielles, telles que l'âge, le prix, etc. L'utilisation de ces données permet de mieux décrire les vecteurs et d'améliorer l'efficacité du filtrage des données et des requêtes conditionnelles.
Les champs numériques sont particulièrement utiles dans de nombreux scénarios. Par exemple, dans les recommandations en matière de commerce électronique, un champ de prix peut être utilisé pour le filtrage ; dans l'analyse du profil des utilisateurs, les tranches d'âge peuvent aider à affiner les résultats. Combinés à des données vectorielles, les champs numériques peuvent aider le système à fournir des recherches de similarité tout en répondant plus précisément aux besoins personnalisés des utilisateurs.
Types de champs numériques pris en charge
Milvus prend en charge plusieurs types de champs numériques pour répondre à différents besoins en matière de stockage de données et de requêtes.
Type | Description |
---|---|
| Type booléen pour stocker |
| Entier de 8 bits, adapté au stockage de données entières de petite taille. |
| Entier de 16 bits, pour les données entières de moyenne portée. |
| Entier de 32 bits, idéal pour le stockage de données entières générales telles que les quantités de produits ou les identifiants d'utilisateurs. |
| Nombre entier de 64 bits, adapté au stockage de données à grande échelle telles que les horodatages ou les identifiants. |
| Nombre à virgule flottante de 32 bits, pour les données nécessitant une précision générale, telles que les valeurs nominales ou la température. |
| Nombre à virgule flottante de 64 bits en double précision, pour les données de haute précision telles que les informations financières ou les calculs scientifiques. |
Ajout d'un champ numérique
Pour utiliser des champs numériques dans Milvus, définissez les champs correspondants dans le schéma de la collection, en attribuant à datatype
un type pris en charge tel que BOOL
ou INT8
. Pour obtenir une liste complète des types de champs numériques pris en charge, reportez-vous à la section Types de champs numériques pris en charge.
L'exemple suivant montre comment définir un schéma qui inclut les champs numériques age
et price
.
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="age", datatype=DataType.INT64)
schema.add_field(field_name="price", datatype=DataType.FLOAT)
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("age")
.dataType(DataType.Int64)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("price")
.dataType(DataType.Float)
.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: "age",
data_type: DataType.Int64,
},
{
name: "price",
data_type: DataType.Float,
},
{
name: "pk",
data_type: DataType.Int64,
is_primary_key: true,
},
{
name: "embedding",
data_type: DataType.FloatVector,
dim: 3,
},
];
export int64Field='{
"fieldName": "age",
"dataType": "Int64"
}'
export floatField='{
"fieldName": "price",
"dataType": "Float"
}'
export pkField='{
"fieldName": "pk",
"dataType": "Int64",
"isPrimary": true
}'
export vectorField='{
"fieldName": "embedding",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": 3
}
}'
export schema="{
\"autoID\": false,
\"fields\": [
$int64Field,
$floatField,
$pkField,
$vectorField
]
}"
Les champs primaire et 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.
Définir les paramètres d'index
La définition de paramètres d'index pour les champs numériques est facultative, mais elle peut améliorer considérablement l'efficacité de la recherche.
Dans l'exemple suivant, nous créons un AUTOINDEX
pour le champ numérique age
, ce qui permet à Milvus de créer automatiquement un index approprié en fonction du type de données. Pour plus d'informations, voir AUTOINDEX.
index_params = client.prepare_index_params()
index_params.add_index(
field_name="age",
index_type="AUTOINDEX",
index_name="inverted_index"
)
import io.milvus.v2.common.IndexParam;
import java.util.*;
List<IndexParam> indexes = new ArrayList<>();
indexes.add(IndexParam.builder()
.fieldName("age")
.indexType(IndexParam.IndexType.AUTOINDEX)
.build());
const indexParams = {
index_name: 'inverted_index',
field_name: 'age',
index_type: IndexType.AUTOINDEX,
);
export indexParams='[
{
"fieldName": "age",
"indexName": "inverted_index",
"indexType": "AUTOINDEX"
}
]'
Outre AUTOINDEX
, vous pouvez spécifier d'autres types d'index de champ numérique. Pour connaître les types d'index pris en charge, reportez-vous à la section Index scalaires.
En outre, avant de créer la collection, vous devez créer un index pour le champ vectoriel. Dans cet exemple, nous utilisons AUTOINDEX
pour simplifier les paramètres de l'index vectoriel.
# Add vector index
index_params.add_index(
field_name="embedding",
index_type="AUTOINDEX", # Use automatic indexing to simplify complex index settings
metric_type="COSINE" # Specify similarity metric type, options include L2, COSINE, or IP
)
indexes.add(IndexParam.builder()
.fieldName("embedding")
.indexType(IndexParam.IndexType.AUTOINDEX)
.metricType(IndexParam.MetricType.COSINE)
.build());
import { IndexType } from "@zilliz/milvus2-sdk-node";
const indexParams = [
{
field_name: "age",
index_name: "inverted_index",
index_type: IndexType.AUTOINDEX,
},
{
field_name: "embedding",
metric_type: "COSINE",
index_type: IndexType.AUTOINDEX,
},
];
export indexParams='[
{
"fieldName": "age",
"indexName": "inverted_index",
"indexType": "AUTOINDEX"
},
{
"fieldName": "embedding",
"metricType": "COSINE",
"indexType": "AUTOINDEX"
}
]'
Créer une collection
Une fois le schéma et les index définis, vous pouvez créer une collection comprenant des champs numériques.
# Create Collection
client.create_collection(
collection_name="your_collection_name",
schema=schema,
index_params=index_params
)
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
.collectionName("my_scalar_collection")
.collectionSchema(schema)
.indexParams(indexes)
.build();
client.createCollection(requestCreate);
client.create_collection({
collection_name: "my_scalar_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_scalar_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 numériques.
data = [
{"age": 25, "price": 99.99, "pk": 1, "embedding": [0.1, 0.2, 0.3]},
{"age": 30, "price": 149.50, "pk": 2, "embedding": [0.4, 0.5, 0.6]},
{"age": 35, "price": 199.99, "pk": 3, "embedding": [0.7, 0.8, 0.9]},
]
client.insert(
collection_name="my_scalar_collection",
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("{\"age\": 25, \"price\": 99.99, \"pk\": 1, \"embedding\": [0.1, 0.2, 0.3]}", JsonObject.class));
rows.add(gson.fromJson("{\"age\": 30, \"price\": 149.50, \"pk\": 2, \"embedding\": [0.4, 0.5, 0.6]}", JsonObject.class));
rows.add(gson.fromJson("{\"age\": 35, \"price\": 199.99, \"pk\": 3, \"embedding\": [0.7, 0.8, 0.9]}", JsonObject.class));
InsertResp insertR = client.insert(InsertReq.builder()
.collectionName("my_scalar_collection")
.data(rows)
.build());
const data = [
{ age: 25, price: 99.99, pk: 1, embedding: [0.1, 0.2, 0.3] },
{ age: 30, price: 149.5, pk: 2, embedding: [0.4, 0.5, 0.6] },
{ age: 35, price: 199.99, pk: 3, embedding: [0.7, 0.8, 0.9] },
];
client.insert({
collection_name: "my_scalar_collection",
data: data,
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/insert" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"data": [
{"age": 25, "price": 99.99, "pk": 1, "embedding": [0.1, 0.2, 0.3]},
{"age": 30, "price": 149.50, "pk": 2, "embedding": [0.4, 0.5, 0.6]},
{"age": 35, "price": 199.99, "pk": 3, "embedding": [0.7, 0.8, 0.9]}
],
"collectionName": "my_scalar_collection"
}'
Dans cet exemple, nous insérons des données qui comprennent age
, price
, pk
(champ primaire) et des représentations vectorielles (embedding
). Pour s'assurer que les données insérées correspondent aux champs définis dans le schéma, il est recommandé de vérifier les types de données à l'avance afin d'éviter les erreurs.
Si vous avez défini enable_dynamic_fields=True
lors de la définition du schéma, Milvus vous permet d'insérer des champs numériques qui n'ont pas été définis à l'avance. Cependant, n'oubliez pas que cela peut augmenter la complexité des requêtes et de la gestion, ce qui peut avoir un impact sur les performances. Pour plus d'informations, voir Champ dynamique.
Recherche et interrogation
Après avoir ajouté des champs numériques, vous pouvez les utiliser pour filtrer les opérations de recherche et de requête afin d'obtenir des résultats de recherche plus précis.
Requêtes de filtrage
Après avoir ajouté des champs numériques, vous pouvez les utiliser pour filtrer les requêtes. Par exemple, vous pouvez interroger toutes les entités dont l'adresse age
est comprise entre 30 et 40.
filter = "30 <= age <= 40"
res = client.query(
collection_name="my_scalar_collection",
filter=filter,
output_fields=["age","price"]
)
print(res)
# Output
# data: ["{'age': 30, 'price': np.float32(149.5), 'pk': 2}", "{'age': 35, 'price': np.float32(199.99), 'pk': 3}"]
import io.milvus.v2.service.vector.request.QueryReq;
import io.milvus.v2.service.vector.response.QueryResp;
String filter = "30 <= age <= 40";
QueryResp resp = client.query(QueryReq.builder()
.collectionName("my_scalar_collection")
.filter(filter)
.outputFields(Arrays.asList("age", "price"))
.build());
System.out.println(resp.getQueryResults());
// Output
//
// [QueryResp.QueryResult(entity={price=149.5, pk=2, age=30}), QueryResp.QueryResult(entity={price=199.99, pk=3, age=35})]
client.query({
collection_name: 'my_scalar_collection',
filter: '30 <= age <= 40',
output_fields: ['age', 'price']
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/query" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_scalar_collection",
"filter": "30 <= age <= 40",
"outputFields": ["age","price"]
}'
## {"code":0,"cost":0,"data":[{"age":30,"pk":2,"price":149.5},{"age":35,"pk":3,"price":199.99}]}
Cette expression de requête renvoie toutes les entités correspondantes et affiche les champs age
et price
. Pour plus d'informations sur les requêtes de filtrage, reportez-vous à la section Filtrage des métadonnées.
Recherche vectorielle avec filtrage des nombres
Outre le filtrage de base des champs numériques, vous pouvez combiner des recherches de similarité vectorielle avec des filtres de champs numériques. Par exemple, le code suivant montre comment ajouter un filtre de champ numérique à une recherche vectorielle.
filter = "25 <= age <= 35"
res = client.search(
collection_name="my_scalar_collection",
data=[[0.3, -0.6, 0.1]],
limit=5,
search_params={"params": {"nprobe": 10}},
output_fields=["age","price"],
filter=filter
)
print(res)
# Output
# data: ["[{'id': 1, 'distance': -0.06000000238418579, 'entity': {'age': 25, 'price': 99.98999786376953}}, {'id': 2, 'distance': -0.12000000476837158, 'entity': {'age': 30, 'price': 149.5}}, {'id': 3, 'distance': -0.18000000715255737, 'entity': {'age': 35, 'price': 199.99000549316406}}]"]
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
String filter = "25 <= age <= 35";
SearchResp resp = client.search(SearchReq.builder()
.collectionName("my_scalar_collection")
.annsField("embedding")
.data(Collections.singletonList(new FloatVec(new float[]{0.3f, -0.6f, 0.1f})))
.topK(5)
.outputFields(Arrays.asList("age", "price"))
.filter(filter)
.build());
System.out.println(resp.getSearchResults());
// Output
//
// [[SearchResp.SearchResult(entity={price=199.99, age=35}, score=-0.19054288, id=3), SearchResp.SearchResult(entity={price=149.5, age=30}, score=-0.20163085, id=2), SearchResp.SearchResult(entity={price=99.99, age=25}, score=-0.2364331, id=1)]]
client.search({
collection_name: 'my_scalar_collection',
data: [0.3, -0.6, 0.1],
limit: 5,
output_fields: ['age', 'price'],
filter: '25 <= age <= 35'
});
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_scalar_collection",
"data": [
[0.3, -0.6, 0.1]
],
"annsField": "embedding",
"limit": 5,
"outputFields": ["age", "price"]
}'
## {"code":0,"cost":0,"data":[{"age":35,"distance":-0.19054288,"id":3,"price":199.99},{"age":30,"distance":-0.20163085,"id":2,"price":149.5},{"age":25,"distance":-0.2364331,"id":1,"price":99.99}]}
Dans cet exemple, nous définissons d'abord un vecteur de requête et ajoutons une condition de filtrage 25 <= age <= 35
pendant la recherche. Cela permet de s'assurer que les résultats de la recherche sont non seulement similaires au vecteur de la requête, mais qu'ils correspondent également à la tranche d'âge spécifiée. Pour plus d'informations, voir Filtrage des métadonnées.