Loading

Redis高级数据类型

Redis高级数据类型

image-20210730213901188

1.语法

HyperLogLog.java

    // 统计20万个重复数据的独立总数
    @Test
public void testHyperLogLog(){

    String redisKey  = "test:hll:01";
    for (int i = 1; i <100000 ; i++) {
        redisTemplate.opsForHyperLogLog().add(redisKey,i);
    }

    for (int i = 1; i <100000 ; i++) {
        int r = (int) (Math.random() * 100000 + 1);
        redisTemplate.opsForHyperLogLog().add(redisKey,r);
    }

    System.out.println("redisTemplate.opsForHyperLogLog().size(redisKey) = " + redisTemplate.opsForHyperLogLog().size(redisKey));

}

//将3组数据合并,再统计合并后的重复数据的独立总数
@Test
public void testHyperLogLogUnion(){
    String redisKey2  = "test:hll:02";
    for (int i = 1; i <10000 ; i++) {
        redisTemplate.opsForHyperLogLog().add(redisKey2,i);
    }

    String redisKey3  = "test:hll:03";
    for (int i = 5001; i <15000 ; i++) {
        redisTemplate.opsForHyperLogLog().add(redisKey3,i);
    }

    String redisKey4  = "test:hll:04";
    for (int i = 1001; i <20000 ; i++) {
        redisTemplate.opsForHyperLogLog().add(redisKey4,i);
    }

    String unionKey = "test:hll:union";
    redisTemplate.opsForHyperLogLog().union(unionKey,redisKey2,redisKey3,redisKey4);

    System.out.println("redisTemplate.opsForHyperLogLog().size(unionKey) = " + redisTemplate.opsForHyperLogLog().size(unionKey));
}

BitMap.java

    //统计一组数据的布尔值
    @Test
    public void testBitMap(){

        String redisKey = "test:bm:01";
        //记录
        redisTemplate.opsForValue().setBit(redisKey,1,true);
        redisTemplate.opsForValue().setBit(redisKey,4,true);
        redisTemplate.opsForValue().setBit(redisKey,7,true);

        //查询
        System.out.println("redisTemplate.opsForValue().getBit(redisKey,0) = " + redisTemplate.opsForValue().getBit(redisKey, 0));
        System.out.println("redisTemplate.opsForValue().getBit(redisKey,0) = " + redisTemplate.opsForValue().getBit(redisKey, 1));
        System.out.println("redisTemplate.opsForValue().getBit(redisKey,0) = " + redisTemplate.opsForValue().getBit(redisKey, 2));

        // 统计出 true 的个数
        Object obj = redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection conn) throws DataAccessException {

                return conn.bitCount(redisKey.getBytes());
            }
        });

        System.out.println(obj);

    }

    //统计3组数据的布尔值,并对3组数据做or运算
    @Test
    public void testBitMapOperation(){

        String redisKey2 = "test:bm:02";
        redisTemplate.opsForValue().setBit(redisKey2,0,true);
        redisTemplate.opsForValue().setBit(redisKey2,1,true);
        redisTemplate.opsForValue().setBit(redisKey2,2,true);

        String redisKey3 = "test:bm:03";
        redisTemplate.opsForValue().setBit(redisKey3,2,true);
        redisTemplate.opsForValue().setBit(redisKey3,3,true);
        redisTemplate.opsForValue().setBit(redisKey3,4,true);

        String redisKey4 = "test:bm:04";
        redisTemplate.opsForValue().setBit(redisKey4,4,true);
        redisTemplate.opsForValue().setBit(redisKey4,5,true);
        redisTemplate.opsForValue().setBit(redisKey4,6,true);

        String redisKey = "test:bm:or";
        Object obj = redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection conn) throws DataAccessException {
                conn.bitOp(RedisStringCommands.BitOperation.OR,redisKey.getBytes(),redisKey2.getBytes(),redisKey3.getBytes(),redisKey4.getBytes());
                return conn.bitCount(redisKey.getBytes());
            }
        });

        System.out.println(obj);
        redisTemplate.opsForValue().getBit(redisKey,0);
        redisTemplate.opsForValue().getBit(redisKey,1);
        redisTemplate.opsForValue().getBit(redisKey,2);
        redisTemplate.opsForValue().getBit(redisKey,3);
        redisTemplate.opsForValue().getBit(redisKey,4);
        redisTemplate.opsForValue().getBit(redisKey,5);
        redisTemplate.opsForValue().getBit(redisKey,6);
    }
}

2.用途

image-20210730222053204

package com.zhuantai.community.service;

import com.zhuantai.community.uitls.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author ANTIA1
 * @date 2021/7/30 23:02
 */
@Service
public class DataService {

    @Autowired
    private RedisTemplate redisTemplate;

