멤버십 매치Compatible with Milvus v3.0.2+

개요

멤버십 매치는 스칼라 필드 값이 호출자가 제공한 집합에 속하는지 여부를 검사하여 엔티티를 필터링합니다. 클라이언트는 간결한 이진 멤버십 필터 블롭을 생성하여 이를 표현식 템플릿 값으로 전달합니다.

이는 대용량 IN [...] 목록을 대체합니다. IN 필터는 모든 멤버를 요청에 직렬화하므로, 멤버 집합이 충분히 크면 프록시의 gRPC 수신 한도를 초과할 수 있습니다. membership_match 를 사용하면 프록시가 블롭을 검증하고 멤버 목록을 재구성하지 않고 쿼리 계획에 포함시킵니다.

Membership Match workflow: the client builds a reusable blob, the proxy validates it, and QueryNodes evaluate it. 멤버십 매치 워크플로: 클라이언트가 재사용 가능한 blob을 생성하고, 프록시가 이를 검증하며, QueryNodes가 이를 평가합니다.

이 다이어그램은 고정된 업무 분담을 보여줍니다. 클라이언트는 블롭을 한 번 생성하여 여러 요청에 걸쳐 재사용하고, 프록시는 엔벨로프와 크기 제한을 검증한 후 블롭을 쿼리 계획에 그대로 포함시키며, QueryNodes는 원시 데이터나 인덱스를 기준으로 해당 계획을 평가합니다.

이 연산자는 정확도 보장 수준이 서로 다른 두 가지 인코딩 방식을 제공합니다:

  • 블룸 (type=bloom): 근사적 멤버십. 오탐(false positive)이 발생할 수 있으나, 유효한 필터의 경우 오탐지(false negative)는 발생하지 않을 것으로 예상됩니다. 대표적인 용도: 가끔 발생하는 오탐이 허용되는 대용량 대상 그룹 또는 제외 필터.
  • Roaring (type=roaring): 정수 값에 대한 정확한 멤버십. 일반적인 용도: ACL, 테넌트 가시성, 규정 준수 필터 및 ID 집합별 삭제 작업.

승인 결정이나 데이터 삭제와 같은 파괴적 작업에는 블룸(Bloom ) 멤버십을 사용하지 마십시오. 오탐이 발생하면 의도된 집합에 속하지 않는 엔티티가 노출되거나 삭제될 수 있습니다.

운영 체크리스트

  • 대상 필드 유형을 확인하고 동일한 값 도메인을 기반으로 BLOB을 생성하십시오.
  • 오탐이 허용되는 경우에만 블룸을 선택하십시오.
  • ACL, 규정 준수, 테넌트 격리 및 삭제 작업의 경우 Roaring을 선택하십시오.
  • 대용량 BLOB은 한 번 생성하여 재사용하고, 매 요청마다 다시 생성하지 마십시오.
  • BLOB 크기는 멤버 수가 아닌 직렬화된 바이트 단위로 산정하십시오.
  • 버전이 혼합된 클러스터에서는 롤링 업그레이드를 완료하고(프록시부터 먼저), 그 후에 ' membership_match'을 활성화하십시오.
  • 파괴적인 워크플로를 활성화하기 전에 비프로덕션 컬렉션에서 표현식을 테스트하십시오.

표현식 구문

membership_match(<field>, {<template>}, type=bloom)
membership_match(<field>, {<template>}, type=roaring)
membership_match(<field>, {<template>})
not membership_match(<field>, {<template>}, type=bloom)

두 번째 인수는 템플릿 자리 표시자입니다. SDK는 클라이언트에서 생성한 필터 블롭을 포함하는 protobuf bytes 형식으로 자리 표시자 값을 제공합니다. 프로덕션 표현식에서는 type 를 명시적으로 유지하여 의도된 정확성 계약이 코드와 로그에 명확히 드러나도록 하십시오.

type 인수는 선택 사항입니다. 모든 blob은 자체 설명형 매직 헤더(Bloom의 경우 MBF1, Roaring의 경우 MRB1 )를 포함하며, type 가 생략되면 서버가 이 헤더를 감지합니다. blob 헤더와 충돌하는 명시적인 type 는 요청 오류로 거부되며, 알 수 없거나 잘린 헤더는 fail-closed 상태를 유발합니다.

인코딩 선택

오탐(false positive)이 허용되는 경우 블룸(Bloom)을 사용하십시오. 블룸은 부호 있는 정수 필드(INT8/16/32/64), VARCHAR 필드 및 JSON 경로를 지원합니다. 블룸 필터는 정확한 허용 목록(allow-list)이 아닙니다.

fpr (오탐률, false-positive rate)은 값이 삽입된 적이 없음에도 불구하고 블룸 필터가 해당 값을 멤버로 보고할 확률을 의미합니다. fpr=0.005 은 대략 200개 중 1개의 비멤버 값이 존재하는 것으로 잘못 보고된다는 것을 의미합니다. fpr이 낮을수록 블롭 크기는 커집니다.

모든 일치가 정확해야 할 때는 Roaring을 사용하십시오. Roaring은 부호 있는 정수 필드만 허용하며, 시리얼라이제이션 전에 멤버의 부호가 INT64로 확장되므로 INT8의 -1과 INT64의 -1은 동일한 멤버로 간주됩니다. UUID나 기타 문자열 필드에는 사용하지 마십시오.

차원블룸(type=bloom)Roaring (type=roaring)
정밀도근사; 오탐지 가능성 있음; 누락 없음정확함; 오탐 없음, 누락 없음
필드INT8/16/32/64, VARCHAR, JSON 경로부호 있는 INT8/16/32/64만
BLOB 크기멤버 수 및 FPR; FPR 0.005일 때 멤버당 약 11비트; 2의 거듭제곱 크기값 분포; 밀집된 집합은 훨씬 더 작은 크기로 압축됨; 무작위 64비트 값은 262,144라는 컨테이너 상한에 도달함
삭제구문 분석 시 거부됨허용됨
일반적인 사용대상 및 제외 필터ACL, 규정 준수, 테넌트 격리, ID 집합별 삭제

JSON 경로는 행별로 엄격한 유형을 따릅니다. JSON 문자열은 VARCHAR 값으로, JSON 정수는 INT64 값으로 처리되며, JSON double은 정수 멤버와 일치하지 않습니다. 이는 5.0이 5와 동일한 것으로 간주되는 정확한 IN 와는 다릅니다. 라이터가 정수를 부동 소수점 형식으로 인코딩하는 경우, 쓰기 시 정규화하거나 유형이 지정된 스칼라 필드를 사용하십시오.

두 인코딩 방식 모두 대상 필드와 동일한 값 도메인에서 멤버 세트를 구성하십시오. 문자열 "10086" 로 블룸 필터를 구축하여 INT64 필드에 적용하지 마십시오. blob 헤더는 삽입된 값 도메인을 기록하며, 도메인이 잘못된 blob은 프로キシ에 의해 아무 결과도 일치하지 않는 경우 조용히 처리되지 않고 매개변수 오류와 함께 거부됩니다. 각 쿼리마다 blob을 다시 구축하기보다는 요청 간에 구축된 blob을 재사용하십시오.

구성원이 수천 개 이하인 집합의 경우, 일반 IN 이 여전히 가장 간단한 옵션입니다. 서버는 IN, Bloom, Roaring 중에서 선택하지 않습니다. 인코딩 선택은 호출자의 책임입니다.

인코딩을 선택하려면:

  1. 워크로드가 오탐(false positive)을 허용하는지 판단하십시오. 허용하지 않는다면 Bloom은 절대 선택지가 될 수 없습니다.
  2. 정확한 멤버십을 확인하려면 부호 있는 정수 필드와 함께 Roaring을 사용하십시오. 밀집되거나 클러스터화된 값은 가장 작은 블롭으로 압축됩니다.
  3. 크기 제한을 확인하십시오. 균일하게 무작위 생성된 64비트 값은 262,144개의 컨테이너 상한선이나 크기 제한을 초과할 수 있습니다. 이 경우, 요청 제한에 맞는 기존의 IN 목록을 사용하십시오.
  4. 정수가 아닌 필드에 대한 정확한 멤버십을 확인하려면 IN을 사용하십시오. 이러한 필드에 대한 정확한 멤버십 인코딩은 없습니다.

RESTful HTTP API에서는 멤버십 일치(membership-match)를 사용할 수 없습니다. HTTP 표현식 템플릿 매개변수는 bool, number, string 및 array 값만 허용하며, blob에 대한 이진 bytes 유형은 없습니다. 멤버십 blob을 전달하려면 gRPC 기반 SDK를 사용하십시오.

SDK 요청 패턴

다음 코드 예제는 멤버십 블롭을 생성하고 이를 필터 템플릿 매개변수로 전달하는 데 중점을 둡니다. 이 예제들은 컬렉션과 필드가 이미 존재하고 로드된 상태이며, SDK 클라이언트가 연결되어 있고, 쿼리 벡터, 멤버 목록 및 기타 참조 변수가 정의되어 있음을 전제로 합니다. 컬렉션 설정 및 전체 애플리케이션 스캐폴딩은 생략되었습니다.

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);

Roaring을 사용한 삭제

외부 정수 ID 집합으로 선택된 엔티티를 삭제할 때는 정확한 Roaring 블롭을 사용하십시오. 삭제를 실행하기 전에 멤버 집합과 컬렉션 필드 유형을 검토하십시오. Bloom을 사용하지 마십시오. 근사 멤버십은 안전한 삭제 술어가 아니며, Bloom 형식은 구문 분석 시점에 Delete 표현식에서 거부됩니다.

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 } });

삭제 의미론은 정확한 3치 매칭을 따릅니다:

필드 값membership_match(…)not membership_match(…)
NULL일치 없음 (NULL)일치 없음 (NULL)
구성원 집합 내일치일치 항목 없음
집합 외부일치 없음일치

이 표는 행별로 해석하면 다음과 같습니다. membership_match 를 사용하는 Delete는 집합 내 엔티티를 제거하고, not membership_match 를 사용하는 Delete는 집합 외 엔티티를 제거하며, NULL 엔티티는 두 극성 모두에서 유지됩니다.

  • NULL 필드 값을 가진 엔티티는 어느 극성에서도 절대 삭제되지 않습니다.
  • 빈 비트맵은 아무것도 삭제하지 않습니다. not membership_match(<field>, {<empty>}, type=roaring) 는 NULL이 아닌 필드 값을 가진 모든 엔티티를 삭제하며, 이는 정확한 보충 집합으로, 설계상 큰 집합이 될 수 있습니다.
  • not membership_match 이는 NULL이 아닌 엔티티에 대한 멤버 집합의 정확한 보충 집합이며, 근사치가 아닙니다.

인덱스만 있고 원시 스칼라 데이터가 없는 씰된 세그먼트의 경우, 인덱스가 지원하는 경우 평가 시 제한된 역조회를 사용합니다. 원시 필드 데이터나 적격 인덱스를 모두 사용할 수 없는 경우, 요청은 필터링되지 않은 엔티티를 반환하는 대신 FieldNotLoaded 로 실패합니다.

운영상의 제한 사항

설정기본값구성 가능제한 대상
proxy.maxMembershipFilterSize64 MiBmilvus.yaml 프록시하나의 BLOB 본문
proxy.maxMembershipFilterPlanSize128 MiBmilvus.yaml 프록시요청당 집계
proxy.grpc.serverMaxRecvSize128 MiBmilvus.yaml 프록시전체 요청
매우 높은 컨테이너 상한선262,144코드에서 수정됨필터당
Roaring 디코딩된 메모리 추정값64 MiB코드에 고정필터당
MBF1 형식 제한128 MiB코드에 고정됨블롭 형식 상한
블룸 fpr0.005클라이언트 빌더오탐지 목표값

proxy.* 설정은 Milvus 서버 구성 항목입니다. 이 설정은 클러스터 운영자가 milvus.yaml 의 proxy 섹션에서 설정하며, 필터링 시 요청별 또는 표현식별로 조정할 수 없습니다. Roaring admissions 및 MBF1 형식 제한은 구현에서 고정되어 있으며 어디에서도 구성할 수 없습니다. ‘ fpr ’ 행은 클라이언트 측에서 제어할 수 있는 유일한 항목으로, 블롭이 생성될 때 0.0001에서 0.05 사이의 허용 범위 내에서 선택됩니다.

블롭 본문의 최대 용량은 기본 FPR에서 약 4,860만 개의 INT64 멤버를 수용할 수 있으며, 여기에 고정된 32바이트 엔벨로프 헤더가 추가됩니다. 요청 전체에 적용되는 할당량은 멤버십을 포함하는 플랜의 직렬화 크기 합계와 Roaring 필터의 예상 디코딩 크기 합계를 모두 포함하며, HybridSearch 하위 요청과 스코어러 필터가 이를 공유합니다. 블룸 본문은 2의 거듭제곱 크기를 가집니다. 즉, 멤버 수가 티어 경계를 약간 넘으면 블롭 크기가 두 배로 늘어나며, FPR을 약간 높이면 종종 바로 아래 티어에 맞출 수 있습니다. 프록시가 크기가 초과된 블룸 블롭을 거부할 경우, 오류 메시지에는 적합한 대체 블룸 표현식( fpr )이 제안됩니다.

  • 멤버십 표현식 결과는 요청 간에 캐시되지 않습니다.
  • 버전이 혼합된 클러스터는 실패로 처리됩니다. 구버전 코드를 실행하는 쿼리 노드(QueryNodes)는 멤버십 계획 노드가 포함된 계획을 거부합니다. 먼저 프록시를 업그레이드한 다음, 오퍼레이터를 활성화하기 전에 롤링 업그레이드를 완료하십시오.
  • 서버 로그는 블롭 바이트를 편집합니다. 표현식 텍스트에는 템플릿 이름만 포함되며, 바이너리 페이로드는 템플릿 값을 통해 대역 외로 전송됩니다.

번역DeepL

관리형 Milvus를 무료로 사용해 보세요

Zilliz Cloud는 번거로움이 없으며, Milvus 기반으로 10배 더 빠릅니다.

시작하기
피드백

이 페이지가 도움이 되었나요?