검색 집계Compatible with Milvus 3.0.x

쇼핑객이 “일상적인 훈련용 검은색 러닝화”를 검색할 때, 근사 최인접 이웃(ANN) 검색은 벡터 유사도에 따라 제품을 순위 매기고 평면적인 상위 K개 목록을 반환합니다. 결과는 관련성이 높을 수 있지만 반복적일 수 있습니다. 아래 예시에서, 상위 6개 결과 중 4개는 브랜드 A 제품인 반면, 브랜드 B와 브랜드 C는 각각 한 번씩만 나타납니다.

단순한 목록만으로는 버킷 중심의 요약 정보를 직접 제공할 수 없습니다. 애플리케이션에서는 유지된 후보 수나 평균 가격을 기준으로 브랜드를 비교하거나, 각 브랜드의 소수 대표 상품을 검토하거나, 결과를 여러 버킷 수준으로 구성해야 할 수도 있습니다.

검색 집계(Search Aggregation)는 선택된 스칼라 필드를 기반으로 유지된 ANN 후보들을 버킷으로 구성합니다. 이 예시에서 각 브랜드는 별도의 버킷이 됩니다. Milvus는 각 버킷에 대한 통계를 계산하고, 버킷을 순서대로 정렬하며, 대표 제품을 할당할 수 있습니다. 애플리케이션은 버킷 우선( result.agg_buckets) 방식을 통해 이 버킷 우선 응답을 활용합니다.

A flat running-shoe search result becomes a set of comparable brand buckets 단순한 러닝화 검색 결과가 비교 가능한 브랜드 버킷 집합으로 변환됩니다

검색 집계는 전체 컬렉션에 대한 정확한 집계를 수행하지 않습니다. 버킷의 존재 여부, 개수, 메트릭, 정렬 순서 및 대표 히트는 ANN 및 그룹화 단계에서 유지된 후보에 따라 달라집니다.

작동 원리

ANN candidates grouped by bucket keys and returned with counts, metrics, and representative hits 버킷 키별로 그룹화되고 개수, 메트릭 및 대표 히트와 함께 반환되는 ANN 후보

  1. 후보 항목 검색. Milvus는 ANN 검색을 실행하여 쿼리 벡터와 가장 가까운 엔티티를 찾습니다. 그런 다음 그룹화 단계에서 각 전체 복합 키에 대해 제한된 수의 후보 항목을 유지합니다. 이 키별 후보 항목 할당량은 집계 트리 내 어디서나 TopHits.size 중 가장 큰 값이거나, top_hits 를 구성하는 레벨이 없을 경우 1 가 됩니다.

  2. 버킷 생성. SearchAggregation.fields 는 버킷 키를 정의합니다. 필드 값의 각 고유한 조합은 별도의 키를 생성합니다. 그림에서 fields=["brand"](Brand A), (Brand B), (Brand C) 버킷 키를 생성합니다. 동일한 키를 가진 유지된 후보는 동일한 버킷에 속하며 해당 버킷의 count 에 기여합니다. SearchAggregation.size 는 Milvus가 반환하는 버킷의 수를 제한합니다.

  3. 결과를 계산하고 반환합니다. 반환된 각 버킷에는 해당 키와 유지된 후보 개수가 포함됩니다. Milvus는 또한 구성된 메트릭을 계산하고, 버킷을 정렬하며, 대표적인 엔티티를 반환하고, 하위 버킷을 생성할 수도 있습니다. result.agg_buckets 내의 각 AggregationBucketkey, count, metrics, hitssub_groups 를 노출합니다. 검색 집계(Search Aggregation)가 활성화되면 일반 검색 적중 목록은 비어 있습니다.

도표에서 TopHits.size=4 는 키당 4개의 후보 예산을 제공하므로, 유지된 4개의 브랜드 A 후보가 count: 4 를 생성합니다. 완성된 브랜드 A 카드는 도표를 간결하게 유지하기 위해 반환된 4개의 대표 검색 결과 중 2개만 표시합니다.

sub_aggregation 를 사용하면 Milvus는 각 상위 버킷 내에서 2단계와 3단계를 반복합니다. ANN 리콜률이나 키별 후보 예산의 변경은 버킷 수, 메트릭, 순서, 검색 결과 및 중첩된 결과를 변경할 수 있습니다.