    private SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");

    // 将指定的IP计入UV
    public void recordUV(String ip){
        String redisKey = RedisKeyUtil.getUVKey(df.format(new Date()));
        redisTemplate.opsForHyperLogLog().add(redisKey,ip);
    }

    //统计指定日期范围内的UV
    public long calculateUV(Date startDate,Date endDate){
        if (startDate == null || endDate == null){
            throw new IllegalArgumentException("参数不能为空!");
        }
        //整理日期范围内的key
        List<String> keyList = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        while (!calendar.getTime().after(endDate)){
            String key = RedisKeyUtil.getUVKey(df.format(calendar.getTime()));
            keyList.add(key);
            calendar.add(Calendar.DATE,1);
        }

        //合并数据
        String redisKey = RedisKeyUtil.getUVKey(df.format(startDate),df.format(endDate));
        redisTemplate.opsForHyperLogLog().union(redisKey,keyList.toArray());

        //返回统计结果
        return redisTemplate.opsForHyperLogLog().size(redisKey);
    }

    // 将指定用户计入DAU
    public void recordDAU(int userId){
        String redisKey = RedisKeyUtil.getDAUKey(df.format(new Date()));
        redisTemplate.opsForValue().setBit(redisKey,userId,true);
    }

    //统计指定日期范围内的DAU
    public long calculateDAU(Date start,Date end){
        if (start == null || end == null){
            throw new IllegalArgumentException("参数不能为空!");
        }
        //整理日期范围内的key
        List<byte[]> keyList = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(start);
        while (!calendar.getTime().after(end)){
            String key = RedisKeyUtil.getDAUKey(df.format(calendar.getTime()));
            keyList.add(key.getBytes());
            calendar.add(Calendar.DATE,1);
        }

        //进行OR运算
        return (long) redisTemplate.execute(new RedisCallback() {
            @Override
            public Object doInRedis(RedisConnection conn) throws DataAccessException {
                String redisKey = RedisKeyUtil.getDAUKey(df.format(start),df.format(end));
                conn.bitOp(RedisStringCommands.BitOperation.OR,redisKey.getBytes(),keyList.toArray(new byte[0][0]));
                return conn.bitCount(redisKey.getBytes());
            }
        });

    }

}

创建一个拦截器在每次请求时统计UV和DAU

package com.zhuantai.community.controller.interceptor;

import com.zhuantai.community.entity.User;
import com.zhuantai.community.service.DataService;
import com.zhuantai.community.uitls.HostHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author ANTIA1
 * @date 2021/7/30 23:20
 */
@Component
public class DataInterceptor implements HandlerInterceptor {


    @Autowired
    private DataService dataService;

    @Autowired
    private HostHolder hostHolder;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //统计UV
        String ip = request.getRemoteHost();
        dataService.recordUV(ip);
        //统计DAU
        User user = hostHolder.getUser();
        if (user != null){
            dataService.recordDAU(user.getId());
        }
        return true;
    }
}
package com.zhuantai.community.config;

import com.zhuantai.community.controller.interceptor.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author ANTIA1
 * @date 2021/7/24 12:55
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    DataInterceptor dataInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(dataInterceptor)
                .excludePathPatterns("/**/*.css","/**/*.js","/**/*.png","/**/*.jpg","/**/*.jpeg");
    }
}

package com.zhuantai.community.controller;

import com.zhuantai.community.service.DataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.Date;

/**
 * @author ANTIA1
 * @date 2021/7/30 23:24
 */
@Controller
public class DataController {

    @Autowired
    DataService dataService;

    //统计页面
    @RequestMapping(value = "/data",method = {RequestMethod.POST,RequestMethod.GET})
    public String getDataPage(Model model){

        return "/site/admin/data";
    }

    //统计网站UV的请求
    @RequestMapping(path = "/data/uv",method = RequestMethod.POST)
    public String getUV(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,@DateTimeFormat(pattern = "yyyy-MM-dd") Date end,Model model){

        long uv = dataService.calculateUV(start, end);
        model.addAttribute("uvResult",uv);
        model.addAttribute("uvStartDate",start);
        model.addAttribute("uvEndDate",end);
        return "forward:/data";
    }

    //统计活跃用户
    @RequestMapping(path = "/data/dau",method = RequestMethod.POST)
    public String getDAU(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,@DateTimeFormat(pattern = "yyyy-MM-dd") Date end,Model model){

        long dau = dataService.calculateDAU(start, end);
        model.addAttribute("dauResult",dau);
        model.addAttribute("dauStartDate",start);
        model.addAttribute("dauEndDate",end);
        return "forward:/data";
    }

}
posted @ 2021-08-02 19:50  ANTIA11  阅读(116)  评论(0编辑  收藏  举报