Pertandingan AnggotaCompatible with Milvus v3.0.2+
Gambaran Umum
Pencocokan keanggotaan menyaring entitas dengan memeriksa apakah nilai bidang skalar termasuk dalam himpunan yang disediakan oleh pemanggil. Klien membangun blob filter keanggotaan biner yang ringkas dan meneruskannya sebagai nilai templat ekspresi.
Fitur ini menggantikan daftar " IN [...] " yang besar. Filter " IN " menserialisasikan setiap anggota ke dalam permintaan, sehingga himpunan anggota yang cukup besar dapat melebihi batas penerimaan gRPC proxy. Dengan " membership_match", proxy memvalidasi blob tersebut dan menyematkannya ke dalam rencana kueri tanpa perlu membangun ulang daftar anggota.
Alur kerja Membership Match: klien membuat blob yang dapat digunakan kembali, proxy memvalidasinya, dan QueryNodes mengevaluasinya.
Diagram tersebut menunjukkan pembagian tugas yang tetap. Klien membuat blob satu kali dan menggunakannya kembali di seluruh permintaan; proxy memvalidasi batas amplop dan ukuran serta menyematkan blob ke dalam rencana kueri secara verbatim; dan QueryNodes mengevaluasi rencana tersebut terhadap data mentah atau indeks.
Operator ini memiliki dua pengkodean dengan jaminan kebenaran yang berbeda:
- Bloom (
type=bloom): Keanggotaan perkiraan. Hasil positif palsu mungkin terjadi; hasil negatif palsu tidak diharapkan dari filter yang valid. Penggunaan umum: filter audiens atau pengecualian dengan volume tinggi di mana hasil positif palsu sesekali dapat diterima. - Roaring (
type=roaring): Keanggotaan yang tepat untuk nilai bilangan bulat. Penggunaan umum: ACL, visibilitas penyewa, filter kepatuhan, dan operasi penghapusan berdasarkan kumpulan ID.
Jangan gunakan keanggotaan Bloom untuk keputusan otorisasi atau penghapusan yang merusak. Hasil positif palsu dapat mengekspos entitas atau menghapus entitas yang tidak termasuk dalam kumpulan yang dimaksud.
Daftar periksa operasional
- Pastikan tipe bidang target dan buat blob dari domain nilai yang sama.
- Pilih Bloom hanya jika hasil positif palsu dapat diterima.
- Pilih Roaring untuk operasi ACL, kepatuhan, isolasi penyewa, dan penghapusan.
- Buat blob besar sekali saja dan gunakan kembali; jangan buat ulang di setiap permintaan.
- Hitung ukuran blob dalam byte yang diserialisasikan, bukan berdasarkan jumlah anggota.
- Pada kluster dengan versi campuran, selesaikan peningkatan bertahap (rolling upgrade), mulai dari proxy terlebih dahulu, sebelum mengaktifkan "
membership_match". - Uji ekspresi tersebut pada koleksi non-produksi sebelum mengaktifkan alur kerja yang bersifat destruktif.
Sintaks ekspresi
membership_match(<field>, {<template>}, type=bloom)
membership_match(<field>, {<template>}, type=roaring)
membership_match(<field>, {<template>})
not membership_match(<field>, {<template>}, type=bloom)
Argumen kedua adalah penanda tempat templat. SDK menyediakan nilai penanda tempat sebagai objek ` bytes ` protobuf yang berisi blob filter yang dibangun oleh klien. Pastikan ` type ` dinyatakan secara eksplisit dalam ekspresi produksi agar kontrak kebenaran yang dimaksud terlihat dalam kode dan log.
Argumen ` type ` bersifat opsional. Setiap blob membawa header magis yang mendeskripsikan dirinya sendiri, ` MBF1 ` untuk Bloom dan ` MRB1 ` untuk Roaring, dan server mendeteksi header tersebut saat ` type ` diabaikan. ` type ` eksplisit yang bertentangan dengan header blob akan ditolak sebagai kesalahan permintaan, sedangkan header yang tidak dikenal atau terpotong mengakibatkan status fail-closed.
Pilih pengkodean
Gunakan Bloom jika false positive dapat diterima. Bloom mendukung bidang bilangan bulat bertanda (INT8/16/32/64), bidang VARCHAR, dan jalur JSON. Filter Bloom bukanlah daftar izinkan yang tepat.
fpr (false-positive rate) adalah probabilitas bahwa filter Bloom melaporkan suatu nilai sebagai anggota padahal nilai tersebut tidak pernah dimasukkan: fpr=0.005 berarti kira-kira satu nilai non-anggota dari setiap 200 nilai dilaporkan secara keliru sebagai ada. FPR yang lebih rendah menghasilkan blob yang lebih besar.
Gunakan Roaring jika setiap pencocokan harus tepat. Roaring hanya menerima kolom bilangan bulat bertanda; anggota diperluas tanda menjadi INT64 sebelum serialisasi, sehingga INT8 -1 dan INT64 -1 dianggap sebagai anggota yang sama. Jangan gunakan metode ini untuk UUID atau kolom string lainnya.
| Dimensi | Bloom (type=bloom) | Roaring (type=roaring) |
|---|---|---|
| Presisi | Perkiraan; kemungkinan hasil positif palsu; tidak ada hasil negatif palsu | Tepat; tidak ada hasil positif palsu dan tidak ada hasil negatif palsu |
| Kolom | INT8/16/32/64, VARCHAR, jalur JSON | Hanya INT8/16/32/64 bertanda |
| Ukuran Blob | Jumlah anggota dan FPR; sekitar 11 bit per anggota pada FPR 0,005; struktur berkuasa dua | Distribusi nilai; himpunan padat terkompresi menjadi ukuran yang jauh lebih kecil; nilai acak 64-bit mencapai batas maksimum wadah sebesar 262.144 |
| Penghapusan | Ditolak pada saat penguraian | Diizinkan |
| Penggunaan umum | Filter audiens dan pengecualian | ACL, kepatuhan, isolasi penyewa, penghapusan berdasarkan kumpulan ID |
JalurJSON bertipe ketat, baris demi baris: string JSON diperiksa sebagai nilai VARCHAR, bilangan bulat JSON sebagai nilai INT64, dan bilangan ganda JSON tidak pernah cocok dengan anggota bilangan bulat, tidak seperti IN yang tepat, di mana 5,0 sama dengan 5. Jika penulis Anda mengenkode bilangan bulat sebagai float, normalisasikan saat penulisan atau gunakan bidang skalar bertipe.
Untuk kedua pengkodean tersebut, buat kumpulan anggota dari domain nilai yang sama dengan bidang target. Jangan membangun filter Bloom dari string "10086" dan menerapkannya ke bidang INT64. Header blob mencatat domain nilai yang dimasukkan, dan blob dengan domain yang salah akan ditolak oleh proxy dengan kesalahan parameter, bukan diam-diam tidak cocok dengan apa pun. Gunakan kembali blob yang sudah dibuat di seluruh permintaan daripada membangunnya ulang untuk setiap kueri.
Untuk himpunan dengan beberapa ribu anggota atau kurang, " IN " biasa tetap menjadi opsi paling sederhana. Server tidak memilih antara IN, Bloom, dan Roaring. Pemilihan enkoding menjadi tanggung jawab pemanggil.
Untuk memilih pengkodean:
- Tentukan apakah beban kerja dapat mentoleransi hasil positif palsu. Jika tidak, Bloom bukanlah pilihan yang tepat.
- Untuk keanggotaan yang tepat, gunakan Roaring dengan bidang bilangan bulat bertanda. Nilai yang padat atau terkluster akan terkompresi menjadi blob terkecil.
- Periksa batas ukuran. Nilai acak seragam 64-bit mungkin melebihi batas maksimum kontainer sebesar 262.144 atau batas ukuran. Jika demikian, gunakan daftar IN tradisional yang sesuai dengan batas permintaan.
- Untuk keanggotaan yang tepat pada bidang non-bilangan bulat, gunakan IN. Tidak ada pengkodean keanggotaan yang tepat untuk bidang-bidang ini.
Pencocokan keanggotaan tidak tersedia melalui API HTTP RESTful. Parameter templat ekspresi HTTP hanya menerima nilai bool, angka, string, dan array; tidak ada tipe biner bytes untuk blob. Gunakan SDK berbasis gRPC untuk mengirimkan blob keanggotaan.
Pola permintaan SDK
Potongan kode berikut berfokus pada pembuatan blob keanggotaan dan meneruskannya sebagai parameter templat filter. Potongan kode ini mengasumsikan bahwa koleksi dan bidang sudah ada dan dimuat, klien SDK sudah terhubung, serta vektor kueri, daftar anggota, dan variabel lain yang dirujuk telah didefinisikan. Pengaturan koleksi dan kerangka aplikasi lengkap tidak disertakan.
from pymilvus import MilvusClient, build_bloom_filter, build_roaring_bitmap
client = MilvusClient(uri="http://localhost:19530")
bloom_blob = build_bloom_filter(["creator-a", "creator-b"], fpr=0.005)
client.search(collection_name="posts", data=[query_vector], anns_field="embedding", limit=10,
filter="membership_match(creator_id, {members}, type=bloom)",
filter_params={"members": bloom_blob})
roaring_blob = build_roaring_bitmap([1001, 1002, 1003])
client.query(collection_name="docs", filter="membership_match(user_id, {members}, type=roaring)",
filter_params={"members": roaring_blob}, output_fields=["user_id", "title"])
bloomBlob, err := milvusclient.NewBloomFilterBlob([]int64{1001, 1002}, fpr)
if err != nil { return err }
search := milvusclient.NewSearchOption("posts", topK, vectors).
WithFilter("membership_match(creator_id, {members}, type=bloom)").
WithTemplateParam("members", bloomBlob)
roaringBlob, err := milvusclient.NewRoaringBitmapBlob([]int64{1001, 1002})
if err != nil { return err }
query := milvusclient.NewQueryOption("docs").
WithFilter("membership_match(user_id, {members}, type=roaring)").
WithTemplateParam("members", roaringBlob)
byte[] bloomBlob = BloomFilterUtils.buildBloomFilter(userIds, BloomFilterUtils.DEFAULT_FPR);
QueryReq request = QueryReq.builder().collectionName("docs")
.filter("membership_match(user_id, {members}, type=bloom)")
.filterTemplateValues(Collections.singletonMap("members", bloomBlob)).build();
byte[] roaringBlob = RoaringBitmapUtils.buildRoaringBitmap(userIds);
const bloomBlob = buildBloomFilter(userIds);
await client.query({ collection_name: 'docs',
filter: 'membership_match(user_id, {members}, type=bloom)',
exprValues: { members: bloomBlob } });
const roaringBlob = buildRoaringBitmap(integerIds);
Hapus dengan Roaring
Gunakan blob Roaring yang tepat saat menghapus entitas yang dipilih oleh himpunan ID integer eksternal. Periksa himpunan anggota dan tipe bidang koleksi sebelum menjalankan perintah hapus. Jangan gunakan Bloom: keanggotaan perkiraan bukanlah predikat hapus yang aman, dan bentuk Bloom ditolak dalam ekspresi Hapus pada saat penguraian.
roaring_blob = build_roaring_bitmap([1001, 1002, 1003])
client.delete(collection_name="docs", filter="membership_match(id, {members}, type=roaring)",
filter_params={"members": roaring_blob})
roaringBlob, err := milvusclient.NewRoaringBitmapBlob([]int64{1001, 1002, 1003})
if err != nil { return err }
_, err = client.Delete(ctx, milvusclient.NewDeleteOption("docs").
WithExpr("membership_match(id, {members}, type=roaring)").
WithTemplateParam("members", roaringBlob))
byte[] roaringBlob = RoaringBitmapUtils.buildRoaringBitmap(userIds);
DeleteReq request = DeleteReq.builder().collectionName("docs")
.filter("membership_match(id, {members}, type=roaring)")
.filterTemplateValues(Collections.singletonMap("members", roaringBlob)).build();
const roaringBlob = buildRoaringBitmap(integerIds);
await client.delete({ collection_name: 'docs',
filter: 'membership_match(id, {members}, type=roaring)',
exprValues: { members: roaringBlob } });
Semantik penghapusan mengikuti pencocokan tiga nilai yang tepat:
| Nilai bidang | membership_match(…) | bukan membership_match(…) |
|---|---|---|
| NULL | tidak cocok (NULL) | tidak cocok (NULL) |
| dalam himpunan anggota | cocok | tidak cocok |
| di luar himpunan | tidak cocok | cocok |
Tabel tersebut dibaca baris demi baris: perintah Delete dengan membership_match menghapus entitas yang berada di dalam himpunan, perintah Delete dengan not membership_match menghapus entitas yang berada di luar himpunan, dan entitas dengan nilai NULL tetap ada pada kedua polaritas.
- Entitas dengan nilai bidang NULL tidak pernah dihapus, di bawah polaritas mana pun.
- Bitmap kosong tidak menghapus apa pun. `
not membership_match(<field>, {<empty>}, type=roaring)` menghapus setiap entitas dengan nilai bidang non-NULL; komplemen yang tepat, yang mungkin merupakan himpunan besar sesuai desain. not membership_matchadalah komplemen tepat dari himpunan anggota atas entitas non-NULL, bukan perkiraan.
Pada segmen tertutup yang dimuat hanya berdasarkan indeks, tanpa data skalar mentah, evaluasi menggunakan pencarian terbalik terbatas jika indeks mendukungnya. Jika data bidang mentah maupun indeks yang memenuhi syarat tidak tersedia, permintaan akan gagal dengan " FieldNotLoaded " alih-alih mengembalikan entitas yang tidak difilter.
Batasan operasional
| Pengaturan | Default | Dapat dikonfigurasi | Apa yang dibatasi |
|---|---|---|---|
proxy.maxMembershipFilterSize | 64 MiB | milvus.yaml proksi | satu isi blob |
proxy.maxMembershipFilterPlanSize | 128 MiB | milvus.yaml proksi | agregat per permintaan |
proxy.grpc.serverMaxRecvSize | 128 MiB | milvus.yaml proksi | seluruh permintaan |
| Batas maksimum kontainer yang sangat tinggi | 262.144 | diperbaiki dalam kode | per filter |
| Perkiraan memori terdekodifikasi Roaring | 64 MiB | tetap dalam kode | per filter |
| Batas format MBF1 | 128 MiB | tetap dalam kode | batas atas format blob |
Bloom fpr | 0,005 | pembuat klien | target positif palsu |
Pengaturan " proxy.* " merupakan konfigurasi server Milvus: pengaturan ini ditetapkan oleh operator kluster di milvus.yaml pada bagian " proxy " dan tidak dapat disesuaikan per permintaan atau per ekspresi saat proses penyaringan. Pengaturan " Roaring admissions" dan batas format MBF1 sudah ditetapkan dalam implementasi dan tidak dapat dikonfigurasi di mana pun. Baris " fpr " adalah satu-satunya pengaturan di sisi klien: nilainya ditentukan saat blob dibuat, dengan rentang yang diterima antara 0,0001 hingga 0,05.
Badan blob maksimum dapat menampung sekitar 48,6 juta anggota INT64 pada fpr default, dengan header amplop 32-byte tetap yang diizinkan di bagian atas. Anggaran permintaan mencakup ukuran serialisasi agregat dari rencana yang mengandung keanggotaan ditambah ukuran terdekodasi yang diperkirakan secara agregat dari filter Roaring, dan sub-permintaan HybridSearch serta filter penilai berbagi anggaran tersebut. Tubuh Bloom merupakan pangkat dua: jumlah anggota yang sedikit melebihi batas tingkatan akan menggandakan ukuran blob, dan nilai fpr yang sedikit lebih tinggi sering kali masih muat di tingkatan di bawahnya. Ketika proxy menolak blob Bloom yang berukuran terlalu besar, pesan kesalahan akan menyarankan ekspresi keanggotaan ( fpr ) yang sesuai.
- Hasil ekspresi keanggotaan tidak disimpan dalam cache antar permintaan.
- Cluster versi campuran gagal ditutup: QueryNodes yang menjalankan kode lama menolak rencana yang berisi node rencana keanggotaan. Tingkatkan proxy terlebih dahulu, lalu selesaikan peningkatan bertahap sebelum mengaktifkan operator.
- Log server menyensor byte blob. Teks ekspresi hanya berisi nama templat; muatan biner dikirimkan di luar jalur dalam nilai-nilai templat.