Skip to content

Milvus Lite 3.0 raw distance semantics differ from server for COSINE and L2 #343

Description

@zc277584121

Summary

While validating vector-search score parity across Milvus Lite, Milvus server, and Zilliz Cloud, I found that milvus-lite==3.0 returns different raw distance values from Milvus server / Zilliz Cloud for the same MilvusClient.search() call.

This is especially visible for COSINE and L2:

  • COSINE: Milvus Lite 3.0 returns distance-style values (same=0.0, orthogonal=1.0), while Milvus server, Zilliz Cloud, and Milvus Lite 2.5 return similarity-style values (same=1.0, orthogonal=0.0).
  • L2: Milvus Lite 3.0 returns Euclidean distance for this probe (orthogonal~=1.4142135), while Milvus server, Zilliz Cloud, and Milvus Lite 2.5 return squared L2 distance (orthogonal=2.0).

If this is intentional, it would be useful to document the behavior and migration guidance. If not, it would be helpful to align Milvus Lite 3.0 with Milvus server / Zilliz Cloud, since client integrations often normalize scores based on the raw distance field.

Probe setup

2D data:

  • query: [1.0, 0.0]
  • row 1: [1.0, 0.0]
  • row 2: [0.0, 1.0]

All tests use MilvusClient.create_collection(..., dimension=2, metric_type=<metric>, auto_id=False) and then MilvusClient.search(..., search_params={"metric_type": <metric>}).

Observed results

Backend Tested versions COSINE raw distance IP raw distance L2 raw distance
Milvus Lite 2.5 pymilvus==2.5.18, milvus-lite==2.5.1 same 1.0, orthogonal 0.0 same 1.0, orthogonal 0.0 same 0.0, orthogonal 2.0
Milvus Lite 3.0 pymilvus==3.0.0, milvus-lite==3.0 same 0.0, orthogonal 1.0 same 1.0, orthogonal 0.0 same 0.0, orthogonal 1.4142135
Milvus server 2.5 milvusdb/milvus:v2.5.13, pymilvus==3.0.0 same 1.0, orthogonal 0.0 same 1.0, orthogonal 0.0 same 0.0, orthogonal 2.0
Milvus server 3.0 milvusdb/milvus:v3.0-beta, pymilvus==3.0.0 same 1.0, orthogonal 0.0 same 1.0, orthogonal 0.0 same 0.0, orthogonal 2.0
Zilliz Cloud pymilvus==3.0.0 same 1.0, orthogonal 0.0 same 1.0, orthogonal 0.0 same 0.0, orthogonal 2.0

Note: for the Milvus Lite 2.5 probe, milvus-lite==2.5.1 imports pkg_resources, so the temporary test environment used setuptools<81.

Minimal reproduction

import tempfile
import uuid
from pathlib import Path
from importlib.metadata import version
from pymilvus import MilvusClient

print(f"pymilvus=={version('pymilvus')}")
try:
    print(f"milvus-lite=={version('milvus-lite')}")
except Exception:
    pass

# For Lite, use a local file URI. For server/Zilliz, replace with the service URI.
uri = str(Path(tempfile.mkdtemp()) / "probe.db")
client = MilvusClient(uri=uri)

try:
    for metric in ["COSINE", "IP", "L2"]:
        collection = f"tmp_metric_probe_{metric.lower()}_{uuid.uuid4().hex[:10]}"
        try:
            client.create_collection(
                collection_name=collection,
                dimension=2,
                metric_type=metric,
                auto_id=False,
            )
            client.insert(
                collection_name=collection,
                data=[
                    {"id": 1, "vector": [1.0, 0.0]},
                    {"id": 2, "vector": [0.0, 1.0]},
                ],
            )
            results = client.search(
                collection_name=collection,
                data=[[1.0, 0.0]],
                anns_field="vector",
                limit=2,
                search_params={"metric_type": metric},
                output_fields=["id"],
            )
            rows = []
            for row in results[0]:
                entity = row.get("entity") or {}
                rows.append({
                    "id": row.get("id") or entity.get("id"),
                    "distance": row.get("distance"),
                })
            print(metric, rows)
        finally:
            if client.has_collection(collection):
                client.drop_collection(collection)
finally:
    client.close()

Expected behavior

The raw distance semantics should either:

  1. match Milvus server / Zilliz Cloud for the same metric, or
  2. be explicitly documented as a Milvus Lite 3.0 behavior change, including guidance for clients that need consistent score normalization across Lite, server, and Zilliz Cloud.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions