This is an automated email from the ASF dual-hosted git repository.
git-hulk pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git
The following commit(s) were added to refs/heads/unstable by this push:
new 3583e5dd3 refactor: avoid sorting inputs for ZINTERCARD (#3697)
3583e5dd3 is described below
commit 3583e5dd316c8918f7d36931fe361ab890a59594
Author: nkysg <[email protected]>
AuthorDate: Mon Oct 26 19:27:41 2026 +0800
refactor: avoid sorting inputs for ZINTERCARD (#3697)
Summary
Avoid sorting and copying all input member lists when calculating
`ZINTERCARD`.
- Use `std::min_element` to select the smallest input set as the
intersection base.
- Iterate over all remaining sets while skipping the selected base
iterator.
- Replace the per-member map counter with a local counter.
The previous implementation sorted every input list only to select the
smallest one, copied that list, and allocated map entries for each
candidate member.
## Tests
- Added `ZINTERCARD` coverage where the smallest input is not the first
key.
- Added `LIMIT` coverage for the same input order.
- `gofmt -w tests/gocase/unit/type/zset/zset_test.go`
- LLVM 18 `clang-tidy` on `src/types/redis_zset.cc`.
## AI-assisted contribution
OpenAI Codex was used to draft the unit tests for this change.
---
src/types/redis_zset.cc | 20 ++++++++++----------
tests/gocase/unit/type/zset/zset_test.go | 21 +++++++++++++++++++++
2 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/src/types/redis_zset.cc b/src/types/redis_zset.cc
index 26a2aee70..1ea50ae91 100644
--- a/src/types/redis_zset.cc
+++ b/src/types/redis_zset.cc
@@ -717,23 +717,23 @@ rocksdb::Status ZSet::InterCard(engine::Context &ctx,
const std::vector<std::str
if (!s.ok() || mscores.empty()) return s;
mscores_list.emplace_back(std::move(mscores));
}
- std::sort(mscores_list.begin(), mscores_list.end(),
- [](const MemberScores &v1, const MemberScores &v2) { return
v1.size() < v2.size(); });
-
- auto base_mscores = mscores_list[0];
- std::map<std::string, size_t> member_counters;
+ const auto base_it =
+ std::min_element(mscores_list.cbegin(), mscores_list.cend(),
+ [](const MemberScores &v1, const MemberScores &v2) {
return v1.size() < v2.size(); });
+ const auto &base_mscores = *base_it;
uint64_t cardinality = 0;
for (const auto &base_ms : base_mscores) {
- member_counters[base_ms.member] = 1;
- for (size_t i = 1; i < mscores_list.size(); i++) {
- for (const auto &ms : mscores_list[i]) {
+ size_t member_count = 1;
+ for (auto it = mscores_list.cbegin(); it != mscores_list.cend(); ++it) {
+ if (it == base_it) continue;
+ for (const auto &ms : *it) {
if (base_ms.member == ms.member) {
- member_counters[ms.member]++;
+ member_count++;
break;
}
}
}
- if (member_counters[base_ms.member] == mscores_list.size()) {
+ if (member_count == mscores_list.size()) {
cardinality++;
if (limit > 0 && cardinality >= limit) {
*inter_cnt = limit;
diff --git a/tests/gocase/unit/type/zset/zset_test.go
b/tests/gocase/unit/type/zset/zset_test.go
index 0f9fa6f44..4dead0626 100644
--- a/tests/gocase/unit/type/zset/zset_test.go
+++ b/tests/gocase/unit/type/zset/zset_test.go
@@ -1295,6 +1295,27 @@ func basicTests(t *testing.T, rdb *redis.Client, ctx
context.Context, enabledRES
})
+ t.Run(fmt.Sprintf("ZINTERCARD with non-first smallest input - %s",
encoding), func(t *testing.T) {
+ createZset(rdb, ctx, "zset_large", []redis.Z{
+ {Score: 1, Member: "a"},
+ {Score: 2, Member: "b"},
+ {Score: 3, Member: "c"},
+ {Score: 4, Member: "d"},
+ })
+ createZset(rdb, ctx, "zset_small", []redis.Z{
+ {Score: 1, Member: "a"},
+ {Score: 2, Member: "b"},
+ })
+ createZset(rdb, ctx, "zset_medium", []redis.Z{
+ {Score: 1, Member: "a"},
+ {Score: 2, Member: "b"},
+ {Score: 3, Member: "e"},
+ })
+
+ require.Equal(t, int64(2), rdb.ZInterCard(ctx, 0, "zset_large",
"zset_small", "zset_medium").Val())
+ require.Equal(t, int64(1), rdb.ZInterCard(ctx, 1, "zset_large",
"zset_small", "zset_medium").Val())
+ })
+
t.Run(fmt.Sprintf("ZMSCORE - %s", encoding), func(t *testing.T) {
rdb.Del(ctx, "zset")
createZset(rdb, ctx, "zset", []redis.Z{