ميلفوس 2.0 - لمحة عن الميزات الجديدة
لقد مر نصف عام منذ الإصدار الأول المرشح للإصدار الأول من Milvus 2.0. الآن نحن فخورون بالإعلان عن التوفر العام للإصدار العام لـ Milvus 2.0. يرجى متابعتي خطوة بخطوة لإلقاء نظرة على بعض الميزات الجديدة التي يدعمها ميلفوس.
حذف الكيانات
يدعم Milvus 2.0 حذف الكيانات، مما يسمح للمستخدمين بحذف المتجهات استنادًا إلى المفاتيح الأساسية (المعرفات) للمتجهات. لن يكونوا قلقين بشأن البيانات المنتهية الصلاحية أو غير الصالحة بعد الآن. لنجرب ذلك.
- اتصل بـ Milvus، وأنشئ مجموعة جديدة، وأدخل 300 صف من المتجهات ذات الـ 128 بُعدًا التي تم إنشاؤها عشوائيًا.
from pymilvus import connections, utility, Collection, DataType, FieldSchema, CollectionSchema
# connect to milvus
host = 'x.x.x.x'
connections.add_connection(default={"host": host, "port": 19530})
connections.connect(alias='default')
# create a collection with customized primary field: id_field
dim = 128
id_field = FieldSchema(name="cus_id", dtype=DataType.INT64, is_primary=True)
age_field = FieldSchema(name="age", dtype=DataType.INT64, description="age")
embedding_field = FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=dim)
schema = CollectionSchema(fields=[id_field, age_field, embedding_field],
auto_id=False, description="hello MilMil")
collection_name = "hello_milmil"
collection = Collection(name=collection_name, schema=schema)
import random
# insert data with customized ids
nb = 300
ids = [i for i in range(nb)]
ages = [random.randint(20, 40) for i in range(nb)]
embeddings = [[random.random() for _ in range(dim)] for _ in range(nb)]
entities = [ids, ages, embeddings]
ins_res = collection.insert(entities)
print(f"insert entities primary keys: {ins_res.primary_keys}")
insert entities primary keys: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299]
- قبل الشروع في الحذف، تحقق من وجود الكيانات التي تريد حذفها عن طريق البحث أو الاستعلام، وقم بذلك مرتين للتأكد من أن النتيجة موثوقة.
# search
nq = 10
search_vec = [[random.random() for _ in range(dim)] for _ in range(nq)]
search_params = {"metric_type": "L2", "params": {"nprobe": 16}}
limit = 3
# search 2 times to verify the vector persists
for i in range(2):
results = collection.search(search_vec, embedding_field.name, search_params, limit)
ids = results[0].ids
print(f"search result ids: {ids}")
expr = f"cus_id in {ids}"
# query to verify the ids exist
query_res = collection.query(expr)
print(f"query results: {query_res}")
search result ids: [76, 2, 246]
query results: [{'cus_id': 246}, {'cus_id': 2}, {'cus_id': 76}]
search result ids: [76, 2, 246]
query results: [{'cus_id': 246}, {'cus_id': 2}, {'cus_id': 76}]
- احذف الكيان الذي يحمل الرقم cus_id 76، ثم ابحث واستعلام عن هذا الكيان.
print(f"trying to delete one vector: id={ids[0]}")
collection.delete(expr=f"cus_id in {[ids[0]]}")
results = collection.search(search_vec, embedding_field.name, search_params, limit)
ids = results[0].ids
print(f"after deleted: search result ids: {ids}")
expr = f"cus_id in {ids}"
# query to verify the id exists
query_res = collection.query(expr)
print(f"after deleted: query res: {query_res}")
print("completed")
trying to delete one vector: id=76
after deleted: search result ids: [76, 2, 246]
after deleted: query res: [{'cus_id': 246}, {'cus_id': 2}, {'cus_id': 76}]
completed
لماذا لا يزال الكيان المحذوف قابلاً للاسترجاع؟ إذا كنت قد راجعت الكود المصدري لـ Milvus، فستجد أن الحذف داخل Milvus غير متزامن ومنطقي، مما يعني أن الكيانات لن يتم حذفها فعليًا. وبدلاً من ذلك، سيتم إرفاقها بعلامة "محذوفة" بحيث لا تسترجعها أي طلبات بحث أو استعلام. بالإضافة إلى ذلك، يبحث ميلفوس تحت مستوى اتساق الثبات المحدود بشكل افتراضي. لذلك، تظل الكيانات المحذوفة قابلة للاسترجاع قبل مزامنة البيانات في عقدة البيانات وعقدة الاستعلام. حاول البحث أو الاستعلام عن الكيان المحذوف بعد بضع ثوانٍ، وستجد أنه لم يعد موجودًا في النتيجة.
expr = f"cus_id in {[76, 2, 246]}"
# query to verify the id exists
query_res = collection.query(expr)
print(f"after deleted: query res: {query_res}")
print("completed")
after deleted: query res: [{'cus_id': 246}, {'cus_id': 2}]
completed
مستوى الاتساق
توضح لنا التجربة أعلاه كيف يؤثر مستوى الاتساق على الرؤية الفورية للبيانات المحذوفة حديثًا. يمكن للمستخدمين ضبط مستوى الاتساق في Milvus بمرونة لتكييفه مع سيناريوهات الخدمة المختلفة. يدعم ميلفوس 2.0 أربعة مستويات من الاتساق:
CONSISTENCY_STRONG
:GuaranteeTs
يتم تعيين على أنه مطابق لأحدث طابع زمني للنظام، وتنتظر عقد الاستعلام حتى ينتقل وقت الخدمة إلى أحدث طابع زمني للنظام، ثم تعالج طلب البحث أو الاستعلام.CONSISTENCY_EVENTUALLY
::GuaranteeTs
يتم تعيين أصغر بشكل غير ملحوظ من الطابع الزمني الأحدث للنظام لتخطي التحقق من الاتساق. تبحث عقد الاستعلام على الفور في طريقة عرض البيانات الموجودة.CONSISTENCY_BOUNDED
:GuaranteeTs
يتم تعيين أصغر نسبياً من الطابع الزمني الأحدث للنظام، وتقوم عقد الاستعلام بالبحث على طريقة عرض بيانات مقبولة وأقل تحديثاً.CONSISTENCY_SESSION
: يستخدم العميل الطابع الزمني لآخر عملية كتابة كـGuaranteeTs
، بحيث يمكن لكل عميل على الأقل استرجاع البيانات التي أدخلها بنفسه.
في إصدار RC السابق، يتبنى ميلفوس التناسق القوي باعتباره التناسق الافتراضي. ومع ذلك، مع الأخذ في الاعتبار حقيقة أن معظم المستخدمين أقل تطلبًا فيما يتعلق بالاتساق من الأداء، فإن ميلفوس يغير الاتساق الافتراضي إلى اتساق محدود الثبات، والذي يمكن أن يوازن متطلباتهم إلى حد كبير. في المستقبل، سنقوم في المستقبل بتحسين تكوين ضمانات الاتساق المحدود بشكل أكبر، وهو ما يمكن تحقيقه فقط أثناء إنشاء المجموعة في الإصدار الحالي. لمزيد من المعلومات حول GuaranteeTs
، راجع الطابع الزمني للضمان في طلبات البحث.
هل سيؤدي انخفاض الاتساق إلى أداء أفضل؟ لا يمكنك أبدًا معرفة الإجابة حتى تجرب ذلك.
- قم بتعديل الكود أعلاه لتسجيل زمن انتقال البحث.
for i in range(5):
start = time.time()
results = collection.search(search_vec, embedding_field.name, search_params, limit)
end = time.time()
print(f"search latency: {round(end-start, 4)}")
ids = results[0].ids
print(f"search result ids: {ids}")
- ابحث بنفس مقياس البيانات والمعلمات باستثناء أنه تم تعيين
consistency_level
على أنهCONSISTENCY_STRONG
.
collection_name = "hello_milmil_consist_strong"
collection = Collection(name=collection_name, schema=schema,
consistency_level=CONSISTENCY_STRONG)
search latency: 0.3293
search latency: 0.1949
search latency: 0.1998
search latency: 0.2016
search latency: 0.198
completed
- ابحث في مجموعة مع تعيين
consistency_level
على أنهCONSISTENCY_BOUNDED
.
collection_name = "hello_milmil_consist_bounded"
collection = Collection(name=collection_name, schema=schema,
consistency_level=CONSISTENCY_BOUNDED)
search latency: 0.0144
search latency: 0.0104
search latency: 0.0107
search latency: 0.0104
search latency: 0.0102
completed
- من الواضح أن متوسط زمن انتقال البحث في المجموعة
CONSISTENCY_BOUNDED
أقصر بـ 200 مللي ثانية من ذلك في المجموعةCONSISTENCY_STRONG
.
هل الكيانات المحذوفة غير مرئية على الفور إذا تم تعيين مستوى الاتساق على أنه قوي؟ الإجابة هي نعم. لا يزال بإمكانك تجربة ذلك بنفسك.
التسليم
عند العمل مع مجموعة البيانات المتدفقة، اعتاد العديد من المستخدمين على إنشاء فهرس وتحميل المجموعة قبل إدراج البيانات فيها. في الإصدارات السابقة من Milvus، كان يتعين على المستخدمين تحميل المجموعة يدويًا بعد بناء الفهرس لاستبدال البيانات الأولية بالفهرس، وهو أمر بطيء وشاق. تسمح ميزة التسليم اليدوي لـ Milvus 2.0 بتحميل الجزء المفهرس تلقائيًا لاستبدال البيانات المتدفقة التي تصل إلى عتبات معينة من الفهرسة، مما يحسن أداء البحث بشكل كبير.
- بناء الفهرس وتحميل المجموعة قبل إدراج المزيد من الكيانات.
# index
index_params = {"index_type": "IVF_SQ8", "metric_type": "L2", "params": {"nlist": 64}}
collection.create_index(field_name=embedding_field.name, index_params=index_params)
# load
collection.load()
- أدخل 50,000 صف من الكيانات 200 مرة (يتم استخدام نفس دفعات المتجهات من أجل الراحة، ولكن هذا لن يؤثر على النتيجة).
import random
# insert data with customized ids
nb = 50000
ids = [i for i in range(nb)]
ages = [random.randint(20, 40) for i in range(nb)]
embeddings = [[random.random() for _ in range(dim)] for _ in range(nb)]
entities = [ids, ages, embeddings]
for i in range(200):
ins_res = collection.insert(entities)
print(f"insert entities primary keys: {ins_res.primary_keys}")
- تحقق من معلومات مقطع التحميل في عقدة الاستعلام أثناء الإدراج وبعده.
# did this in another python console
utility.get_query_segment_info("hello_milmil_handoff")
- ستجد أن جميع المقاطع المختومة المحملة في عقدة الاستعلام مفهرسة.
[segmentID: 430640405514551298
collectionID: 430640403705757697
partitionID: 430640403705757698
mem_size: 394463520
num_rows: 747090
index_name: "_default_idx"
indexID: 430640403745079297
nodeID: 7
state: Sealed
, segmentID: 430640405514551297
collectionID: 430640403705757697
partitionID: 430640403705757698
mem_size: 397536480
num_rows: 752910
index_name: "_default_idx"
indexID: 430640403745079297
nodeID: 7
state: Sealed
...
ما هو أكثر من ذلك
بالإضافة إلى الوظائف المذكورة أعلاه، تم تقديم ميزات جديدة مثل ضغط البيانات وموازنة التحميل الديناميكي والمزيد في Milvus 2.0. يرجى الاستمتاع برحلتك الاستكشافية مع ميلفوس!
في المستقبل القريب، سوف نشارككم سلسلة من المدونات التي ستعرض تصميم الميزات الجديدة في Milvus 2.0.
تجدنا على
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word