صفيف الهياكلCompatible with Milvus 2.6.4+
يخزن حقل صفيف الهياكل في كيان ما مجموعة مرتبة من عناصر الهياكل. تشترك كل بنية في المصفوفة في نفس المخطط المحدد مسبقًا، وتتألف من عدة متجهات وحقول قياسية.
إليك مثال لكيان من مجموعة تحتوي على حقل صفيف من الهياكل.
{
'id': 0,
'title': 'Walden',
'title_vector': [0.1, 0.2, 0.3, 0.4, 0.5],
'author': 'Henry David Thoreau',
'year_of_publication': 1845,
'chunks': [
{
'text': 'When I wrote the following pages, or rather the bulk of them...',
'text_vector': [0.3, 0.2, 0.3, 0.2, 0.5],
'chapter': 'Economy',
},
{
'text': 'I would fain say something, not so much concerning the Chinese and...',
'text_vector': [0.7, 0.4, 0.2, 0.7, 0.8],
'chapter': 'Economy'
}
]
// hightlight-end
}
في المثال أعلاه، الحقل chunks هو حقل صفيف من حقول الهياكل، ويحتوي كل عنصر من عناصر الهياكل على الحقول الخاصة به، وهي text و text_vector و chapter.
الحدود
أنواع البيانات
عند إنشاء مجموعة، يمكنك استخدام نوع Struct كنوع بيانات للعناصر في حقل Array. ومع ذلك، لا يمكنك إضافة مصفوفة من الهياكل إلى مجموعة موجودة، ولا يدعم Milvus استخدام نوع Struct كنوع بيانات لحقل مجموعة.
تشترك الهياكل في حقل المصفوفة في نفس المخطط، والذي يجب تعريفه عند إنشاء حقل المصفوفة.
يحتوي مخطط Struct على كل من حقول المتجهات والحقول القياسية، كما هو موضح في الجدول التالي:
نوع الحقل
نوع البيانات
المتجه
FLOAT_VECTORعددية
VARCHARINT8/16/32/64FLOATDOUBLEBOOLEANاحتفظ بعدد حقول المتجهات على مستوى المجموعة وفي الهياكل مجتمعة بحيث لا يزيد عن أو يساوي 10.
قابل للفراغ والقيم الافتراضية
حقل صفيف الهياكل غير قابل للإلغاء ولا يقبل أي قيمة افتراضية.
الدالة
لا يمكنك استخدام دالة لاشتقاق حقل متجه من حقل قياسي داخل بنية.
نوع الفهرس والنوع المتري
يجب أن تكون جميع الحقول المتجهة في مجموعة مفهرسة. لفهرسة حقل متجه داخل حقل صفيف من الهياكل، يستخدم ميلفوس قائمة تضمين لتنظيم التضمينات المتجهة في كل عنصر من عناصر الهيكل وفهرسة قائمة التضمين بأكملها ككل.
ويمكنك استخدام
AUTOINDEXأوHNSWكنوع الفهرس وأي نوع قياس مدرج أدناه لإنشاء فهارس لقوائم التضمين في حقل صفيف الهياكل.نوع الفهرس
النوع المتري
الملاحظات
AUTOINDEX(أوHNSW)MAX_SIM_COSINEلتضمين القوائم من الأنواع التالية:
- FLOAT_VECTOR
MAX_SIM_IPMAX_SIM_L2لا تدعم الحقول القياسية في حقل Array of Structs الفهارس.
بيانات Upsert
لا تدعم الهياكل عمليات إعادة إدراج في وضع الدمج. ومع ذلك، لا يزال بإمكانك إجراء عمليات الإدراج في وضع التجاوز لتحديث البيانات في الهياكل. للاطلاع على تفاصيل حول الاختلافات بين عمليات الإدراج في وضع الدمج ووضع التجاوز، راجع Upsert Entities.
التصفية العددية
لا يمكنك استخدام مصفوفة من الهياكل أو أي حقول داخل عنصر الهيكل الخاص بها في تعابير التصفية داخل عمليات البحث والاستعلامات.
إضافة مصفوفة من الهياكل
لاستخدام مصفوفة من الهياكل في Milvus، تحتاج إلى تحديد حقل مصفوفة عند إنشاء مجموعة، وتعيين نوع البيانات لعناصرها إلى Struct. العملية كالتالي:
تعيين نوع بيانات الحقل إلى
DataType.ARRAYعند إضافة الحقل كحقل مصفوفة إلى مخطط المجموعة.قم بتعيين سمة الحقل
element_typeإلىDataType.STRUCTلجعل الحقل مصفوفة من الهياكل.قم بإنشاء مخطط Struct (بنية) وقم بتضمين الحقول المطلوبة. بعد ذلك، قم بالإشارة إلى مخطط الهيكل في سمة الحقل
struct_schema.قم بتعيين سمة الحقل
max_capacityإلى قيمة مناسبة لتحديد الحد الأقصى لعدد الهياكل التي يمكن أن يحتويها كل كيان في هذا الحقل.(اختياري) يمكنك تعيين
mmap.enabledلأي حقل داخل عنصر Struct لموازنة البيانات الساخنة والباردة في Struct.
إليك كيفية تحديد مخطط مجموعة يتضمن مصفوفة من الهياكل:
from pymilvus import MilvusClient, DataType
client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus"
)
schema = client.create_schema()
# add the primary field to the collection
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)
# add some scalar fields to the collection
schema.add_field(field_name="title", datatype=DataType.VARCHAR, max_length=512)
schema.add_field(field_name="author", datatype=DataType.VARCHAR, max_length=512)
schema.add_field(field_name="year_of_publication", datatype=DataType.INT64)
# add a vector field to the collection
schema.add_field(field_name="title_vector", datatype=DataType.FLOAT_VECTOR, dim=5)
# Create a struct schema
struct_schema = client.create_struct_field_schema()
# add a scalar field to the struct
struct_schema.add_field("text", DataType.VARCHAR, max_length=65535)
struct_schema.add_field("chapter", DataType.VARCHAR, max_length=512)
# add a vector field to the struct with mmap enabled
struct_schema.add_field("text_vector", DataType.FLOAT_VECTOR, mmap_enabled=True, dim=5)
# reference the struct schema in an Array field with its
# element type set to `DataType.STRUCT`
schema.add_field("chunks", datatype=DataType.ARRAY, element_type=DataType.STRUCT,
struct_schema=struct_schema, max_capacity=1000)
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.AddFieldReq;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
CreateCollectionReq.CollectionSchema collectionSchema = CreateCollectionReq.CollectionSchema.builder()
.build();
collectionSchema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.autoID(true)
.build());
collectionSchema.addField(AddFieldReq.builder()
.fieldName("title")
.dataType(DataType.VarChar)
.maxLength(512)
.build());
collectionSchema.addField(AddFieldReq.builder()
.fieldName("author")
.dataType(DataType.VarChar)
.maxLength(512)
.build());
collectionSchema.addField(AddFieldReq.builder()
.fieldName("year_of_publication")
.dataType(DataType.Int64)
.build());
collectionSchema.addField(AddFieldReq.builder()
.fieldName("title_vector")
.dataType(DataType.FloatVector)
.dimension(5)
.build());
Map<String, String> params = new HashMap<>();
params.put("mmap_enabled", "true");
collectionSchema.addField(AddFieldReq.builder()
.fieldName("chunks")
.dataType(DataType.Array)
.elementType(DataType.Struct)
.maxCapacity(1000)
.addStructField(AddFieldReq.builder()
.fieldName("text")
.dataType(DataType.VarChar)
.maxLength(65535)
.build())
.addStructField(AddFieldReq.builder()
.fieldName("chapter")
.dataType(DataType.VarChar)
.maxLength(512)
.build())
.addStructField(AddFieldReq.builder()
.fieldName("text_vector")
.dataType(DataType.FloatVector)
.dimension(VECTOR_DIM)
.typeParams(params)
.build())
.build());
// go
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const milvusClient = new MilvusClient("http://localhost:19530");
const schema = [
{
name: "id",
data_type: DataType.INT64,
is_primary_key: true,
auto_id: true,
},
{
name: "title",
data_type: DataType.VARCHAR,
max_length: 512,
},
{
name: "author",
data_type: DataType.VARCHAR,
max_length: 512,
},
{
name: "year_of_publication",
data_type: DataType.INT64,
},
{
name: "title_vector",
data_type: DataType.FLOAT_VECTOR,
dim: 5,
},
{
name: "chunks",
data_type: DataType.ARRAY,
element_type: DataType.STRUCT,
fields: [
{
name: "text",
data_type: DataType.VARCHAR,
max_length: 65535,
},
{
name: "chapter",
data_type: DataType.VARCHAR,
max_length: 512,
},
{
name: "text_vector",
data_type: DataType.FLOAT_VECTOR,
dim: 5,
mmap_enabled: true,
},
],
max_capacity: 1000,
},
];
# restful
SCHEMA='{
"autoID": true,
"fields": [
{
"fieldName": "id",
"dataType": "Int64",
"isPrimary": true
},
{
"fieldName": "title",
"dataType": "VarChar",
"elementTypeParams": { "max_length": "512" }
},
{
"fieldName": "author",
"dataType": "VarChar",
"elementTypeParams": { "max_length": "512" }
},
{
"fieldName": "year_of_publication",
"dataType": "Int64"
},
{
"fieldName": "title_vector",
"dataType": "FloatVector",
"elementTypeParams": { "dim": "5" }
}
],
"structArrayFields": [
{
"name": "chunks",
"description": "Array of document chunks with text and vectors",
"elementTypeParams":{
"max_capacity": 1000
},
"fields": [
{
"fieldName": "text",
"dataType": "VarChar",
"elementTypeParams": { "max_length": "65535" }
},
{
"fieldName": "chapter",
"dataType": "VarChar",
"elementTypeParams": { "max_length": "512" }
},
{
"fieldName": "text_vector",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": "5",
"mmap_enabled": "true"
}
}
]
}
]
}'
توضّح الأسطر المظللة في مثال الشيفرة أعلاه الإجراء لتضمين مصفوفة من الهياكل في مخطط مجموعة.
تعيين بارامترات الفهرس
تكون الفهرسة إلزامية لجميع حقول المتجهات، بما في ذلك حقول المتجهات في المجموعة وتلك المحددة في بنية العنصر.
تختلف معلمات الفهرس القابلة للتطبيق اعتمادًا على نوع الفهرس المستخدم. للحصول على تفاصيل حول معلمات الفهرس القابلة للتطبيق، راجع شرح الفهرس وصفحات التوثيق الخاصة بنوع الفهرس المحدد.
لفهرسة قائمة تضمين، تحتاج إلى تعيين نوع الفهرس الخاص بها إلى AUTOINDEX أو HNSW ، واستخدام MAX_SIM_COSINE كنوع مقياس لـ Milvus لقياس أوجه التشابه بين قوائم التضمين.
# Create index parameters
index_params = client.prepare_index_params()
# Create an index for the vector field in the collection
index_params.add_index(
field_name="title_vector",
index_type="AUTOINDEX",
metric_type="L2",
)
# Create an index for the vector field in the element Struct
index_params.add_index(
field_name="chunks[text_vector]",
index_type="AUTOINDEX",
metric_type="MAX_SIM_COSINE",
)
import io.milvus.v2.common.IndexParam;
List<IndexParam> indexParams = new ArrayList<>();
indexParams.add(IndexParam.builder()
.fieldName("title_vector")
.indexType(IndexParam.IndexType.AUTOINDEX)
.metricType(IndexParam.MetricType.L2)
.build());
indexParams.add(IndexParam.builder()
.fieldName("chunks[text_vector]")
.indexType(IndexParam.IndexType.AUTOINDEX)
.metricType(IndexParam.MetricType.MAX_SIM_COSINE)
.build());
// go
await milvusClient.createCollection({
collection_name: "books",
fields: schema,
});
const indexParams = [
{
field_name: "title_vector",
index_type: "AUTOINDEX",
metric_type: "L2",
},
{
field_name: "chunks[text_vector]",
index_type: "AUTOINDEX",
metric_type: "MAX_SIM_COSINE",
},
];
# restful
INDEX_PARAMS='[
{
"fieldName": "title_vector",
"indexName": "title_vector_index",
"indexType": "AUTOINDEX",
"metricType": "L2"
},
{
"fieldName": "chunks[text_vector]",
"indexName": "chunks_text_vector_index",
"indexType": "AUTOINDEX",
"metricType": "MAX_SIM_COSINE"
}
]'
إنشاء مجموعة
بمجرد أن يصبح المخطط والفهرس جاهزين، يمكنك إنشاء مجموعة تتضمن حقل مصفوفة من الهياكل.
client.create_collection(
collection_name="my_collection",
schema=schema,
index_params=index_params
)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.collection.request.CreateCollectionReq;
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("http://localhost:19530")
.token("root:Milvus")
.build());
CreateCollectionReq requestCreate = CreateCollectionReq.builder()
.collectionName("my_collection")
.collectionSchema(collectionSchema)
.indexParams(indexParams)
.build();
client.createCollection(requestCreate);
// go
await milvusClient.createCollection({
collection_name: "books",
fields: schema,
indexes: indexParams,
});
# restful
curl -X POST "http://localhost:19530/v2/vectordb/collections/create" \
-H "Content-Type: application/json" \
-H "Request-Timeout: 10" \
-d "{
\"collectionName\": \"my_collection\",
\"description\": \"A collection for storing book information with struct array chunks\",
\"schema\": $SCHEMA,
\"indexParams\": $INDEX_PARAMS
}"
إدراج البيانات
بعد إنشاء المجموعة، يمكنك إدراج البيانات التي تتضمن مصفوفات من الهياكل على النحو التالي.
# Sample data
data = {
'title': 'Walden',
'title_vector': [0.1, 0.2, 0.3, 0.4, 0.5],
'author': 'Henry David Thoreau',
'year_of_publication': 1845,
'chunks': [
{
'text': 'When I wrote the following pages, or rather the bulk of them...',
'text_vector': [0.3, 0.2, 0.3, 0.2, 0.5],
'chapter': 'Economy',
},
{
'text': 'I would fain say something, not so much concerning the Chinese and...',
'text_vector': [0.7, 0.4, 0.2, 0.7, 0.8],
'chapter': 'Economy'
}
]
}
# insert data
client.insert(
collection_name="my_collection",
data=[data]
)
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import io.milvus.v2.service.vector.request.InsertReq;
import io.milvus.v2.service.vector.response.InsertResp;
Gson gson = new Gson();
JsonObject row = new JsonObject();
row.addProperty("title", "Walden");
row.add("title_vector", gson.toJsonTree(Arrays.asList(0.1f, 0.2f, 0.3f, 0.4f, 0.5f)));
row.addProperty("author", "Henry David Thoreau");
row.addProperty("year_of_publication", 1845);
JsonArray structArr = new JsonArray();
JsonObject struct1 = new JsonObject();
struct1.addProperty("text", "When I wrote the following pages, or rather the bulk of them...");
struct1.add("text_vector", gson.toJsonTree(Arrays.asList(0.3f, 0.2f, 0.3f, 0.2f, 0.5f)));
struct1.addProperty("chapter", "Economy");
structArr.add(struct1);
JsonObject struct2 = new JsonObject();
struct2.addProperty("text", "I would fain say something, not so much concerning the Chinese and...");
struct2.add("text_vector", gson.toJsonTree(Arrays.asList(0.7f, 0.4f, 0.2f, 0.7f, 0.8f)));
struct2.addProperty("chapter", "Economy");
structArr.add(struct2);
row.add("chunks", structArr);
InsertResp insertResp = client.insert(InsertReq.builder()
.collectionName("my_collection")
.data(Collections.singletonList(row))
.build());
// go
{
id: 0,
title: "Walden",
title_vector: [0.1, 0.2, 0.3, 0.4, 0.5],
author: "Henry David Thoreau",
"year-of-publication": 1845,
chunks: [
{
text: "When I wrote the following pages, or rather the bulk of them...",
text_vector: [0.3, 0.2, 0.3, 0.2, 0.5],
chapter: "Economy",
},
{
text: "I would fain say something, not so much concerning the Chinese and...",
text_vector: [0.7, 0.4, 0.2, 0.7, 0.8],
chapter: "Economy",
},
],
},
];
await milvusClient.insert({
collection_name: "books",
data: data,
});
# restful
curl -X POST "http://localhost:19530/v2/vectordb/entities/insert" \
-H "Content-Type: application/json" \
-H "Request-Timeout: 10" \
-d '{
"collectionName": "my_collection",
"data": [
{
"title": "Walden",
"title_vector": [0.1, 0.2, 0.3, 0.4, 0.5],
"author": "Henry David Thoreau",
"year_of_publication": 1845,
"chunks": [
{
"text": "When I wrote the following pages, or rather the bulk of them...",
"text_vector": [0.3, 0.2, 0.3, 0.2, 0.5],
"chapter": "Economy"
},
{
"text": "I would fain say something, not so much concerning the Chinese and...",
"text_vector": [0.7, 0.4, 0.2, 0.7, 0.8],
"chapter": "Economy"
}
]
}
]
}'
import json
import random
from typing import List, Dict, Any
# Real classic books (title, author, year)
BOOKS = [
("Pride and Prejudice", "Jane Austen", 1813),
("Moby Dick", "Herman Melville", 1851),
("Frankenstein", "Mary Shelley", 1818),
("The Picture of Dorian Gray", "Oscar Wilde", 1890),
("Dracula", "Bram Stoker", 1897),
("The Adventures of Sherlock Holmes", "Arthur Conan Doyle", 1892),
("Alice's Adventures in Wonderland", "Lewis Carroll", 1865),
("The Time Machine", "H.G. Wells", 1895),
("The Scarlet Letter", "Nathaniel Hawthorne", 1850),
("Leaves of Grass", "Walt Whitman", 1855),
("The Brothers Karamazov", "Fyodor Dostoevsky", 1880),
("Crime and Punishment", "Fyodor Dostoevsky", 1866),
("Anna Karenina", "Leo Tolstoy", 1877),
("War and Peace", "Leo Tolstoy", 1869),
("Great Expectations", "Charles Dickens", 1861),
("Oliver Twist", "Charles Dickens", 1837),
("Wuthering Heights", "Emily Brontë", 1847),
("Jane Eyre", "Charlotte Brontë", 1847),
("The Call of the Wild", "Jack London", 1903),
("The Jungle Book", "Rudyard Kipling", 1894),
]
# Common chapter names for classics
CHAPTERS = [
"Introduction", "Prologue", "Chapter I", "Chapter II", "Chapter III",
"Chapter IV", "Chapter V", "Chapter VI", "Chapter VII", "Chapter VIII",
"Chapter IX", "Chapter X", "Epilogue", "Conclusion", "Afterword",
"Economy", "Where I Lived", "Reading", "Sounds", "Solitude",
"Visitors", "The Bean-Field", "The Village", "The Ponds", "Baker Farm"
]
# Placeholder text snippets (mimicking 19th-century prose)
TEXT_SNIPPETS = [
"When I wrote the following pages, or rather the bulk of them...",
"I would fain say something, not so much concerning the Chinese and...",
"It is a truth universally acknowledged, that a single man in possession...",
"Call me Ishmael. Some years ago—never mind how long precisely...",
"It was the best of times, it was the worst of times...",
"All happy families are alike; each unhappy family is unhappy in its own way.",
"Whether I shall turn out to be the hero of my own life, or whether that station...",
"You will rejoice to hear that no disaster has accompanied the commencement...",
"The world is too much with us; late and soon, getting and spending...",
"He was an old man who fished alone in a skiff in the Gulf Stream..."
]
def random_vector() -> List[float]:
return [round(random.random(), 1) for _ in range(5)]
def generate_chunk() -> Dict[str, Any]:
return {
"text": random.choice(TEXT_SNIPPETS),
"text_vector": random_vector(),
"chapter": random.choice(CHAPTERS)
}
def generate_record(record_id: int) -> Dict[str, Any]:
title, author, year = random.choice(BOOKS)
num_chunks = random.randint(1, 5) # 1 to 5 chunks per book
chunks = [generate_chunk() for _ in range(num_chunks)]
return {
"title": title,
"title_vector": random_vector(),
"author": author,
"year_of_publication": year,
"chunks": chunks
}
# Generate 1000 records
data = [generate_record(i) for i in range(1000)]
# Insert the generated data
client.insert(collection_name="my_collection", data=data)
بحث متجه مقابل حقل صفيف من الهياكل
يمكنك إجراء عمليات بحث متجهية على حقول المتجهات في مجموعة وفي مصفوفة من الهياكل.
على وجه التحديد، يجب عليك ربط اسم حقل صفيف الهياكل وحقول المتجهات المستهدفة داخل عناصر الهياكل كقيمة للمعلمة anns_field في طلب البحث، واستخدام EmbeddingList لتنظيم متجهات الاستعلام بشكل منظم.
يوفر Milvus EmbeddingList لمساعدتك في تنظيم متجهات الاستعلام لعمليات البحث مقابل قائمة تضمين في مصفوفة من الهياكل بشكل أكثر دقة. يحتوي كل EmbeddingList على تضمين متجه على الأقل ويتوقع عددًا من الكيانات الأعلىK في المقابل.
ومع ذلك، لا يمكن استخدام EmbeddingList إلا في طلبات search() دون البحث عن النطاق أو تجميع معلمات البحث، ناهيك عن طلبات search_iterator().
from pymilvus.client.embedding_list import EmbeddingList
# each query embedding list triggers a single search
embeddingList1 = EmbeddingList()
embeddingList1.add([0.2, 0.9, 0.4, -0.3, 0.2])
embeddingList2 = EmbeddingList()
embeddingList2.add([-0.2, -0.2, 0.5, 0.6, 0.9])
embeddingList2.add([-0.4, 0.3, 0.5, 0.8, 0.2])
# a search with a single embedding list
results = client.search(
collection_name="my_collection",
data=[ embeddingList1 ],
anns_field="chunks[text_vector]",
search_params={"metric_type": "MAX_SIM_COSINE"},
limit=3,
output_fields=["chunks[text]"]
)
import io.milvus.v2.service.vector.request.data.EmbeddingList;
import io.milvus.v2.service.vector.request.data.FloatVec;
EmbeddingList embeddingList1 = new EmbeddingList();
embeddingList1.add(new FloatVec(new float[]{0.2f, 0.9f, 0.4f, -0.3f, 0.2f}));
EmbeddingList embeddingList2 = new EmbeddingList();
embeddingList2.add(new FloatVec(new float[]{-0.2f, -0.2f, 0.5f, 0.6f, 0.9f}));
embeddingList2.add(new FloatVec(new float[]{-0.4f, 0.3f, 0.5f, 0.8f, 0.2f}));
Map<String, Object> params = new HashMap<>();
params.put("metric_type", "MAX_SIM_COSINE");
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("my_collection")
.annsField("chunks[text_vector]")
.data(Collections.singletonList(embeddingList1))
.searchParams(params)
.limit(3)
.outputFields(Collections.singletonList("chunks[text]"))
.build());
// go
const embeddingList1 = [[0.2, 0.9, 0.4, -0.3, 0.2]];
const embeddingList2 = [
[-0.2, -0.2, 0.5, 0.6, 0.9],
[-0.4, 0.3, 0.5, 0.8, 0.2],
];
const results = await milvusClient.search({
collection_name: "books",
data: embeddingList1,
anns_field: "chunks[text_vector]",
search_params: { metric_type: "MAX_SIM_COSINE" },
limit: 3,
output_fields: ["chunks[text]"],
});
# restful
embeddingList1='[[0.2,0.9,0.4,-0.3,0.2]]'
embeddingList2='[[-0.2,-0.2,0.5,0.6,0.9],[-0.4,0.3,0.5,0.8,0.2]]'
curl -X POST "http://localhost:19530/v2/vectordb/entities/search" \
-H "Content-Type: application/json" \
-H "Request-Timeout: 10" \
-d "{
\"collectionName\": \"my_collection\",
\"data\": [$embeddingList1],
\"annsField\": \"chunks[text_vector]\",
\"searchParams\": {\"metric_type\": \"MAX_SIM_COSINE\"},
\"limit\": 3,
\"outputFields\": [\"chunks[text]\"]
}"
يستخدم طلب البحث أعلاه chunks[text_vector] للإشارة إلى الحقل text_vector في عناصر الهيكل. يمكنك استخدام هذه الصيغة لتعيين المعلمات anns_field و output_fields.
سيكون الناتج قائمة بالكيانات الثلاثة الأكثر تشابهًا.
# [
# [
# {
# 'id': 461417939772144945,
# 'distance': 0.9675756096839905,
# 'entity': {
# 'chunks': [
# {'text': 'The world is too much with us; late and soon, getting and spending...'},
# {'text': 'All happy families are alike; each unhappy family is unhappy in its own way.'}
# ]
# }
# },
# {
# 'id': 461417939772144965,
# 'distance': 0.9555778503417969,
# 'entity': {
# 'chunks': [
# {'text': 'Call me Ishmael. Some years ago—never mind how long precisely...'},
# {'text': 'He was an old man who fished alone in a skiff in the Gulf Stream...'},
# {'text': 'When I wrote the following pages, or rather the bulk of them...'},
# {'text': 'It was the best of times, it was the worst of times...'},
# {'text': 'The world is too much with us; late and soon, getting and spending...'}
# ]
# }
# },
# {
# 'id': 461417939772144962,
# 'distance': 0.9469035863876343,
# 'entity': {
# 'chunks': [
# {'text': 'Call me Ishmael. Some years ago—never mind how long precisely...'},
# {'text': 'The world is too much with us; late and soon, getting and spending...'},
# {'text': 'He was an old man who fished alone in a skiff in the Gulf Stream...'},
# {'text': 'Call me Ishmael. Some years ago—never mind how long precisely...'},
# {'text': 'The world is too much with us; late and soon, getting and spending...'}
# ]
# }
# }
# ]
# ]
يمكنك أيضًا تضمين قوائم تضمين متعددة في المعلمة data لاسترداد نتائج البحث لكل من قوائم التضمين هذه.
# a search with multiple embedding lists
results = client.search(
collection_name="my_collection",
data=[ embeddingList1, embeddingList2 ],
anns_field="chunks[text_vector]",
search_params={"metric_type": "MAX_SIM_COSINE"},
limit=3,
output_fields=["chunks[text]"]
)
print(results)
Map<String, Object> params = new HashMap<>();
params.put("metric_type", "MAX_SIM_COSINE");
SearchResp searchResp = client.search(SearchReq.builder()
.collectionName("my_collection")
.annsField("chunks[text_vector]")
.data(Arrays.asList(embeddingList1, embeddingList2))
.searchParams(params)
.limit(3)
.outputFields(Collections.singletonList("chunks[text]"))
.build());
List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (int i = 0; i < searchResults.size(); i++) {
System.out.println("Results of No." + i + " embedding list");
List<SearchResp.SearchResult> results = searchResults.get(i);
for (SearchResp.SearchResult result : results) {
System.out.println(result);
}
}
// go
const results2 = await milvusClient.search({
collection_name: "books",
data: [embeddingList1, embeddingList2],
anns_field: "chunks[text_vector]",
search_params: { metric_type: "MAX_SIM_COSINE" },
limit: 3,
output_fields: ["chunks[text]"],
});
# restful
curl -X POST "http://localhost:19530/v2/vectordb/entities/search" \
-H "Content-Type: application/json" \
-H "Request-Timeout: 10" \
-d "{
\"collectionName\": \"my_collection\",
\"data\": [$embeddingList1, $embeddingList2],
\"annsField\": \"chunks[text_vector]\",
\"searchParams\": {\"metric_type\": \"MAX_SIM_COSINE\"},
\"limit\": 3,
\"outputFields\": [\"chunks[text]\"]
}"
سيكون الناتج قائمة بالكيانات الثلاثة الأكثر تشابهًا لكل قائمة تضمين.
# [
# [
# {
# 'id': 461417939772144945,
# 'distance': 0.9675756096839905,
# 'entity': {
# 'chunks': [
# {'text': 'The world is too much with us; late and soon, getting and spending...'},
# {'text': 'All happy families are alike; each unhappy family is unhappy in its own way.'}
# ]
# }
# },
# {
# 'id': 461417939772144965,
# 'distance': 0.9555778503417969,
# 'entity': {
# 'chunks': [
# {'text': 'Call me Ishmael. Some years ago—never mind how long precisely...'},
# {'text': 'He was an old man who fished alone in a skiff in the Gulf Stream...'},
# {'text': 'When I wrote the following pages, or rather the bulk of them...'},
# {'text': 'It was the best of times, it was the worst of times...'},
# {'text': 'The world is too much with us; late and soon, getting and spending...'}
# ]
# }
# },
# {
# 'id': 461417939772144962,
# 'distance': 0.9469035863876343,
# 'entity': {
# 'chunks': [
# {'text': 'Call me Ishmael. Some years ago—never mind how long precisely...'},
# {'text': 'The world is too much with us; late and soon, getting and spending...'},
# {'text': 'He was an old man who fished alone in a skiff in the Gulf Stream...'},
# {'text': 'Call me Ishmael. Some years ago—never mind how long precisely...'},
# {'text': 'The world is too much with us; late and soon, getting and spending...'}
# ]
# }
# }
# ],
# [
# {
# 'id': 461417939772144663,
# 'distance': 1.9761409759521484,
# 'entity': {
# 'chunks': [
# {'text': 'It was the best of times, it was the worst of times...'},
# {'text': 'It is a truth universally acknowledged, that a single man in possession...'},
# {'text': 'Whether I shall turn out to be the hero of my own life, or whether that station...'},
# {'text': 'He was an old man who fished alone in a skiff in the Gulf Stream...'}
# ]
# }
# },
# {
# 'id': 461417939772144692,
# 'distance': 1.974656581878662,
# 'entity': {
# 'chunks': [
# {'text': 'It is a truth universally acknowledged, that a single man in possession...'},
# {'text': 'Call me Ishmael. Some years ago—never mind how long precisely...'}
# ]
# }
# },
# {
# 'id': 461417939772144662,
# 'distance': 1.9406685829162598,
# 'entity': {
# 'chunks': [
# {'text': 'It is a truth universally acknowledged, that a single man in possession...'}
# ]
# }
# }
# ]
# ]
في المثال البرمجي أعلاه، embeddingList1 هي قائمة تضمين من متجه واحد، بينما embeddingList2 تحتوي على متجهين. يقوم كل منهما بتشغيل طلب بحث منفصل ويتوقع قائمة بالكيانات الأكثر تشابهًا من بين الكيانات المتشابهة.
الخطوات التالية
يمثل تطوير صفيف أصلي من نوع بيانات Structs تقدمًا كبيرًا في قدرة ميلفوس على التعامل مع بنيات البيانات المعقدة. لفهم حالات الاستخدام بشكل أفضل وتعظيم هذه الميزة الجديدة، ننصحك بقراءة تصميم المخطط باستخدام مصفوفة الهياكل.