2014-02-10

百行代码实现一个简单的Zset(SortedSet)

Views: 23081 | 5 Comments

排序的集合(Zset, SortedSet)是这样的一种集合数据结构, 集合中的元素不可重复, 而且元素之间根据每一个元素的权重来排序. Zset 是一种非常重要和应用广泛的数据结构, 是 Redis 数据库所支持的最核心一种. Zset 可用于排行榜, 好友列表, 去重, 历史记录等业务需求. 你可以理解一个 Zset 是一个下面结构的数据库表:

item,   score
UNIQUE, INDEX(int)

Item 列被加了 UNIQUE 约束, 所以可以去重. Score 列是加了索引的整数列, 可用于排序.

如果要在内存中实现一个 Zset 数据结构, 我们可以看 Redis 的源码.

Redis 用两个数据结构的组合来实现 Zset: Hashmap 和 Skiplist. Hashmap 存储的是元素对应 Redis 对象, 所以可以去重; Skiplist 用于排序. 虽然思路很简单, Redis 的实现代码量也不多, 但是要抽取出来使用也不是很方便. 所以, 我们可以实现一个简化版.

我用 C++ 来实现, 用到了 STL 容器, 代码量不过百行(不完全接口), 被应用在 SSDB 数据库的 key 过期功能上.

同样, 我也是用了两个数据结构, 不过是 std::map 和 std::set. map 用于去重, set 用于排序. 因为 STL 的 set 是排序的, 而且可以使用自定义的排序比较函数, 所以用起来非常方便. 当然, 你可以把 set 按成 map, 就可以实现 SortedHashmap 了.

class SortedSet
{
public:
	int size() const;
	int add(const std::string &key, int64_t score);
	int del(const std::string &key);
	// key will be pointed to the first time if SortedSet not empty
	int front(const std::string **key, int64_t *score=NULL) const;
	// the first item is copied into key if SortedSet not empty
	int front(std::string *key, int64_t *score=NULL) const;
	int pop_front();

private:
	struct Item
	{
		std::string key;
		int64_t score;
		
		bool operator<(const Item& b) const{
			return this->score < b.score
				|| (this->score == b.score && this->key < b.key);
		}
	};
	
	std::map<std::string, std::set<Item>::iterator> existed;
	std::set<Item> sorted_set;
};

具体的实现代码见: https://github.com/ideawu/ssdb/blob/master/src/util/sorted_set.cpp

Related posts:

  1. SSDB在大数据量日志分析中的应用案例
  2. 如何使用SSDB的zscan命令
  3. Redis 导数据的 PHP 脚本
  4. 用PHP遍历SSDB中的zset集合
  5. 用 HBase 来存储 zset
Posted by ideawu at 2014-02-10 20:28:11 Tags:

5 Responses to "百行代码实现一个简单的Zset(SortedSet)"

Leave a Comment