JSON-Feld
JSON (JavaScript Object Notation) ist ein leichtgewichtiges Datenaustauschformat, das eine flexible Möglichkeit zur Speicherung und Abfrage komplexer Datenstrukturen bietet. In Milvus können Sie mit JSON-Feldern neben Vektordaten zusätzliche strukturierte Informationen speichern und so erweiterte Suchen und Abfragen ermöglichen, die Vektorähnlichkeit mit strukturierter Filterung kombinieren.
JSON-Felder sind ideal für Anwendungen, die Metadaten zur Optimierung der Abfrageergebnisse benötigen. So können beispielsweise im E-Commerce Produktvektoren mit Attributen wie Kategorie, Preis und Marke angereichert werden. In Empfehlungssystemen können Benutzervektoren mit Präferenzen und demografischen Informationen kombiniert werden. Im Folgenden finden Sie ein Beispiel für ein typisches JSON-Feld.
{
"category": "electronics",
"price": 99.99,
"brand": "BrandA"
}
JSON-Feld hinzufügen
Um JSON-Felder in Milvus zu verwenden, definieren Sie den entsprechenden Feldtyp im Sammlungsschema und setzen Sie datatype
auf den unterstützten JSON-Typ, d.h. JSON
.
So definieren Sie ein Sammlungsschema, das ein JSON-Feld enthält.
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
]
}"
In diesem Beispiel fügen wir ein JSON-Feld mit der Bezeichnung metadata
hinzu, um zusätzliche Metadaten im Zusammenhang mit Vektordaten zu speichern, wie Produktkategorie, Preis und Markeninformationen.
Das Primärfeld und das Vektorfeld sind obligatorisch, wenn Sie eine Sammlung erstellen. Das Primärfeld identifiziert jede Entität eindeutig, während das Vektorfeld für die Ähnlichkeitssuche entscheidend ist. Weitere Einzelheiten finden Sie unter Primärfeld & AutoID, Dichter Vektor, Binärer Vektor oder Spärlicher Vektor.
Sammlung erstellen
Wenn Sie eine Sammlung erstellen, müssen Sie einen Index für das Vektorfeld erstellen, um die Abrufleistung zu gewährleisten. In diesem Beispiel verwenden wir AUTOINDEX
, um die Indexerstellung zu vereinfachen. Weitere Einzelheiten finden Sie unter 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"
}
]'
Verwenden Sie das definierte Schema und die Indexparameter, um eine Sammlung zu erstellen.
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
}"
Daten einfügen
Nachdem Sie die Sammlung erstellt haben, können Sie Daten einfügen, die JSON-Felder enthalten.
# 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"
}'
In diesem Beispiel.
Jeder Dateneintrag enthält ein Primärfeld (
pk
),metadata
als JSON-Feld zum Speichern von Informationen wie Produktkategorie, Preis und Marke.embedding
ist ein 3-dimensionales Vektorfeld, das für die vektorielle Ähnlichkeitssuche verwendet wird.
Suche und Abfrage
JSON-Felder ermöglichen eine skalare Filterung während der Suche und erweitern die Vektorsuchfunktionen von Milvus. Neben der Vektorähnlichkeit können Sie auch Abfragen basierend auf JSON-Eigenschaften durchführen.
Filter-Abfragen
Sie können Daten auf der Grundlage von JSON-Eigenschaften filtern, z. B. nach bestimmten Werten suchen oder prüfen, ob eine Zahl in einen bestimmten Bereich fällt.
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}]}
In der obigen Abfrage filtert Milvus Entitäten heraus, bei denen das Feld metadata
eine Kategorie von "electronics"
und einen Preis unter 150 hat, und gibt Entitäten zurück, die diesen Kriterien entsprechen.
Vektorsuche mit JSON-Filterung
Durch die Kombination von Vektorähnlichkeit mit JSON-Filterung können Sie sicherstellen, dass die abgerufenen Daten nicht nur semantisch übereinstimmen, sondern auch spezifische Geschäftsbedingungen erfüllen, wodurch die Suchergebnisse präziser und auf die Bedürfnisse der Benutzer abgestimmt werden.
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\"}"}]}
In diesem Beispiel gibt Milvus die Top 5 Entitäten zurück, die dem Abfragevektor am ähnlichsten sind, wobei das Feld metadata
eine Marke von "BrandA"
enthält.
Darüber hinaus unterstützt Milvus erweiterte JSON-Filteroperatoren wie JSON_CONTAINS
, JSON_CONTAINS_ALL
und JSON_CONTAINS_ANY
, die die Abfragemöglichkeiten weiter verbessern können. Weitere Einzelheiten finden Sie unter Metadaten-Filterung.
Begrenzungen
Beschränkungen bei der Indizierung: Aufgrund der Komplexität der Datenstrukturen wird die Indizierung von JSON-Feldern nicht unterstützt.
Datentypabgleich: Wenn der Schlüsselwert eines JSON-Feldes ein Integer- oder Fließkommawert ist, kann er nur mit einem anderen Integer- oder Fließkommaschlüssel oder
INT32/64
oderFLOAT32/64
verglichen werden. Handelt es sich bei dem Schlüsselwert um eine Zeichenkette (VARCHAR
), kann er nur mit einem anderen Zeichenkettenschlüssel verglichen werden.Beschränkungen bei der Benennung: Es wird empfohlen, bei der Benennung von JSON-Schlüsseln nur Buchstaben, numerische Zeichen und Unterstriche zu verwenden, da andere Zeichen bei der Filterung oder Suche Probleme verursachen können.
Behandlung von String-Werten: Für String-Werte (
VARCHAR
) speichert Milvus JSON-Feldstrings ohne semantische Konvertierung. Zum Beispiel:'a"b'
"a'b"
,'a\\'b'
und"a\\"b"
werden wie eingegeben gespeichert;'a'b'
und"a"b"
werden jedoch als ungültig betrachtet.Umgang mit verschachtelten Wörterbüchern: Alle verschachtelten Wörterbücher innerhalb von JSON-Feldwerten werden als Zeichenketten behandelt.