제한 사항

검색 집계(Search Aggregation)를 사용하기 전에 다음 제한 사항을 확인하십시오.

  • 중첩 집계: 하나의 요청에는 하나의 루트 SearchAggregation 와 최대 3개의 중첩된 sub_aggregation 수준이 포함될 수 있으며, 총 4개 수준까지 가능합니다.

  • 버킷 키 생성에 사용되는 필드: SearchAggregation.fields 은 Boolean, integer, VARCHARTIMESTAMPTZ 필드를 지원합니다. FLOAT, DOUBLE, ARRAY, JSON, GEOMETRY, TEXT, vector 또는 dynamic 필드는 지원하지 않습니다.

  • 메트릭 필드: count"*" 또는JSON 가 아니며 동적이지 않은 모든 필드를 허용하며, 필드가 지정된 경우 NULL 값은 건너뜁니다. sumavg 는 정수 및 부동 소수점 필드를 허용합니다. minmax 는 추가로 문자열 및 TIMESTAMPTZ 필드를 허용합니다.

  • Top Hits 정렬 필드: TopHits.sort 는 비교 가능한 부울, 정수, 부동 소수점, 문자열 및 TIMESTAMPTZ 필드와 _score 를 허용합니다. ARRAY, JSON, GEOMETRY, 벡터 또는 동적 필드는 지원하지 않습니다.

  • 후보 예산: 집계 트리 내 어디에서든 가장 큰 TopHits.size 값은 전체 복합 키당 유지되는 후보의 수와 동일합니다. 어떤 레벨에서도 top_hits 가 구성되지 않은 경우, Milvus는 키당 하나의 후보를 유지합니다. 버킷 count 및 메트릭은 이러한 유지된 후보를 기반으로 계산되므로, TopHits.size 를 변경하면 해당 값도 변경될 수 있습니다.

  • Null 허용 버킷 필드: NULL 값은 자체 버킷 키를 형성합니다. null 버킷을 제외하려면 검색 요청에 brand is not null 와 같은 필터를 추가하십시오.

  • 반복되는 필드: 동일한 필드는 두 개 이상의 SearchAggregation.fields 목록에 동시에 나타날 수 없습니다. 예를 들어, 루트 집계에서 fields=["category"] 를 사용하는 경우, 중첩된 sub_aggregation 에서는 fields=["category"] 를 함께 사용할 수 없습니다.

  • 지원되지 않는 조합: 검색 집계(Search Aggregation)는 검색 필터( offset), 검색 반복자(Search Iterators), 하이브리드 검색(Hybrid Search), 하이라이터(Highlighter) 또는 그룹화 검색(Grouping Search)과 함께 사용할 수 없습니다.

  • 반환되는 항목: 구성된 결과 항목의 최대 개수를 10,000개 이하로 유지하십시오. 이 최대값은 다음과 같이 계산합니다.

    number of query vectors × size at every aggregation level × largest TopHits.size at any level

    TopHits 가 구성되지 않은 레벨이 없는 경우, 마지막 요소로 1 를 사용하십시오. 예를 들어, 쿼리 벡터 1개, 루트 버킷 10개, 루트 버킷당 자식 버킷 5개, 자식 버킷당 히트 2개인 경우, 구성된 최대값은 다음과 같습니다:

    1 × 10 × 5 × 2 = 100

검색 집계 사용

달성하고자 하는 목표에 따라 예제를 선택하십시오:

다음으로 이동하십시오설명주요 설정
버킷 비교 및 정렬버킷별 통계를 계산하여 버킷을 비교한 다음, 반환된 버킷을 메트릭, 개수 또는 키 기준으로 정렬합니다.fields, size, metrics, order
각 버킷의 대표적인 결과 표시각 버킷에서 제한된 수의 엔티티를 반환하고, 해당 엔티티를 스칼라 필드 또는 벡터 점수에 따라 개별적으로 정렬합니다.top_hits, TopHits.size, TopHits.sort
여러 수준에서 결과 그룹화결과를 상위 및 하위 버킷 수준으로 구성하여 여러 차원을 순차적으로 분석합니다.sub_aggregation

