Skip to content

Add list shard keys API#7615

Merged
coszio merged 3 commits intoqdrant:devfrom
amiremohamadi:api/list-shard-keys
Nov 29, 2025
Merged

Add list shard keys API#7615
coszio merged 3 commits intoqdrant:devfrom
amiremohamadi:api/list-shard-keys

Conversation

@amiremohamadi
Copy link
Contributor

related to #4002

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@amiremohamadi
Copy link
Contributor Author

quick question! do these changes require openapi tests as well? we didn't have separate tests for shards, so i assume i should create a new file for it? (E.g. tests/openapi/test_shard_key.py)

cc: @coszio

@qdrant qdrant deleted a comment from coderabbitai bot Nov 26, 2025
@timvisee timvisee self-requested a review November 26, 2025 13:36
@timvisee
Copy link
Member

quick question! do these changes require openapi tests as well? we didn't have separate tests for shards, so i assume i should create a new file for it? (E.g. tests/openapi/test_shard_key.py)

Yes. Please feel free to create a new test file there.

@coszio coszio self-requested a review November 26, 2025 20:41
coderabbitai[bot]

This comment was marked as resolved.

@qdrant qdrant deleted a comment from coderabbitai bot Nov 27, 2025
Copy link
Member

@timvisee timvisee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your contribution! I must say, I'm quite impressed.

Right now we return an array of shard keys (either being a string or a number). I wonder if we ever want to extend this to also report the number of shards that belong to a key. With the current design that is not (easily) possible. At the same time I do like the simplicity it currently has.

Thoughts @coszio @generall ?

Of course, this information is already indirectly available through GET /collections/something/cluster.

Let me think about it for a bit.

Comment on lines +262 to +267
let shard_keys: CollectionShardKeys = do_get_collection_shard_keys(
self.dispatcher.toc(&access, &pass),
access,
request.into_inner().collection_name.as_str(),
)
.await?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shard keys are only used when custom sharding is enabled.

I wonder if it makes sense to just return an error if custom sharding is not enabled.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should error.

The endpoint is /collections/{collection_name}/shards, and right now the response we want is

{
  "shard_keys": [
     { "key": "my_shard_key" }
  ]
}

Since semantics refer to shards in general, this same endpoint can be extended to add another field called "shards". Something like

{
  "shard_keys": [
     { "key": "my_shard_key", "shard_ids": [1] }
  ],
  "shards": [
    { "id": 1 }
  ]
}

Or just "shards" in the case of ShardingMethod::Auto

{
  "shards": [
    { "id": 1 }
  ]
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hadn’t considered errors in my last changes, as @coszio point makes sense to me. I’ll defer to you guys’ call.

@timvisee
Copy link
Member

Having quickly discussed this internally. Lets use a dedicated type for each item in the list we return. That allows us to extend it in the future.

I expect this to be similar to the collections listing (GET /collections). It doesn't return a list of strings, but it returns a list of CollectionDescriptions, which we might extend in the future.

In code:

  • #[derive(Debug, Serialize, JsonSchema)]
    #[serde(rename_all = "snake_case")]
    #[schemars(example = "example_collections_response")]
    pub struct CollectionsResponse {
    pub collections: Vec<CollectionDescription>,
    }
  • #[derive(Debug, Serialize, JsonSchema)]
    #[serde(rename_all = "snake_case")]
    pub struct CollectionDescription {
    pub name: String,
    }
  • {
      "result": {
        "collections": [
          {
            "name": "test1"
          },
          {
            "name": "test2"
          }
        ]
      },
      "status": "ok",
      "time": 0.00003392
    }

So, for the shard key listing I'd expect to use a wrapping struct like this:

#[derive(Debug, Serialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub struct ShardKeyDescription {
    pub shard_key: ShardKey,
}

Copy link
Contributor

@coszio coszio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work! My review mostly covers nits, but requesting changes due to #7615 (comment)

Comment on lines +262 to +267
let shard_keys: CollectionShardKeys = do_get_collection_shard_keys(
self.dispatcher.toc(&access, &pass),
access,
request.into_inner().collection_name.as_str(),
)
.await?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should error.

The endpoint is /collections/{collection_name}/shards, and right now the response we want is

{
  "shard_keys": [
     { "key": "my_shard_key" }
  ]
}

Since semantics refer to shards in general, this same endpoint can be extended to add another field called "shards". Something like

{
  "shard_keys": [
     { "key": "my_shard_key", "shard_ids": [1] }
  ],
  "shards": [
    { "id": 1 }
  ]
}

Or just "shards" in the case of ShardingMethod::Auto

{
  "shards": [
    { "id": 1 }
  ]
}

coderabbitai[bot]

This comment was marked as resolved.

@qdrant qdrant deleted a comment from coderabbitai bot Nov 28, 2025
Copy link
Contributor

@coszio coszio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for taking the time to address this!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/api/build.rs (1)

118-189: Add collection_name validation for ListShardKeysRequest

ListShardKeysRequest currently only appears in extra_derives, so it gets a Validate impl but no actual constraints on collection_name, unlike other collection-level requests. This creates an inconsistent validation surface for the new RPC.

Recommend adding a field-level validation entry mirroring existing collection_name rules:

 fn configure_validation(builder: Builder) -> Builder {
     builder
         // prost_wkt_types needed for serde support
         .extern_path(".google.protobuf.Timestamp", "::prost_wkt_types::Timestamp")
         // Service: collections.proto
         .validates(&[
             ("GetCollectionInfoRequest.collection_name", "length(min = 1, max = 255), custom(function = \"common::validation::validate_collection_name_legacy\")"),
             ("CollectionExistsRequest.collection_name", "length(min = 1, max = 255), custom(function = \"common::validation::validate_collection_name_legacy\")"),
             ("CreateCollection.collection_name", "length(min = 1, max = 255), custom(function = \"common::validation::validate_collection_name\")"),
             ...
             ("ListCollectionAliasesRequest.collection_name", "length(min = 1, max = 255), custom(function = \"common::validation::validate_collection_name_legacy\")"),
+            ("ListShardKeysRequest.collection_name", "length(min = 1, max = 255), custom(function = \"common::validation::validate_collection_name_legacy\")"),
             ("HnswConfigDiff.ef_construct", "range(min = 4)"),
             ...
         ], &[
             "ListCollectionsRequest",
             "ListAliasesRequest",
             "CollectionClusterInfoRequest",
             ...
-            "Replica",
-            "ListShardKeysRequest",
+            "Replica",
+            "ListShardKeysRequest",
         ])

(Keeping "ListShardKeysRequest" in extra_derives is harmless due to dedup, but optional once the field rule is present.)

♻️ Duplicate comments (2)
lib/collection/src/shards/shard_holder/shard_mapping.rs (1)

69-72: Shard-key iterator API matches existing mapping helpers

iter_shard_keys cleanly exposes HashMap::keys() and mirrors iter_shard_ids, giving callers an efficient way to enumerate shard keys without cloning.

lib/api/src/grpc/qdrant.rs (1)

1983-1991: Add collection_name validation to ListShardKeysRequest for consistency

ListShardKeysRequest derives validator::Validate but collection_name lacks the length + validate_collection_name_legacy constraints used on other collection-name requests (e.g. GetCollectionInfoRequest, CollectionExistsRequest). This means validate(request.get_ref())? in the tonic handler does not enforce any constraints on this field, unlike the rest of the API surface.

Mirror the same validation attributes on collection_name in the corresponding .proto definition and regenerate this file, instead of editing it directly. Based on learnings, lib/api/src/grpc/qdrant.rs is prost-generated from the proto specs.

🧹 Nitpick comments (4)
tests/openapi/helpers/collection_setup.py (1)

136-136: Consider conditionally including sharding_method.

Currently, "sharding_method": sharding_method will include the field with a null value when sharding_method=None. While this may work if the backend treats null as absent, it would be cleaner to only include the field when it has a value:

body = {
    "vectors": {
        "size": 4,
        "distance": "Dot",
        "on_disk": on_disk_vectors,
    },
    "sparse_vectors": {
        "sparse-text": {},
    },
    "on_disk_payload": on_disk_payload,
    "wal_config": {
        "wal_capacity_mb": wal_capacity,
    }
}
if sharding_method is not None:
    body["sharding_method"] = sharding_method
tests/openapi/test_shard_key.py (1)

53-54: Improve assertion precision.

The current assertions check if the values appear in any field of the dictionary items, which is imprecise. Consider checking the specific "key" field:

-    assert any("test_key" in item.values() for item in shard_keys)
-    assert any(100 in item.values() for item in shard_keys)
+    assert any(item.get("key") == "test_key" for item in shard_keys)
+    assert any(item.get("key") == 100 for item in shard_keys)

This makes the test more robust and clearer in intent.

docs/redoc/master/openapi.json (1)

16009-16019: Prefer required, non-null list; add example.

Return an empty array when sharding is auto instead of null. This matches other list responses (e.g., CollectionsResponse.collections) and simplifies clients.

Apply:

-      "ShardKeysResponse": {
+      "ShardKeysResponse": {
         "type": "object",
+        "required": ["shard_keys"],
         "properties": {
           "shard_keys": {
-            "description": "The existing shard keys. Only available when sharding method is `custom`",
+            "description": "Existing shard keys. Empty array when sharding method is `auto`.",
             "type": "array",
             "items": {
               "$ref": "#/components/schemas/ShardKeyDescription"
-            },
-            "nullable": true
+            }
           }
-        }
+        },
+        "example": {
+          "shard_keys": [
+            { "shard_key": "region_1" },
+            { "shard_key": 12 }
+          ]
+        }
       },
