🚀 Coba Zilliz Cloud, Milvus yang sepenuhnya terkelola, secara gratis—rasakan performa 10x lebih cepat! Coba Sekarang>>

milvus-logo
LFAI
  • Home
  • Blog
  • Milvus 2.0 - Sekilas tentang Fitur Baru

Milvus 2.0 - Sekilas tentang Fitur Baru

  • Engineering
January 27, 2022
Yanliang Qiao

Sudah setengah tahun sejak kandidat rilis pertama Milvus 2.0. Sekarang kami dengan bangga mengumumkan ketersediaan Milvus 2.0 secara umum. Silakan ikuti langkah demi langkah untuk melihat sekilas beberapa fitur baru yang didukung oleh Milvus.

Penghapusan entitas

Milvus 2.0 mendukung penghapusan entitas, yang memungkinkan pengguna untuk menghapus vektor berdasarkan kunci utama (ID) dari vektor. Mereka tidak akan khawatir lagi dengan data yang sudah kadaluarsa atau tidak valid. Mari kita coba.

  1. Hubungkan ke Milvus, buat koleksi baru, dan masukkan 300 baris vektor 128 dimensi yang dibuat secara acak.
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]
  1. Sebelum melanjutkan ke penghapusan, periksa entitas yang ingin Anda hapus dengan pencarian atau kueri, dan lakukan dua kali untuk memastikan hasilnya dapat diandalkan.
# 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}]
  1. Hapus entitas dengan cus_id 76, lalu cari dan kueri entitas ini.
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

Mengapa entitas yang telah dihapus masih dapat diambil? Jika Anda telah memeriksa kode sumber Milvus, Anda akan menemukan bahwa penghapusan di dalam Milvus bersifat asinkron dan logis, yang berarti entitas tidak akan dihapus secara fisik. Sebaliknya, mereka akan dilampirkan dengan tanda "dihapus" sehingga tidak ada permintaan pencarian atau permintaan kueri yang akan mengambilnya. Selain itu, Milvus mencari di bawah tingkat konsistensi Bounded Staleness secara default. Oleh karena itu, entitas yang dihapus masih dapat diambil sebelum data disinkronkan di node data dan node kueri. Coba cari atau kueri entitas yang dihapus setelah beberapa detik, Anda akan menemukan entitas tersebut tidak ada lagi dalam hasil pencarian.

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

Tingkat konsistensi

Percobaan di atas menunjukkan kepada kita bagaimana tingkat konsistensi mempengaruhi visibilitas langsung dari data yang baru saja dihapus. Pengguna dapat mengatur tingkat konsistensi untuk Milvus secara fleksibel untuk menyesuaikannya dengan berbagai skenario layanan. Milvus 2.0 mendukung empat tingkat konsistensi:

  • CONSISTENCY_STRONG: GuaranteeTs diatur sebagai identik dengan stempel waktu sistem terbaru, dan node kueri menunggu hingga waktu layanan berlanjut ke stempel waktu sistem terbaru, dan kemudian memproses permintaan pencarian atau kueri.
  • CONSISTENCY_EVENTUALLY: GuaranteeTs disetel lebih kecil secara signifikan daripada stempel waktu sistem terbaru untuk melewati pemeriksaan konsistensi. Node kueri langsung mencari pada tampilan data yang ada.
  • CONSISTENCY_BOUNDED: GuaranteeTs disetel relatif lebih kecil dari stempel waktu sistem terbaru, dan simpul kueri mencari pada tampilan data yang masih dapat ditoleransi dan kurang diperbarui.
  • CONSISTENCY_SESSION: Klien menggunakan timestamp dari operasi penulisan terakhir sebagai GuaranteeTs, sehingga setiap klien setidaknya dapat mengambil data yang dimasukkan dengan sendirinya.

Pada rilis RC sebelumnya, Milvus mengadopsi Strong sebagai konsistensi default. Namun, dengan mempertimbangkan fakta bahwa sebagian besar pengguna tidak terlalu menuntut konsistensi dibandingkan dengan performa, Milvus mengubah konsistensi default menjadi Bounded Staleness, yang dapat menyeimbangkan kebutuhan mereka secara lebih baik. Di masa mendatang, kami akan lebih mengoptimalkan konfigurasi dari GuaranteeTs, yang hanya dapat dicapai selama pembuatan koleksi dalam rilis saat ini. Untuk informasi lebih lanjut tentang GuaranteeTs, lihat Cap Waktu Jaminan dalam Permintaan Pencarian.

Apakah konsistensi yang lebih rendah akan menghasilkan kinerja yang lebih baik? Anda tidak akan pernah tahu jawabannya sampai Anda mencobanya.

  1. Ubah kode di atas untuk mencatat latensi pencarian.
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}")
  1. Cari dengan skala data dan parameter yang sama kecuali consistency_level ditetapkan sebagai 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
  1. Cari dalam koleksi dengan consistency_level yang ditetapkan sebagai 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
  1. Jelas, latensi pencarian rata-rata di koleksi CONSISTENCY_BOUNDED lebih pendek 200ms dibandingkan dengan koleksi CONSISTENCY_STRONG.

Apakah entitas yang dihapus langsung tidak terlihat jika tingkat konsistensi ditetapkan sebagai Kuat? Jawabannya adalah Ya. Anda masih bisa mencoba hal ini sendiri.

Handoff

Bekerja dengan kumpulan data streaming, banyak pengguna yang terbiasa membangun indeks dan memuat koleksi sebelum memasukkan data ke dalamnya. Pada rilis Milvus sebelumnya, pengguna harus memuat koleksi secara manual setelah pembuatan indeks untuk mengganti data mentah dengan indeks, yang mana hal ini lambat dan melelahkan. Fitur handoff memungkinkan Milvus 2.0 untuk secara otomatis memuat segmen yang diindeks untuk menggantikan data streaming yang mencapai ambang batas pengindeksan tertentu, sehingga meningkatkan kinerja pencarian.

  1. Bangun indeks dan muat koleksi sebelum memasukkan lebih banyak entitas.
# 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()
  1. Masukkan 50.000 baris entitas sebanyak 200 kali (kumpulan vektor yang sama digunakan demi kenyamanan, tetapi ini tidak akan memengaruhi hasil).
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}")
  1. Periksa informasi segmen pemuatan di simpul kueri selama dan setelah penyisipan.
# did this in another python console
utility.get_query_segment_info("hello_milmil_handoff")
  1. Anda akan menemukan bahwa semua segmen yang disegel yang dimuat ke simpul kueri diindeks.
[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
...

Terlebih lagi

Selain fungsi-fungsi di atas, fitur-fitur baru seperti Pemadatan Data, Keseimbangan Beban Dinamis, dan banyak lagi telah diperkenalkan ke dalam Milvus 2.0. Selamat menikmati perjalanan eksplorasi Anda dengan Milvus!

Dalam waktu dekat, kami akan membagikan kepada Anda serangkaian blog yang memperkenalkan desain fitur-fitur baru di Milvus 2.0.

Temukan kami di:

Try Managed Milvus for Free

Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.

Get Started

Like the article? Spread the word

Terus Baca