아래 예제에서는 브랜드, 카테고리, 색상, 가격 및 평점 필드가 포함된 제품 컬렉션을 사용합니다. 모든 브랜드 이름, 제품 이름, 가격, 평점 및 검색 결과는 합성된 예제 데이터입니다. 다음 섹션을 확장하여 컬렉션을 생성하고 공유 검색 변수를 정의하십시오.

예제 컬렉션 설정

from pymilvus import DataType, MilvusClient, SearchAggregation, TopHits

client = MilvusClient(
    uri="http://localhost:19530",
    token="root:Milvus",
)

collection_name = "product_search_aggregation"

if client.has_collection(collection_name):
    client.drop_collection(collection_name)

schema = client.create_schema(auto_id=False, enable_dynamic_field=False)
schema.add_field("id", DataType.INT64, is_primary=True)
schema.add_field("embedding", DataType.FLOAT_VECTOR, dim=5)
schema.add_field("name", DataType.VARCHAR, max_length=200)
schema.add_field("brand", DataType.VARCHAR, max_length=100)
schema.add_field("category", DataType.VARCHAR, max_length=100)
schema.add_field("color", DataType.VARCHAR, max_length=50)
schema.add_field("price", DataType.DOUBLE)
schema.add_field("rating", DataType.DOUBLE)
schema.add_field("in_stock", DataType.BOOL)

index_params = client.prepare_index_params()
index_params.add_index(
    field_name="embedding",
    index_type="AUTOINDEX",
    metric_type="COSINE",
)

client.create_collection(
    collection_name=collection_name,
    schema=schema,
    index_params=index_params,
    # Make preceding writes visible to searches from this client.
    consistency_level="Session",
)

client.insert(
    collection_name=collection_name,
    data=[
        {
            "id": 1,
            "embedding": [0.12, 0.42, 0.18, 0.66, 0.31],
            "name": "Runner A1",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "black",
            "price": 129.99,
            "rating": 4.7,
            "in_stock": True,
        },
        {
            "id": 2,
            "embedding": [0.10, 0.39, 0.20, 0.61, 0.29],
            "name": "Trail A2",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "blue",
            "price": 139.99,
            "rating": 4.6,
            "in_stock": True,
        },
        {
            "id": 3,
            "embedding": [0.14, 0.44, 0.19, 0.68, 0.33],
            "name": "Runner B1",
            "brand": "Brand B",
            "category": "running_shoes",
            "color": "white",
            "price": 159.99,
            "rating": 4.8,
            "in_stock": True,
        },
        {
            "id": 4,
            "embedding": [0.16, 0.41, 0.22, 0.62, 0.30],
            "name": "Runner C1",
            "brand": "Brand C",
            "category": "running_shoes",
            "color": "red",
            "price": 119.99,
            "rating": 4.4,
            "in_stock": False,
        },
        {
            "id": 5,
            "embedding": [0.48, 0.20, 0.59, 0.15, 0.71],
            "name": "Jacket A1",
            "brand": "Brand A",
            "category": "jackets",
            "color": "black",
            "price": 99.99,
            "rating": 4.5,
            "in_stock": True,
        },
        {
            "id": 6,
            "embedding": [0.45, 0.18, 0.55, 0.17, 0.69],
            "name": "Jacket B1",
            "brand": "Brand B",
            "category": "jackets",
            "color": "blue",
            "price": 89.99,
            "rating": 4.3,
            "in_stock": True,
        },
        {
            "id": 7,
            "embedding": [0.09, 0.38, 0.17, 0.60, 0.27],
            "name": "Runner A3",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "black",
            "price": 159.99,
            "rating": 4.8,
            "in_stock": True,
        },
        {
            "id": 8,
            "embedding": [0.13, 0.43, 0.21, 0.65, 0.32],
            "name": "Runner A4",
            "brand": "Brand A",
            "category": "running_shoes",
            "color": "black",
            "price": 149.99,
            "rating": 4.9,
            "in_stock": True,
        },
    ],
)

client.load_collection(collection_name)

query_vector = [0.11, 0.40, 0.19, 0.64, 0.30]
search_params = {
    "metric_type": "COSINE",
    "params": {},
}

