void test_zsets_union(Ardb& db) { DBID dbid = 0; db.ZClear(dbid, "myzset1"); db.ZClear(dbid, "myzset2"); db.ZAdd(dbid, "myzset1", ValueData((int64) 1), "one"); db.ZAdd(dbid, "myzset1", ValueData((int64) 2), "two"); db.ZAdd(dbid, "myzset2", ValueData((int64) 1), "one"); db.ZAdd(dbid, "myzset2", ValueData((int64) 2), "two"); db.ZAdd(dbid, "myzset2", ValueData((int64) 3), "three"); SliceArray keys; keys.push_back("myzset1"); keys.push_back("myzset2"); WeightArray ws; ws.push_back(10); ws.push_back(4); db.ZUnionStore(dbid, "myzset3", keys, ws); CHECK_FATAL(db.ZCard(dbid, "myzset3") != 3, "Fail:"); ZSetQueryOptions options; options.withscores = true; ValueDataArray values; db.ZRange(dbid, "myzset3", 0, -1, values, options); std::string str; CHECK_FATAL(values.size() != 6, "Fail:%zu", values.size()); CHECK_FATAL(values[0].ToString(str) != "three", "Fail:%s", values[0].ToString(str).c_str()); CHECK_FATAL(values[2].ToString(str) != "one", "Fail:%s", values[2].ToString(str).c_str()); CHECK_FATAL(values[4].ToString(str) != "two", "Fail:%s", values[4].ToString(str).c_str()); }
void test_zsets_inter(Ardb& db) { DBID dbid = 0; db.ZClear(dbid, "myzset1"); db.ZClear(dbid, "myzset2"); db.ZAdd(dbid, "myzset1", ValueData((int64) 1), "one"); db.ZAdd(dbid, "myzset1", ValueData((int64) 2), "two"); db.ZAdd(dbid, "myzset2", ValueData((int64) 1), "one"); db.ZAdd(dbid, "myzset2", ValueData((int64) 2), "two"); db.ZAdd(dbid, "myzset2", ValueData((int64) 3), "three"); SliceArray keys; keys.push_back("myzset1"); keys.push_back("myzset2"); WeightArray ws; ws.push_back(20); ws.push_back(4); db.ZInterStore(dbid, "myzset3", keys, ws); int zcard = db.ZCard(dbid, "myzset3"); CHECK_FATAL(zcard != 2, "Fail:%d", zcard); ZSetQueryOptions options; options.withscores = true; ValueDataArray values; db.ZRange(dbid, "myzset3", 0, -1, values, options); std::string str; CHECK_FATAL(values.size() != 4, "Fail:%zu", values.size()); CHECK_FATAL(values[0].ToString(str) != "one", "Fail:"); }
int Ardb::ZUnionStore(const DBID& db, const Slice& dst, SliceArray& keys, WeightArray& weights, AggregateType type) { while (weights.size() < keys.size()) { weights.push_back(1); } ValueScoreMap vm; struct ZUnionWalk: public WalkHandler { uint32_t z_weight; ValueScoreMap& z_vm; AggregateType z_aggre_type; ZUnionWalk(uint32_t ws, ValueScoreMap& vm, AggregateType type) : z_weight(ws), z_vm(vm), z_aggre_type(type) { } int OnKeyValue(KeyObject* k, ValueObject* value, uint32 cursor) { ZSetKeyObject* zsk = (ZSetKeyObject*) k; double score = 0; switch (z_aggre_type) { case AGGREGATE_MIN: { score = z_weight * zsk->score; if (score < z_vm[zsk->value]) { z_vm[zsk->value] = score; } break; } case AGGREGATE_MAX: { score = z_weight * (zsk->score); if (score > z_vm[zsk->value]) { z_vm[zsk->value] = score; } break; } case AGGREGATE_SUM: default: { score = z_weight * (zsk->score) + z_vm[zsk->value]; z_vm[zsk->value] = score; break; } } return 0; } }; SliceArray::iterator kit = keys.begin(); uint32_t idx = 0; while (kit != keys.end()) { ZSetMetaValue meta; if (0 == GetZSetMetaValue(db, *kit, meta)) { Slice empty; ZSetKeyObject tmp(*kit, empty, meta.min_score, db); ZUnionWalk walk(weights[idx], vm, type); Walk(tmp, false, &walk); } idx++; kit++; } if (vm.size() > 0) { double min_score = 0, max_score = 0; BatchWriteGuard guard(GetEngine()); ZClear(db, dst); KeyLockerGuard keyguard(m_key_locker, db, dst); ZSetMetaValue meta; meta.size = vm.size(); while (!vm.empty()) { ValueScoreMap::iterator it = vm.begin(); ZSetKeyObject zsk(dst, it->first, it->second, db); ValueObject zsv; zsv.type = EMPTY; ZSetScoreKeyObject zk(dst, it->first, db); ValueObject zv; zv.type = DOUBLE; zv.v.double_v = it->second; if (zv.v.double_v < min_score) { min_score = zv.v.double_v; } if (zv.v.double_v > max_score) { max_score = zv.v.double_v; } SetValue(zsk, zsv); SetValue(zk, zv); //reduce memory footprint for huge data set vm.erase(it); } meta.min_score = min_score; meta.max_score = max_score; SetZSetMetaValue(db, dst, meta); } return vm.size(); }
int Ardb::ZInterStore(const DBID& db, const Slice& dst, SliceArray& keys, WeightArray& weights, AggregateType type) { while (weights.size() < keys.size()) { weights.push_back(1); } uint32_t min_size = 0; ZSetMetaValueArray metas; uint32_t min_idx = 0; uint32_t idx = 0; SliceArray::iterator kit = keys.begin(); while (kit != keys.end()) { ZSetMetaValue meta; if (0 == GetZSetMetaValue(db, *kit, meta)) { if (min_size == 0 || min_size > meta.size) { min_size = meta.size; min_idx = idx; } } metas.push_back(meta); kit++; idx++; } struct ZInterWalk: public WalkHandler { uint32_t z_weight; ValueScoreMap& z_cmp; ValueScoreMap& z_result; AggregateType z_aggre_type; ZInterWalk(uint32_t weight, ValueScoreMap& cmp, ValueScoreMap& result, AggregateType type) : z_weight(weight), z_cmp(cmp), z_result(result), z_aggre_type( type) { } int OnKeyValue(KeyObject* k, ValueObject* value, uint32 cursor) { ZSetKeyObject* zsk = (ZSetKeyObject*) k; if ((&z_cmp != &z_result) && z_cmp.count(zsk->value) == 0) { return 0; } switch (z_aggre_type) { case AGGREGATE_MIN: { double score = z_weight * zsk->score; ValueScoreMap::iterator it = z_cmp.find(zsk->value); if (it == z_cmp.end() || score < it->second) { z_result[zsk->value] = score; } break; } case AGGREGATE_MAX: { double score = z_weight * zsk->score; ValueScoreMap::iterator it = z_cmp.find(zsk->value); if (it == z_cmp.end() || score > it->second) { z_result[zsk->value] = score; } break; } case AGGREGATE_SUM: default: { if (z_cmp.count(zsk->value) == 0) { z_result[zsk->value] = z_weight * (zsk->score); } else { z_result[zsk->value] = z_weight * (zsk->score) + z_cmp[zsk->value]; } break; } } return 0; } }; ValueScoreMap cmp1, cmp2; Slice empty; ZSetKeyObject cmp_start(keys[min_idx], empty, metas[min_idx].min_score, db); ZInterWalk walk(weights[min_idx], cmp1, cmp1, type); Walk(cmp_start, false, &walk); ValueScoreMap* cmp = &cmp1; ValueScoreMap* result = &cmp2; for (uint32_t i = 0; i < keys.size(); i++) { if (i != min_idx) { Slice empty; ZSetKeyObject tmp(keys.at(i), empty, metas[i].min_score, db); ZInterWalk walk(weights[i], *cmp, *result, type); Walk(tmp, false, &walk); cmp->clear(); ValueScoreMap* old = cmp; cmp = result; result = old; } } if (cmp->size() > 0) { double min_score = 0, max_score = 0; BatchWriteGuard guard(GetEngine()); ZClear(db, dst); KeyLockerGuard keyguard(m_key_locker, db, dst); ZSetMetaValue meta; meta.size = cmp->size(); while (!cmp->empty()) { ValueScoreMap::iterator it = cmp->begin(); ZSetKeyObject zsk(dst, it->first, it->second, db); ValueObject zsv; zsv.type = EMPTY; ZSetScoreKeyObject zk(dst, it->first, db); ValueObject zv; zv.type = DOUBLE; zv.v.double_v = it->second; if (zv.v.double_v < min_score) { min_score = zv.v.double_v; } if (zv.v.double_v > max_score) { max_score = zv.v.double_v; } SetValue(zsk, zsv); SetValue(zk, zv); //reduce memory footprint for huge data set cmp->erase(it); } meta.min_score = min_score; meta.max_score = max_score; SetZSetMetaValue(db, dst, meta); } return cmp->size(); }