Summary of zset usage skills of redis

zset is a sorted set. I mainly use it to rank users and count data in a specified interval. It can be used to replace the between and statement in mysql, and list several scenarios on how to use zset to solve needs.
Business scenario: users every day There is brushing data generated, including brushing time, brushing time, and brushing score.

Requirement 1: Ranking
according to the highest score of each user every day Requirement 2: Ranking according to the highest score of each user every day, if the scores are the same Adhere to the number of days to rank
Requirement 3: Count the brushing data of a single user in the past 7 days, and display the average score of brushing, the average score of brushing time, and how many days did not insist on brushing twice a day.

Requirement 1: Ranking according to the highest score of each user
every day Create a new zset every day, when a user brushing data comes over, use the zscore command in the zset to find out whether the current user has a record according to the user's id. If there is no current user record, Then directly use the zadd command to add a new record, the value is the user id, and the score is the brushing score. If there is a record, compare the score of the current record and the record in zset, which is greater, and insert the larger score into the corresponding user id. zset can be.
When the user checks the ranking of the brushing records, the user's ranking can be displayed according to the scores from large to small directly through the zRevRangeWithScores command. If you want to know the ranking of a certain user, you can find out the user's score according to the user id, and calculate the user's ranking by zset.count(zsetkey, userScore + 0.01, topScore) + 1. This logic is to add one to the user's score. 0.01, and then calculate how many users there are between the maximum value and the current value + 0.01, and the number of people obtained + 1 is the user ranking. This statement is written in java. zcount should be used in redis.

Requirement 2: Operational activities are ranked according to the highest score of each user per day. If the scores are the same, the ranking will be based on the number of days of persistence.
Taking into account the score and the number of days
For calculating the number of days of persistence, we need to use the set of redis to complete. When the user adds a brushing record, use a set to record the user's persistence date, such as 20161027. This record is added to the combination with the user id In the set of the key, and then use the scar command of the set (size in springdata) to calculate the user's persistence days. The advantages of doing this: 1. The set can filter duplicate dates, and each record can be inserted without thinking. 2: If an operation activity needs to count the number of days that users persist in a certain period of time, a new set can be created to store the operation activity. All dates, and then use the intersection operation of set to calculate the intersection, and count the number of elements, and the obtained data is the number of days that the total users of the operation activities persist.
After getting the insistday number of adherence days, corresponding to the user's brushing score in requirement 1, we make an expansion, such as *1000, provided that the user's insistence days will not exceed 999, each time the user data is inserted into the zset, the user's score is calculated score*1000+insistday. In this way, through the zRevRangeWithScores command, you can get the ranking based on user scores, and then the ranking list based on the number of days.

Requirement 3: Count the brushing data of a single user in the past 7 days, and display the average score of brushing, the average score of brushing time, and how many days there is no brushing. Insist on brushing your teeth twice a day.
The idea is the same as requirement 2, and make a fuss on the score of zset. Make the score into a double-type data that records the date, score, and duration at the same time, and divide it into 16 digits: the first 10 digits convert the time into a character type of yyMMddHHmm, and the middle three digits record the brushing score of 000. Be sure to occupy 3 digits, if not enough Substitute 0 with 0, record the duration of the last three digits, convert the three digits into strings, and finally assemble the 10+3+3 strings, convert them into doubles, and record them in each user's zset.
In this way, when 7 days of data are counted, only the dates of the first and seventh days can be calculated and converted into begindate: yyMMdd0000000000 endDate: yyMMdd2359999999, which can be obtained by using the rangeByScoreWithScores command of zset
zset.zRangeByScoreWithScores(zsetkey, begindate, mendDateax) all data in between


private Set<TypedTuple<Object>> getUserRecordBetweenDate(Integer userId,
			Date beginDate, Date endDate) {
		String beginStr = DateUtil.dateToStr(beginDate, "yyMMdd");
		String endStr = DateUtil.dateToStr(endDate, "yyMMdd");
		StringBuffer sbbegin = new StringBuffer();
		sbbegin.append(beginStr);
		sbbegin.append("0000");// hour and minute
		sbbegin.append("000");// Score
		sbbegin.append("000");// brushing time
		Double min = Double.valueOf(sbbegin.toString());
		StringBuffer sbend = new StringBuffer();
		sbend.append(endStr);
		sbend.append("2359");
		sbend.append("100");
		sbend.append("999");
		Double max = Double.valueOf(sbend.toString());
		String zsetkey = Constant.RedisZsetEnum.USERALLRECORD.getKey() + userId;
		ZSetOperations<String, Object> zset = redisService
				.getZsetRedisTemplate();
		Set<TypedTuple<Object>> userZset = zset.rangeByScoreWithScores(zsetkey,
				min, max);
return userZset;

然后对score转化成string型,利用substring(10,13),substring(13,16)得到刷牙分数和刷牙时长,对其求和,再除以条数即位平均数。
对应没有坚持两次的天数统计:循环遍历开始日期到结束日期组成的列表,利用rangeByScoreWithScores命令把begindate与endDate中的yyMMdd换成那一天的日期即可,如果得到的结果个数<2则将统计的天数+1

需要注意的问题:
1.在zset中声明的类型与调用的类型一定要统一。比如声明的zset中value的值为String,那么如果调用的时候哪怕你知道用户id为Integer型12345,也要将其转化为String才能调用,否则是得不到数据的

2.在需求三中实际上有个漏洞,如果数据是当天23:59之后的时间,其实最后的秒数是被忽略了。一个是业务的考虑,不需要太顾及,另外一个就是在zset的score中,对于double型的数据,如果太长,超过了17位,则其采用科学计数法记录的数据会有误差,后面的数据就记不住了,对于我们的需求中,需要一个数据同时完成时间,得分,时长的记录,所以就对score的形式进行了缩减,把年的前两位减掉,把日期的秒数减掉,以保证16位的长度。另外在获取score的时候,得到的是科学计数法的数据,我通过这段代码将其转化为string

public static String getStringFromDouble(Double d){
		DecimalFormat format = new DecimalFormat("#");
		String a = format.format(d);
		return a;
	}[size=large][/size]

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326564144&siteId=291194637