lib/api/src/grpc/qdrant.rs (1)

2007-2022: Consider renaming ShardKeyDescription.key to shard_key for API clarity

The wrapper type is great for future extensibility, but the field name key is quite generic and slightly inconsistent with other shard-related types (LocalShardInfo.shard_key, ShardKeySelector.shard_keys). Renaming this field to shard_key in the proto (and regenerating) would make the API more self-descriptive and consistent with existing naming.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf564a4 and 71486c1.

📒 Files selected for processing (17)
  • docs/redoc/master/openapi.json (2 hunks)
  • lib/api/build.rs (1 hunks)
  • lib/api/src/grpc/conversions.rs (2 hunks)
  • lib/api/src/grpc/proto/collections.proto (1 hunks)
  • lib/api/src/grpc/proto/collections_service.proto (1 hunks)
  • lib/api/src/grpc/qdrant.rs (5 hunks)
  • lib/api/src/rest/models.rs (2 hunks)
  • lib/collection/src/shards/shard_holder/shard_mapping.rs (1 hunks)
  • openapi/openapi-shards.ytt.yaml (1 hunks)
  • src/actix/api/shards_api.rs (2 hunks)
  • src/common/collections.rs (2 hunks)
  • src/schema_generator.rs (2 hunks)
  • src/tonic/api/collections_api.rs (2 hunks)
  • tests/consensus_tests/auth_tests/test_jwt_access.py (2 hunks)
  • tests/openapi/helpers/collection_setup.py (3 hunks)
  • tests/openapi/test_shard_key.py (1 hunks)
  • tests/openapi_consistency_check.sh (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (.github/review-rules.md)

**/*.rs: Prefer explicit SomeType::from(x) over implicit x.into() in Rust
In new code, don't use transmute_from_u8, transmute_to_u8, transmute_from_u8_to_slice, transmute_from_u8_to_mut_slice, transmute_to_u8_slice - use bytemuck or zerocopy crates instead
Prefer explicit exhaustive matches over catch-all _ arm in Rust match expressions, so we don't miss handling new enum variants when they are added later (exceptions: tests and benchmarks, or when sure new variants won't affect logic)
Prefer explicit field ignoring using : _ over using .. in Rust struct destructuring (exceptions: tests and benchmarks, or when sure new fields won't affect logic)

Files:

  • lib/collection/src/shards/shard_holder/shard_mapping.rs
  • src/common/collections.rs
  • src/schema_generator.rs
  • lib/api/src/grpc/conversions.rs
  • lib/api/src/rest/models.rs
  • lib/api/build.rs
  • src/tonic/api/collections_api.rs
  • src/actix/api/shards_api.rs
  • lib/api/src/grpc/qdrant.rs
🧠 Learnings (9)
📚 Learning: 2025-03-20T13:19:35.328Z
Learnt from: timvisee
Repo: qdrant/qdrant PR: 6209
File: lib/collection/src/shards/shard_holder/shard_mapping.rs:119-122
Timestamp: 2025-03-20T13:19:35.328Z
Learning: The `to_map()` method in `ShardKeyMappingWrapper` is a temporary solution that will be replaced in a future version (likely in version 1.15 based on the TODO comment). Performance benchmarking for this method is not necessary as it's not used frequently and will be replaced with an implementation that doesn't require cloning.

Applied to files:

  • lib/collection/src/shards/shard_holder/shard_mapping.rs
📚 Learning: 2025-09-08T08:47:43.795Z
Learnt from: timvisee
Repo: qdrant/qdrant PR: 7188
File: lib/collection/src/update_handler.rs:810-813
Timestamp: 2025-09-08T08:47:43.795Z
Learning: In the Qdrant codebase, CollectionId implements traits that allow &CollectionId to convert Into<String>, so passing &collection_name to functions requiring Into<String> works correctly without needing .clone() or .to_string().

Applied to files:

  • src/common/collections.rs
📚 Learning: 2025-09-16T19:14:17.614Z
Learnt from: generall
Repo: qdrant/qdrant PR: 7183
File: lib/api/src/grpc/qdrant.rs:4263-4273
Timestamp: 2025-09-16T19:14:17.614Z
Learning: In qdrant, lib/api/src/grpc/qdrant.rs is auto-generated by prost-build; do not edit it directly. Make changes in lib/api/src/grpc/proto/points.proto (e.g., add [deprecated=true], doc comments, or encoding options), then regenerate the Rust code.

Applied to files:

  • src/schema_generator.rs
  • lib/api/src/grpc/conversions.rs
  • lib/api/src/grpc/qdrant.rs
📚 Learning: 2025-08-10T18:31:56.855Z
Learnt from: generall
Repo: qdrant/qdrant PR: 7006
File: lib/collection/src/operations/point_ops.rs:501-528
Timestamp: 2025-08-10T18:31:56.855Z
Learning: In Qdrant, batch operations validate that `ids`, `vectors`, and `payloads` (if present) have matching lengths at the REST API level in `lib/api/src/rest/validate.rs` through the `Validate` trait implementation for `Batch`. This validation happens before data is converted to internal structures like `PointInsertOperationsInternal`, so methods operating on these internal structures can safely assume the lengths match.

Applied to files:

  • src/schema_generator.rs
📚 Learning: 2025-08-10T18:30:02.986Z
Learnt from: generall
Repo: qdrant/qdrant PR: 7006
File: lib/collection/src/operations/verification/update.rs:158-174
Timestamp: 2025-08-10T18:30:02.986Z
Learning: In Qdrant's strict mode verification code (lib/collection/src/operations/verification/update.rs), exhaustive pattern matching without `..` is intentionally used for structs like PointsBatch and PointsList. This design pattern ensures compilation fails when new fields are added, forcing developers to explicitly consider how new fields should be handled in the indexed_filter_write method. This provides visibility and compile-time safety for struct evolution.

Applied to files:

  • src/schema_generator.rs
📚 Learning: 2025-08-10T18:26:12.443Z
Learnt from: generall
Repo: qdrant/qdrant PR: 7006
File: docs/redoc/master/openapi.json:13645-13652
Timestamp: 2025-08-10T18:26:12.443Z
Learning: In qdrant, docs/redoc/master/openapi.json is auto-generated from the REST schemas. To change field docs, edit lib/api/src/rest/schema.rs (e.g., add doc comments or #[schemars(description = ...)]). Specifically, UpdateVectors.update_filter lacked a description and should state: "If specified, only update vectors for points that match this filter; points not matching the filter are left unchanged."

Applied to files:

  • lib/api/src/rest/models.rs
📚 Learning: 2025-08-10T18:25:16.206Z
Learnt from: generall
Repo: qdrant/qdrant PR: 7006
File: docs/redoc/master/openapi.json:10626-10634
Timestamp: 2025-08-10T18:25:16.206Z
Learning: In Qdrant, docs/redoc/master/openapi.json is autogenerated from the Rust REST schema definitions (e.g., lib/api/src/rest/schema.rs). To change OpenAPI descriptions, update the Rust struct field doc comments/attributes rather than editing the JSON directly.

Applied to files:

  • lib/api/src/rest/models.rs
📚 Learning: 2025-08-15T15:56:36.821Z
Learnt from: coszio
Repo: qdrant/qdrant PR: 7065
File: lib/collection/src/operations/universal_query/shard_query.rs:0-0
Timestamp: 2025-08-15T15:56:36.821Z
Learning: Internal gRPC APIs in Qdrant don't require additional runtime validation when proto-level validation is already configured via build.rs range constraints.

Applied to files:

  • lib/api/build.rs
  • lib/api/src/grpc/qdrant.rs
📚 Learning: 2025-10-16T13:00:46.809Z
Learnt from: coszio
Repo: qdrant/qdrant PR: 7368
File: lib/shard/src/query/mod.rs:313-341
Timestamp: 2025-10-16T13:00:46.809Z
Learning: In the Qdrant codebase, for the `Feedback` query variant in `lib/shard/src/query/mod.rs`, validation for sparse vectors should happen down the line rather than early in the `query_enum_from_grpc_raw_query` function. The `Nearest` variant is treated as a special case where early validation with better error messages is acceptable.

Applied to files:

  • lib/api/src/grpc/qdrant.rs
🧬 Code graph analysis (4)
src/common/collections.rs (1)
lib/collection/src/shards/shard_holder/mod.rs (1)
  • new (85-122)
src/tonic/api/collections_api.rs (2)
lib/api/src/grpc/conversions.rs (18)
  • request (2752-2756)
  • request (2757-2761)
  • from (132-147)
  • from (151-162)
  • from (166-177)
  • from (181-188)
  • from (192-204)
  • from (208-224)
  • from (228-240)
  • from (244-249)
  • from (253-286)
  • from (290-295)
  • from (299-311)
  • from (315-327)
  • from (331-342)
  • from (346-357)
  • from (361-372)
  • from (376-402)
src/tonic/auth.rs (1)
  • extract_access (111-115)
tests/consensus_tests/auth_tests/test_jwt_access.py (1)
lib/storage/src/rbac/ops_checks.rs (13)
  • check_access (78-78)
  • check_access (109-111)
  • check_access (123-126)
  • check_access (138-140)
  • check_access (152-154)
  • check_access (166-168)
  • check_access (180-188)
  • check_access (200-203)
  • check_access (215-217)
  • check_access (229-237)
  • check_access (263-265)
  • check_access (277-279)
  • check_access (300-302)
lib/api/src/grpc/qdrant.rs (1)
src/actix/api/shards_api.rs (1)
  • list_shard_keys (18-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: integration-tests-consensus
  • GitHub Check: test-shard-snapshot-api-s3-minio
  • GitHub Check: test-consistency
  • GitHub Check: e2e-tests
  • GitHub Check: integration-tests
  • GitHub Check: rust-tests (ubuntu-latest)
  • GitHub Check: lint
  • GitHub Check: rust-tests (windows-latest)
  • GitHub Check: rust-tests (macos-latest)
  • GitHub Check: test-consensus-compose
  • GitHub Check: Build Qdrant Edge Python bindings
🔇 Additional comments (18)
tests/openapi_consistency_check.sh (1)

38-49: OpenAPI API-count bump looks consistent with new endpoint

Updating EXPECTED_NUMBER_OF_APIS to 70 aligns with adding the new shard-keys endpoint and associated schemas; the script’s checks and messaging remain correct.

lib/api/src/grpc/proto/collections_service.proto (1)

61-64: ListShardKeys RPC wiring is consistent with existing shard-key RPCs

The new ListShardKeys method, docs, and placement next to create/delete shard-key operations are coherent and follow existing service conventions.

src/schema_generator.rs (1)

3-4: Schema generator extension for ShardKeysResponse is correct

Importing ShardKeysResponse and adding it as field bo in AllDefinitions matches the pattern used for other REST models, ensuring the new response type is included in generated schemas.

Also applies to: 41-100

lib/api/src/grpc/conversions.rs (1)

51-60: gRPC ListShardKeysResponse conversion is consistent and efficient

The new (Instant, ShardKeysResponse) -> ListShardKeysResponse conversion correctly:

  • Flattens the REST shard-key collection into gRPC ShardKeyDescription items.
  • Reuses convert_shard_key_to_grpc for explicit type conversion.
  • Sets time from timing.elapsed().as_secs_f64(), matching other list-style responses.

Imports added for ListShardKeysResponse, ShardKeyDescription, and ShardKeysResponse are minimal and appropriate.

Also applies to: 65-66, 131-148

lib/api/src/grpc/proto/collections.proto (1)

793-812: Shard-keys proto messages follow existing collection patterns

ListShardKeysRequest, ShardKeyDescription, and ListShardKeysResponse mirror established collection APIs: a request keyed by collection_name, a dedicated item wrapper, and a response containing a list plus processing time. The design is consistent and future‑proof.

openapi/openapi-shards.ytt.yaml (1)

31-43: OpenAPI GET /collections/{collection_name}/shards definition is well-formed

The new list_shard_keys operation is correctly attached under the shards path, reuses the existing collection_name path parameter pattern, and returns the new ShardKeysResponse schema, matching the rest of the shard-key API surface.

src/tonic/api/collections_api.rs (1)

251-271: LGTM! Implementation follows established patterns.

The handler correctly implements the shard key listing logic following the same pattern as other read-only collection operations in this file (e.g., list, list_collection_aliases). The use of new_unchecked_verification_pass is appropriate for read operations.

tests/consensus_tests/auth_tests/test_jwt_access.py (2)

251-257: LGTM! Access configuration is appropriate.

The access flags (True, True, True) correctly allow read, collection read/write, and manage levels to list shard keys, which is appropriate for a read-only metadata operation. This aligns with similar operations like list_collection_aliases and get_collection_cluster_info.


1204-1210: LGTM! Test follows established patterns.

The test correctly validates access control for the new list_shard_keys endpoint using the same pattern as other endpoint tests in this file.

tests/openapi/helpers/collection_setup.py (1)

160-162: LGTM! Early return is appropriate for custom sharding.

Skipping point insertion when sharding_method == "custom" is correct because custom sharding requires explicit shard key creation before points can be inserted. This allows test code to create shard keys as needed.

src/common/collections.rs (1)

93-115: LGTM! Implementation correctly handles both sharding methods.

The function appropriately returns None for ShardingMethod::Auto (where shard keys don't apply) and iterates the shard key mapping for ShardingMethod::Custom. The access check and error handling are consistent with similar functions in this file.

lib/api/src/rest/models.rs (2)

165-169: LGTM! Good use of wrapper type for extensibility.

The ShardKeyDescription struct wraps the shard key, allowing for future extension with additional fields (e.g., shard IDs, metadata) without breaking the API, as discussed in the PR comments.


171-177: LGTM! Response structure is well-designed.

The Option<Vec<ShardKeyDescription>> correctly represents that shard keys are only present for custom sharding. The doc comment clearly explains this, and skip_serializing_if ensures cleaner JSON output.

src/actix/api/shards_api.rs (1)

17-32: LGTM! Handler follows Actix patterns correctly.

The implementation properly uses the helpers::time wrapper and new_unchecked_verification_pass for this read-only operation, consistent with other handlers in the codebase.

docs/redoc/master/openapi.json (1)

99-172: LGTM: REST shape aligns with existing patterns.

GET List shard keys endpoint looks consistent (tags, operationId, envelope).

lib/api/src/grpc/qdrant.rs (3)

2934-2959: Client wiring for ListShardKeys RPC looks correct

The new CollectionsClient::list_shard_keys method follows the same pattern as existing RPCs (ready check, codec, path /qdrant.Collections/ListShardKeys, method metadata, compression settings). No issues spotted here.


3073-3080: Collections service trait extension is consistent

The added list_shard_keys method on the Collections trait uses the expected request/response types and matches the client/server routing. Interface shape is consistent with other collection RPCs.


3768-3813: Server routing for /qdrant.Collections/ListShardKeys is correctly hooked up

The new match arm registers /qdrant.Collections/ListShardKeys, wires it through ListShardKeysSvc<T>, and applies the same compression and message-size config as other methods. This matches the client path and trait signature.

@qdrant qdrant deleted a comment from coderabbitai bot Nov 28, 2025
@qdrant qdrant deleted a comment from coderabbitai bot Nov 28, 2025
@coszio coszio merged commit 4f13b99 into qdrant:dev Nov 29, 2025
15 checks passed
timvisee pushed a commit that referenced this pull request Dec 3, 2025
@timvisee
Copy link
Member

timvisee commented Dec 4, 2025

We've just released Qdrant 1.16.2 which includes these changes.

Note that we only update our API spec and clients in 1.17.0, but the implemented call is usable now.

@amiremohamadi
Copy link
Contributor Author

@timvisee i've submitted a PR to the client
qdrant/rust-client#254

would appreciate a review when you have time!

@timvisee
Copy link
Member

We've released Qdrant 1.17.0 which includes this feature.

Documentation: https://qdrant.tech/documentation/guides/distributed_deployment/#user-defined-sharding

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants