Skip to content

[vector store 2/13] Remove custom sharding from the Qdrant store (speedkick) - #1654

Merged
edwinyyyu merged 1 commit into
MemMachine:speedkickfrom
edwinyyyu:feat/qdrant-remove-custom-sharding-speedkick
Sep 16, 2026
Merged

edwinyyyu merged 1 commit into
MemMachine:speedkickfrom
edwinyyyu:feat/qdrant-remove-custom-sharding-speedkick

Conversation

@edwinyyyu

@edwinyyyu edwinyyyu commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Purpose of the change

The Qdrant store could shard its native collection by logical collection (QdrantConf.is_distributed, CUSTOM sharding, one shard key per logical collection, a shard-key selector on every operation) so that a logical collection could be deleted by dropping its shard. The payload partition key was written and filtered in both modes, with the shard key on top, so no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured in #1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an explicit create_shard_key call of about 450 ms, 45 s for the hundred against 0.3 s with payload partitioning alone, including 10,000 points; 505 segments against 5, and still 5 after deleting and reusing tenants; and cluster mode is required, with a bootstrap --uri. At ten thousand tenants that is over an hour of shard-key creation and some 50,000 segments before a point is written. Qdrant's own guidance says the same: a physical structure per tenant is for the few oversized ones, the long tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing (a write to a dropped shard fails). Deletion is about to become a registry write that is O(1) and atomic as seen by every reader, a stale handle is fenced by that registry, and the points are reclaimed afterward by a filter-delete off the request path, so a shard per logical collection would only add its cost; it goes now, on the current shape, so the later changes do not carry it. Promoting a single oversized tenant to its own custom-sharded collection later, Qdrant's tiered arrangement, stays open: it is a separate collection, not a flag on this one.

is_distributed was never documented; a configuration naming it is rejected.

Stack

Slice 2 of 13, every PR targeting speedkick; merge bottom-up.

# PR change
1 #1606 (merged) Remove per-project filterable properties
2 #1654 (this PR) Remove custom sharding from the Qdrant store
3 #1630 Bound every request to a remote vector store by a configured timeout
4 #1622 Create a session's storage with the session, never on a request
5 #1623 Make the examples that write to a project create it first
6 #1624 Make no memory request create a project
7 #1625 Remove open-or-create and close from both stores
8 #1626 Rename logical collection to partition, and open to get, on both stores
9 #1627 Make a vector store one collection, with string-keyed partitions
10 #1631 Mint an incarnation per partition life in a SQL-arbitrated registry; delete logically, reclaim by purge
11 #1618 Let a deployment tune a Qdrant collection's HNSW, optimizers and quantization
#1597 EventMemory session, source and expansion: not a slice of this chain; 12 and 13 need it
12 #1628 Make a vector store filter only on the properties it declares
13 #1616 Close the filter union, and make negation the complement on every backend

This PR's own change is its last commit, bf33c427 (7 files changed, 9 insertions(+), 192 deletions(-)); it sits directly on speedkick, and #1630 is stacked on it.

Verification

ruff check, ruff format --check, ty check (two pre-existing spacy diagnostics), pytest packages/server/server_tests packages/client/client_tests: 2212 passed, 3 skipped, on the slice-11 tree (speedkick 973aad52 plus slices 2-11), 2026-09-16; every slice passed its own affected suites when built.

🤖 Generated with Claude Code

https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

@edwinyyyu edwinyyyu changed the title [vector store 7/13] Remove custom sharding from the Qdrant store (speedkick) [vector store 7/14] Remove custom sharding from the Qdrant store (speedkick) Sep 16, 2026
@edwinyyyu
edwinyyyu force-pushed the feat/qdrant-remove-custom-sharding-speedkick branch from b6850d3 to b488238 Compare September 16, 2026 18:57
@edwinyyyu edwinyyyu changed the title [vector store 7/14] Remove custom sharding from the Qdrant store (speedkick) [vector store 2/13] Remove custom sharding from the Qdrant store (speedkick) Sep 16, 2026
The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn
edwinyyyu added a commit to edwinyyyu/MemMachine that referenced this pull request Sep 17, 2026
…edkick) (MemMachine#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
edwinyyyu added a commit to edwinyyyu/MemMachine that referenced this pull request Sep 17, 2026
…edkick) (MemMachine#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 408b0a9)
edwinyyyu added a commit to edwinyyyu/MemMachine that referenced this pull request Sep 17, 2026
…edkick) (MemMachine#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 408b0a9)

@edwinyyyu edwinyyyu left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Found while auditing the main port, #1671. "is_distributed was never documented; a configuration naming it is rejected": the second half does not hold. SupportedDB.build_config does conf_cls(**conf), no configuration model sets extra="forbid", and pydantic's default is extra="ignore", so SupportedDB.QDRANT.build_config({"host": "h", "registry_database": "r", "is_distributed": True}) returns a QdrantConf with no error: the key is silently ignored. Same sentence on #1671.

edwinyyyu added a commit to edwinyyyu/MemMachine that referenced this pull request Sep 18, 2026
…edkick) (MemMachine#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 779362c)
edwinyyyu added a commit to edwinyyyu/MemMachine that referenced this pull request Sep 18, 2026
…edkick) (MemMachine#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 779362c)
edwinyyyu added a commit to edwinyyyu/MemMachine that referenced this pull request Sep 18, 2026
…edkick) (MemMachine#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 779362c)
edwinyyyu added a commit to edwinyyyu/MemMachine that referenced this pull request Sep 18, 2026
…edkick) (MemMachine#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 779362c)
edwinyyyu added a commit to edwinyyyu/MemMachine that referenced this pull request Sep 21, 2026
…edkick) (MemMachine#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 779362c)
edwinyyyu added a commit to edwinyyyu/MemMachine that referenced this pull request Sep 21, 2026
…edkick) (MemMachine#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 779362c)
edwinyyyu added a commit to edwinyyyu/MemMachine that referenced this pull request Sep 21, 2026
…edkick) (MemMachine#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 779362c)
edwinyyyu added a commit to edwinyyyu/MemMachine that referenced this pull request Sep 25, 2026
…edkick) (MemMachine#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in MemMachine#1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
(cherry picked from commit 779362c)
edwinyyyu added a commit that referenced this pull request Sep 25, 2026
…tore (port of #1654) (#1671)

[vector store 2/13] Remove custom sharding from the Qdrant store (speedkick) (#1654)

Remove custom sharding from the Qdrant store

The Qdrant store could shard its native collection by logical collection
(`QdrantConf.is_distributed`, CUSTOM sharding, one shard key per logical
collection, a shard-key selector on every operation) so that a logical
collection could be deleted by dropping its shard. The payload partition
key was written and filtered in both modes, with the shard key on top, so
no query changes here; what changes is the cost of a tenant.

A shard key is a physical structure, and its cost is per tenant. Measured
in #1564 (Qdrant 1.19.0, one hundred tenants): admitting a tenant is an
explicit `create_shard_key` call of about 450 ms, 45 s for the hundred
against 0.3 s with payload partitioning alone, including 10,000 points;
505 segments against 5, and still 5 after deleting and reusing tenants;
and cluster mode is required, with a bootstrap `--uri`. At ten thousand
tenants that is over an hour of shard-key creation and some 50,000
segments before a point is written. Qdrant's own guidance says the same:
a physical structure per tenant is for the few oversized ones, the long
tail is a payload value.

What the shard bought was the O(1) delete, and with it a kind of fencing
(a write to a dropped shard fails). Deletion is about to become a
registry write that is O(1) and atomic as seen by every reader, a stale
handle is fenced by that registry, and the points are reclaimed afterward
by a filter-delete off the request path, so a shard per logical
collection would only add its cost; it goes now, on the current shape, so
the later changes do not carry it. Promoting a single oversized tenant to
its own custom-sharded collection later, Qdrant's tiered arrangement,
stays open: it is a separate collection, not a flag on this one.

`is_distributed` was never documented; a configuration naming it is
rejected.

Claude-Session: https://claude.ai/code/session_01ESpWYTmCR7X3bJEpoA8SAn


(cherry picked from commit 779362c)

Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
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.

1 participant