위의 설정은 벡터 인덱스와 검색 매개변수 모두에 대해 COSINE 를 구성합니다. 따라서 이후 예제에서는 {"_score": "desc"} 를 사용하여 코사인 유사도가 높은 결과를 먼저 표시합니다. L2 와 같은 거리 측정 기준의 경우 {"_score": "asc"} 를 사용하십시오.

버킷 비교 및 정렬

계산된 통계를 사용하여 검색된 엔티티 그룹을 비교하고 버킷이 반환되는 순서를 제어해야 할 때 이 패턴을 사용합니다. 이 예제에서 Milvus는 brand 에 따라 검색된 제품을 그룹화하고, 각 브랜드 버킷에 대한 가격 지표를 계산한 다음, 평균 가격 순으로 버킷을 정렬합니다.

필드 값당 하나 이상의 엔티티를 반환하여 결과의 다양성만을 높이는 것이 목표라면, 대신 ‘그룹화 검색(Grouping Search)’을 사용하십시오.

다음 구성은 최대 세 개의 브랜드 버킷을 생성하고, 각 버킷에 대한 메트릭을 계산한 후, 평균 가격 순으로 버킷을 정렬합니다:

aggregation = SearchAggregation(
    # Form one bucket for each distinct brand value.
    fields=["brand"],
    # Return up to three buckets at this aggregation level.
    size=3,
    # Calculate named metrics for every selected bucket.
    metrics={
        "product_count": {"count": "*"},
        "avg_price": {"avg": "price"},
        "min_price": {"min": "price"},
    },
    # Sort buckets by average price, highest first.
    order=[
        {"avg_price": "desc"},
        # If average prices are equal, sort by bucket key in ascending order.
        {"_key": "asc"},
    ],
)

MilvusClient.search()search_aggregation 매개변수에 객체를 전달합니다:

result = client.search(
    collection_name=collection_name,
    data=[query_vector],
    anns_field="embedding",
    search_params=search_params,
    output_fields=[
        "name",
        "brand",
        "category",
        "color",
        "price",
        "rating",
        "in_stock",
    ],
    search_aggregation=aggregation,
)

search_aggregation 가 설정되면, PyMilvus는 result[0] 에서 일반 엔티티 히트를 반환하지 않습니다. 대신 result.agg_buckets[0] 에서 버킷 응답을 읽어오십시오. output_fields 매개변수는 반환된 각 AggregationHit.fields 매핑에 어떤 스칼라 필드가 표시될지 제어합니다. Milvus는 output_fields 에 나열되지 않은 메트릭 소스 및 정렬 필드도 여전히 사용할 수 있습니다.

버킷 출력 예시 보기

다음 출력은 위의 요청에서 캡처한 것으로, 가독성을 위해 JSON 형식으로 직렬화되었습니다. PyMilvus는 JSON 대신 AggregationBucket 객체를 반환합니다. key 값은 fields 에 필드가 하나만 포함되어 있는 경우에도 항상 정렬된 키 구성 요소 목록입니다. 이를 통해 복합 키의 필드 순서가 유지됩니다.

[
  {
    "key": [
      {
        "field_id": 103,
        "field_name": "brand",
        "value": "Brand B"
      }
    ],
    "count": 1,
    "metrics": {
      "product_count": 1,
      "avg_price": 159.99,
      "min_price": 159.99
    },
    "hits": [],
    "sub_groups": []
  },
  {
    "key": [
      {
        "field_id": 103,
        "field_name": "brand",
        "value": "Brand A"
      }
    ],
    "count": 1,
    "metrics": {
      "product_count": 1,
      "avg_price": 129.99,
      "min_price": 129.99
    },
    "hits": [],
    "sub_groups": []
  },
  {
    "key": [
      {
        "field_id": 103,
        "field_name": "brand",
        "value": "Brand C"
      }
    ],
    "count": 1,
    "metrics": {
      "product_count": 1,
      "avg_price": 119.99,
      "min_price": 119.99
    },
    "hits": [],
    "sub_groups": []
  }
]

이 가이드에 소개된 단일 쿼리 벡터의 경우, result.agg_buckets[0] 에서 반환된 최상위 버킷을 확인하십시오. 각 버킷은 정렬된 키 구성 요소, retained-candidate count, 계산된 metrics, 대표 hitssub_groups 에 포함된 중첩 버킷을 노출합니다.

다음과 같이 구성을 읽어옵니다:

설정제어 대상이 예시에서
fieldsMilvus가 버킷 키를 생성하는 방식brand 의 고유한 값마다 버킷을 하나씩 생성합니다.
size반환되는 버킷의 최대 개수최대 3개의 브랜드 버킷을 반환합니다.
metrics각 버킷에 대해 계산되는 통계상품 수, 평균 가격, 최저 가격을 계산합니다.
orderMilvus가 반환된 버킷을 정렬하는 방법평균 가격 순으로 정렬한 후, 동점 시 버킷 키를 사용하여 순위를 결정합니다.

search_aggregation 가 설정된 경우 Milvus는 limit 를 무시합니다. 최상위 버킷의 수를 제어하려면 루트 SearchAggregation.size 값을 사용하십시오.

이러한 설정으로 Milvus는 avg_price 순서대로 내림차순으로 브랜드 B, 브랜드 A, 브랜드 C 버킷을 반환합니다. _key 기준은 버킷의 평균 가격이 동일한 경우에만 적용됩니다. 이 구성에서는 top_hits 가 정의되어 있지 않으므로, 모든 버킷의 hits 목록은 비어 있으며 키별 후보 예산은 1 입니다. 따라서 표시된 개수 및 메트릭은 브랜드당 하나의 유지된 후보를 나타냅니다. 집계 시 더 넓은 키별 메트릭 창이 필요한 경우, top_hits 를 더 큰 TopHits.size 로 구성하십시오.

메트릭 및 정렬 규칙

SearchAggregation.metrics 항목은 사용자 정의 별칭을 {operation: source} 에 매핑합니다:

소스지원되는 작업동작
JSON 가 아니며 동적이지 않은 모든 필드countNULL 가 아닌 소스 필드를 가진 유지된 후보를 집계합니다.
정수형 또는 실수형 필드sum, ` avg`, ` min`, maxnull이 아닌 유지된 값을 기준으로 계산합니다.
문자열 또는 TIMESTAMPTZ 필드min, maxnull이 아닌 유지된 값 중 최소값 또는 최대값을 선택합니다.
"*"count버킷 내의 모든 유지된 후보를 집계합니다. 결과는 bucket.count 과 일치합니다.
_scoresum, avg, min, max유지된 후보에 대한 ANN 유사도 또는 거리 값을 집계합니다.

SearchAggregation.order 다음 키를 허용합니다:

순서 키의미
메트릭 별칭avg_price 와 같이, metrics 에서 동일한 집계 수준에서 계산된 값을 기준으로 정렬합니다.
_count각 버킷에 보존된 후보의 수에 따라 정렬합니다.
_key_key 라는 컬렉션 필드가 아닌 버킷 키를 기준으로 정렬합니다.

order 항목은 키를 "asc" 또는 "desc" 에 매핑합니다. Milvus는 첫 번째 항목부터 마지막 항목까지 여러 항목을 평가합니다. order 를 생략하면 Milvus는 유지된 후보 집합의 버킷 검색 순서를 그대로 유지합니다.

벡터 일치 품질에 따라 버킷을 정렬하려면, 먼저 _score 에서 버킷 수준 메트릭을 계산한 다음, order 에서 해당 메트릭 별칭을 사용해야 합니다. 각 버킷에는 여러 엔티티 점수가 포함될 수 있으므로, _score 를 버킷 정렬 키로 직접 사용할 수는 없습니다. 예를 들어, COSINE 또는 IP 의 경우:

aggregation = SearchAggregation(
    fields=["brand"],
    size=3,
    metrics={"max_score": {"max": "_score"}},
    order=[{"max_score": "desc"}],
)

L2 를 사용하여 _score 의 최소값을 계산하고, 거리 값이 가장 작은 버킷이 먼저 오도록 메트릭 별칭을 오름차순으로 정렬합니다.

복합 버킷 키 생성

복합 버킷 키를 생성하려면 동일한 목록에 여러 필드 이름을 전달합니다:

aggregation = SearchAggregation(
    # Combine brand and color to form a composite bucket key.
    fields=["brand", "color"],
    size=6,
)

이 구성을 사용하면 (Brand A, black), (Brand A, blue), (Brand B, white) 과 같은 키가 생성될 수 있습니다. 두 엔티티는 두 값이 모두 일치할 때만 동일한 버킷을 공유합니다. Milvus는 목록 순서를 유지하므로 brand 가 첫 번째 키 구성 요소이고 color 가 두 번째 키 구성 요소입니다. order 에서 _key 가 사용될 경우, Milvus는 복합 키 구성 요소를 동일한 순서로 비교합니다. 중첩된 목록은 지원되지 않으므로, 여러 문자열을 하나의 평면 목록으로 전달하십시오.

size=6 는 이 집계 수준에서 반환되는 복합 버킷의 최대 개수입니다. 예제 데이터에는 5개의 서로 다른 브랜드-색상 조합이 포함되어 있으므로, 5개 모두 반환될 수 있습니다. 반환 항목 제한에서 이 요청은 1 query vector × 6 buckets × 1 = 6 에 구성된 결과 항목을 기여합니다.

SearchAggregation.fields 목록에 여러 필드가 포함되면 해당 집계 수준에서 복합 버킷 키가 생성됩니다. 부모-자식 버킷 계층 구조를 생성하려면 중첩 집계를 사용하십시오.

다음 예제에서는 ` aggregation`를 재정의합니다. 업데이트된 객체를 동일한 ` search_aggregation ` 매개변수에 전달하고 검색 호출을 다시 실행하십시오.

각 버킷의 대표적인 결과 표시

애플리케이션에서 각 버킷의 실제 제품을 표시해야 하는 경우 대표적인 엔티티를 포함하십시오. 이 예제에서 Milvus는 각 브랜드 버킷에서 최대 두 개의 제품을 반환하며, 평점 순서대로 정렬한 다음 벡터 점수 순서대로 정렬합니다.

TopHits 를 다음과 같이 구성하십시오:

aggregation = SearchAggregation(
    fields=["brand"],
    size=3,
    # Return and sort representative entities for each selected bucket.
    top_hits=TopHits(
        # Return up to two entities per bucket.
        size=2,
        # Apply sort criteria in list order.
        sort=[
            {"rating": "desc"},
            {"_score": "desc"},
        ],
    ),
)

대표적인 검색 결과를 포함한 버킷 보기

다음은 위 요청에서 추출한 브랜드 A 버킷으로, 가독성을 위해 JSON 형식으로 직렬화되었습니다.

{
  "key": [
    {
      "field_id": 103,
      "field_name": "brand",
      "value": "Brand A"
    }
  ],
  "count": 2,
  "metrics": {},
  "hits": [
    {
      "pk": 1,
      "score": 0.99976646900177,
      "fields": {
        "brand": "Brand A",
        "category": "running_shoes",
        "color": "black",
        "in_stock": true,
        "name": "Runner A1",
        "price": 129.99,
        "rating": 4.7
      }
    },
    {
      "pk": 2,
      "score": 0.9997048377990723,
      "fields": {
        "brand": "Brand A",
        "category": "running_shoes",
        "color": "blue",
        "in_stock": true,
        "name": "Trail A2",
        "price": 139.99,
        "rating": 4.6
      }
    }
  ],
  "sub_groups": []
}

매개변수목적
top_hits선택 사항입니다. 이 집계 수준에 대한 대표 엔티티를 구성합니다. 생략할 경우, bucket.hits 는 비어 있으며 키별 후보 예산은 기본적으로 1로 설정됩니다.
TopHits.size선택된 각 버킷에서 최대 두 개의 대표 엔티티를 반환하고, 전체 집계 트리에 대해 키별 후보 예산을 2로 설정합니다.
TopHits.sort나열된 기준을 사용하여 각 버킷 내의 엔티티를 정렬합니다.

애플리케이션에 대표 엔티티가 필요하거나, 카운트 및 메트릭에 더 넓은 키별 후보 창이 필요한 경우 ` top_hits `를 구성하십시오. ` TopHits.size ` 값이 클수록 후보 예산과 `Limits`의 최대 반환 항목 계산값이 모두 증가합니다.

