qdrant / qdrant-client

Python client for Qdrant vector search engine
https://qdrant.tech
Apache License 2.0
786 stars 120 forks source link

Pydantic missing field error on collection_cluster_info response #771

Closed ArthurMelin closed 1 month ago

ArthurMelin commented 2 months ago

Hi, I'm getting a Pydantic missing field exception on the field obj.result.resharding_operations when using qdrant.http.cluster_api.collection_cluster_info(...).

When looking at the server source, it looks like currently this field doesn't get serialized if it's empty: https://github.com/qdrant/qdrant/blob/9fa86106e85d734765efe2c686a3ce975e53fb38/lib/collection/src/operations/types.rs#L210

Environment: qdrant-client: 1.11.1 qdrant: 1.11.3

Traceback:

Traceback (most recent call last):
  File "/data/scripts/rebalance.py", line 10, in <module>
    cluster_info = qdrant.http.cluster_api.collection_cluster_info(collection).result
  File "/data/scripts/venv/lib64/python3.9/site-packages/qdrant_client/http/api/cluster_api.py", line 302, in collection_cluster_info
    return self._build_for_collection_cluster_info(
  File "/data/scripts/venv/lib64/python3.9/site-packages/qdrant_client/http/api/cluster_api.py", line 81, in _build_for_collection_cluster_info
    return self.api_client.request(
  File "/data/scripts/venv/lib64/python3.9/site-packages/qdrant_client/http/api_client.py", line 79, in request
    return self.send(request, type_)
  File "/data/scripts/venv/lib64/python3.9/site-packages/qdrant_client/http/api_client.py", line 101, in send
    raise ResponseHandlingException(e)
qdrant_client.http.exceptions.ResponseHandlingException: 1 validation error for ParsingModel[InlineResponse2008] (for parse_as_type)
obj.result.resharding_operations
  Field required [type=missing, input_value={'peer_id': 4660132199939..., 'shard_transfers': []}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.9/v/missing
joein commented 2 months ago

Hi @ArthurMelin

Could you provide a minimal reproducible code snippet please? So we could confirm the problem and also see how you're using it

ArthurMelin commented 2 months ago

Sure, here it is:

from qdrant_client import QdrantClient

qdrant = QdrantClient()

peers = [int(p) for p in qdrant.http.cluster_api.cluster_status().result.peers]

collections = [c.name for c in qdrant.http.collections_api.get_collections().result.collections]

for collection in collections:
    cluster_info = qdrant.http.cluster_api.collection_cluster_info(collection).result
    shards = (
        [{"id": s.shard_id, "peer": cluster_info.peer_id} for s in cluster_info.local_shards] +
        [{"id": s.shard_id, "peer": s.peer_id} for s in cluster_info.remote_shards]
    )
    shards.sort(key=lambda s: s["id"])
    peer_shards = {p: [s["id"] for s in shards if s["peer"] == p] for p in peers}
    while True:
        min_peer = min(peer_shards.keys(), key=lambda k: len(peer_shards[k]))
        max_peer = max(peer_shards.keys(), key=lambda k: len(peer_shards[k]))
        if len(peer_shards[max_peer]) - len(peer_shards[min_peer]) <= 1:
            break
        shard = peer_shards[max_peer][-1]
        print(f"move shard {shard} from {max_peer} to {min_peer}")
        peer_shards[max_peer].remove(shard)
        peer_shards[min_peer].append(shard)
joein commented 2 months ago

Hi @ArthurMelin It seems to be a bug in our openapi schema, which resulted in generating the incorrect model. Thanks for pointing it out

joein commented 2 months ago

Should be fixed after releasing this one https://github.com/qdrant/qdrant/pull/5060

joein commented 1 month ago

Hey @ArthurMelin

The fix should be available with the next release You can try it out now with the dev branch

joein commented 1 month ago

Should be available as of qdrant-client v1.11.3 and qdrant v1.11.4