SearchAggregation.order TopHits.sort 는 각 버킷 내의 엔티티를 정렬하는 반면, 는 버킷을 정렬합니다. 정렬 순서는 및 메트릭을 위해 유지된 후보 항목에 영향을 미치지 않습니다. 는 지원되는 비교 가능한 스칼라 필드 이름과 ANN 유사도 또는 거리를 나타내는 내장 필드를 허용합니다. Milvus는 항목을 첫 번째부터 마지막까지 평가합니다. 이 예제에서는 에 따라 제품을 가장 높은 값에서 가장 낮은 값 순으로 정렬하며, 두 평점이 동일한 경우에만 를 사용합니다. 이 설정에서는 를 사용하므로, 내림차순 을 적용하면 더 유사한 제품이 먼저 표시됩니다. count TopHits.sort _score sort rating _score COSINE _score

metrics 또는 TopHits.sort 에서 사용하는 필드는 output_fields 에 반드시 포함될 필요는 없습니다. Milvus는 내부적으로 해당 필드를 가져오지만, output_fields 에 명시적으로 나열된 필드만 반환된 각 히트의 fields 매핑에 포함됩니다. 기본 키와 벡터 점수는 AggregationHit.pkAggregationHit.score 를 통해 계속 사용할 수 있습니다.

반환된 각 AggregationHitpk 에서 기본 키를, score 에서 벡터 점수를, fields 에서 요청된 출력 필드를 노출합니다.

여러 수준에서 결과 그룹화

한 수준 내의 버킷을 다른 수준 안에 포함시켜야 할 때는 중첩 집계(nested aggregation)를 사용합니다. 이 예제에서 Milvus는 먼저 카테고리 버킷을 생성한 다음, 각 카테고리 내에 브랜드 버킷을 생성합니다.

자식 집계는 부모 버킷에 할당된 엔티티만 수신합니다. fields 는 각 집계 수준에서 버킷 키를 제어하며, sub_aggregation 는 부모-자식 계층 구조를 생성합니다.

아래 구성은 키가 (running_shoes) 인 카테고리 버킷을 생성합니다. 해당 상위 버킷 내에서 자식 집계는 (Brand A), (Brand B), (Brand C) 과 같은 키를 가진 별도의 브랜드 버킷을 생성합니다.

Parent bucket key:
(running_shoes)

Child bucket keys:
├── (Brand A)
├── (Brand B)
└── (Brand C)

각 레벨은 여러 필드를 독립적으로 사용할 수 있습니다. 예를 들어, 자식 집계에서 fields=["brand", "color"] 을 사용하면 (Brand A, black) 과 같은 복합 자식 키가 생성됩니다.

다음 구성은 이 계층 구조를 구현합니다:

aggregation = SearchAggregation(
    fields=["category"],
    size=2,
    metrics={
        "product_count": {"count": "*"},
        "avg_price": {"avg": "price"},
    },
    order=[{"product_count": "desc"}],
    # For each category bucket, group only its entities by brand.
    sub_aggregation=SearchAggregation(
        fields=["brand"],
        size=3,
        metrics={
            "brand_count": {"count": "*"},
            "avg_rating": {"avg": "rating"},
        },
        order=[{"avg_rating": "desc"}],
        top_hits=TopHits(
            size=2,
            sort=[{"rating": "desc"}],
        ),
    ),
)

중첩된 버킷 결과 보기

다음 직렬화된 발췌문은 running_shoes 상위 버킷과 그 하위 버킷인 Brand B를 보여줍니다. 간결성을 위해 Brand A 및 Brand C 하위 버킷은 생략되었습니다.

{
  "key": [
    {
      "field_id": 104,
      "field_name": "category",
      "value": "running_shoes"
    }
  ],
  "count": 4,
  "metrics": {
    "avg_price": 137.49,
    "product_count": 4
  },
  "hits": [],
  "sub_groups": [
    {
      "key": [
        {
          "field_id": 103,
          "field_name": "brand",
          "value": "Brand B"
        }
      ],
      "count": 1,
      "metrics": {
        "avg_rating": 4.8,
        "brand_count": 1
      },
      "hits": [
        {
          "pk": 3,
          "score": 0.9994542598724365,
          "fields": {
            "brand": "Brand B",
            "category": "running_shoes",
            "color": "white",
            "in_stock": true,
            "name": "Runner B1",
            "price": 159.99,
            "rating": 4.8
          }
        }
      ],
      "sub_groups": []
    }
  ]
}

표시된 결과는 단일 복합 버킷 키인 (running_shoes, Brand B) 이 아니라 버킷 경로 (running_shoes) → (Brand B) 을 나타냅니다.

Milvus는 먼저 product_count 순서로 정렬된 최대 두 개의 카테고리 버킷을 선택합니다. 그런 다음 선택된 각 카테고리 내에서 sub_aggregation 을 독립적으로 실행하고, avg_rating 순서로 정렬된 최대 세 개의 브랜드 버킷을 반환합니다.

위의 출력에서:

  • 루트 running_shoes 버킷은 하위 복합 키에 걸쳐 4개의 유지된 후보를 포함합니다. 이 버킷의 metrics 에는 루트 수준의 avg_priceproduct_count 값이 포함됩니다.
  • 루트 버킷의 sub_groups 목록에는 하위 브랜드 버킷들이 포함되어 있습니다. 표시된 Brand B 버킷에는 유지된 후보 1개와 해당 버킷 자체의 avg_ratingbrand_count 값이 포함되어 있습니다.
  • 루트 버킷의 hits 목록은 루트 집계에서 top_hits 가 구성되지 않았기 때문에 비어 있습니다. 브랜드 B 자식 버킷에는 sub_aggregation 에서 top_hits 가 구성되어 있으므로 대표적인 히트가 포함되어 있습니다.

자주 묻는 질문

버킷 카운트 및 메트릭의 정확도는 어느 정도인가요?

검색 집계는 유지된 ANN 후보를 요약합니다. 전체 컬렉션에 대한 집계를 실행하지는 않습니다.

후보 유지에는 두 단계의 근사화 과정이 있습니다. ANN 검색은 관련 컬렉션 엔티티를 생략할 수 있으며, 그룹화 단계에서는 각 전체 복합 키에 대해 최대 TopHits.size 개의 후보만 유지합니다. 어떤 레벨에서도 top_hits 가 구성되지 않은 경우, 이 키별 제한은 1개입니다.

예를 들어, 컬렉션에 브랜드 A 제품이 5,000개 포함되어 있고 그중 다수가 벡터 쿼리와 관련이 있다고 가정해 보겠습니다. 집계에서 ` TopHits(size=4)`를 사용하는 경우, 브랜드 A 버킷은 전체 복합 키에 대해 최대 4개의 후보만 유지할 수 있습니다. 이 버킷의 ` count ` 및 메트릭은 유지된 후보들을 설명하며, 모든 관련 브랜드 A 제품이나 5,000개의 컬렉션 엔티티 전체를 설명하는 것은 아닙니다.

order 가 메트릭 별칭을 사용할 때 근사치의 중요성이 가장 커집니다. 검색 리콜의 변화는 메트릭 값을 변경할 수 있으며, 결과적으로 SearchAggregation.size 에 포함되는 버킷이 달라질 수 있습니다. 중첩 집계는 각 자식 레벨이 부모 버킷에 있는 엔티티를 대상으로 처리하기 때문에 이러한 효과를 증폭시킬 수 있습니다.

일치하는 모든 엔티티에 대한 정확한 통계가 필요한 경우, 검색 집계 대신 정확한 쿼리 집계 워크플로를 사용하십시오.

애플리케이션의 주요 결과 형식에 따라 선택하십시오:

주요 요구 사항권장활용할 결과 형식
그룹화 필드에서 중복 값이 적은 표준 순위 엔티티 목록을 반환그룹화 검색각 쿼리 벡터에 대한 플랫 검색 결과
키, 개수, 메트릭, 정렬 순서, 대표 검색 결과 또는 하위 버킷을 사용하여 그룹을 버킷으로 검사하거나 비교검색 집계AggregationBucket 내의 객체 result.agg_buckets

검색 집계에서 ` top_hits`를 구성하더라도, 주요 응답은 여전히 버킷 트리입니다. 애플리케이션이 이미 일반 검색 결과를 처리하고 있으며 주로 결과의 다양성을 원하는 경우, 그룹화 검색은 여전히 유용합니다.

이 API들은 상호 배타적입니다. PyMilvus는 동일한 요청에서 ‘ search_aggregation ’가 ‘ group_by_field ’ 또는 ‘ group_by_fields ’와 결합될 경우 ‘ ParamError ’ 예외를 발생시킵니다.