当前位置: 首页 > article >正文

附件商户,用户签到,uv统计功能(geo,bitmap,hyperloglog结构的使用)

目录

  • 附近商户
    • 一:Geo数据结构
    • 二:附近商户搜索
  • 用户签到
    • 一:BitMap功能演示
    • 二:实现签到功能
    • 三:统计签到功能
  • uv统计
    • 一:hyperloglog的用法
    • 二:测试百万数据的t'ji
    • 二:测试百万数据的t'ji

附近商户

一:Geo数据结构

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

二:附近商户搜索

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

编写一个测试方法,将店铺的信息:经纬度传入geo中,且按照typeid分组查询,因为我们查询距离都是在一个模块中查看的,所以需要根据类型分组;member就是店铺的id;

@Test
    void loadShopData() {
        //获取店铺的所有信息
        List<Shop> list = shopService.list();
        //使用stream流对list进行分组,按照typeid
        Map<Long, List<Shop>> collect = list.stream().collect(Collectors.groupingBy(Shop::getTypeId));
        //遍历map,获取每个类型的id和每个类型的所有商家,每一次查询都是一个typeid
        for (Map.Entry<Long, List<Shop>> longListEntry : collect.entrySet()) {
            Long typeId = longListEntry.getKey();
            String key =RedisConstants.SHOP_GEO_KEY + typeId;
            List<Shop> value = longListEntry.getValue();
            //创建一个GeoLocation的集合原来存储geo相关信息
            List<RedisGeoCommands.GeoLocation<String>> locations=new ArrayList<>(value.size());
            for (Shop shop : value) {
//                stringRedisTemplate.opsForGeo().add(key,new Point(shop.getX(),shop.getY())
//                ,shop.getId().toString());
                //写入信息:x,y,member
                locations.add( new RedisGeoCommands.GeoLocation<String>(shop.getId().toString(),
                        new Point(shop.getX(),shop.getY())));
            }
            //将每个类型的店铺geo信息批量插入redis
            stringRedisTemplate.opsForGeo().add(key,  locations);
        }

然后就要将商品连带着距离返回给前端,并且返回的数据是以距离进行排序:

@Override
@Transactional
public Result queryShopByType(Integer typeId, Integer current, Double x, Double y) {
    //判断有没有传入x,和y,没有就直接去数据库查询
    if (x == null || y == null) {
        Page<Shop> shopPage = query().eq("type_id", typeId).
                page(new Page<Shop>(current, SystemConstants.DEFAULT_PAGE_SIZE));
        return Result.ok(shopPage.getRecords());
    }
    String key = RedisConstants.SHOP_GEO_KEY + typeId;
    //设置redis-geo中分页查询的参数
    Integer from = (current - 1) * SystemConstants.DEFAULT_PAGE_SIZE;//开始的索引
    Integer end = current * SystemConstants.DEFAULT_PAGE_SIZE;//结束的索引
    //从redis中的geo中搜索附近的店铺id并且按照距离排序
    GeoResults<RedisGeoCommands.GeoLocation<String>> search = stringRedisTemplate.opsForGeo().search(
            key,
            GeoReference.fromCoordinate(x, y),
            new Distance(5000),
            RedisGeoCommands.
                    GeoSearchCommandArgs.
                    newGeoSearchArgs().includeDistance()
                    .limit(end)
    );
    if (search == null) {
        return Result.ok(Collections.emptyList());
    }
    //获取geo中的内容,每个内容都包含value的值,和距离
    List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = search.getContent();
    List<Long> ids = new ArrayList<>(content.size());
    Map<String, Distance> map = new HashMap<>(content.size());
    //遍历每一条内容,并且将获取到的value(店铺id)和距离存储起来,店铺id用list存储,距离因为是和店铺在一起的,所以选择用map来存储,能够保留对应关系
    //因为是分页查询,前面获取的是从0到end的所以内容,我们这里要从from开始而不是0开始,所以使用stream流的skip,直接跳过0-from,从from开始
    content.stream().skip(from).forEach(geoResult -> {
        //将店铺id存入集合,将距离存入map
                String name = geoResult.getContent().getName();
                ids.add(Long.valueOf(name));
                map.put(name, geoResult.getDistance());
            }
    );
    //判断集合是否为空,因为刚才我们从跳过了前面的从from开始,所以获取到的id集合可能为空,所以要判断一下,否则在sql的in中会报错
    if (ids==null||ids.isEmpty()){
        return Result.ok();
    }
    //一样的将集合转成字符串,用‘,’隔开
    String join = StrUtil.join(",", ids);
    //从数据库中查询id集合中的对应的店铺,并且顺序要和ids的顺序一致
    List<Shop> shops = query().in("id", ids).
            last("order by field(id," + join + ")").list();
    //遍历每一个shop,为他们的distance属性赋值
    for (Shop shop : shops) {
        String id = shop.getId().toString();
        Distance distance = map.get(id);
        shop.setDistance(distance.getValue());
    }
    return Result.ok(shops);
}

用户签到

一:BitMap功能演示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用法:setbit:向指定位置存入一个0或1,getbit,从指定位置取出值0/1;bitcount,统计bitmap中值为1的个数;

bitops,查询数组中第一个是0或者1的位置;

二:实现签到功能

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

实现签到功能我们就使用bitmap,因为签到对我们来说就是签上和没签上,签上就是1,没签上就是0,我们可以以一个月为一个key,然后以bitmap来存储就行,在java中使用bitmap是和字符串一起的:

@Override
public Result sign() {
    Long id = UserHolder.getUser().getId();
    LocalDate now = LocalDate.now();
    String format = now.format(DateTimeFormatter.ofPattern("yyyy:MM"));
    String key=RedisConstants.USER_SIGN_KEY+id+format;
    //true代表我们设置的值是1;
    stringRedisTemplate.opsForValue().setBit(key,now.getDayOfMonth()-1,true);
    return Result.ok();
}

三:统计签到功能

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

统计签到就是从今天开始向前,有多少个连续的1;

首先我们要得到到今天为止这个月所有签到的数据,可以使用bitfield获取

如果从后向前遍历每个bit位:可以先与1做与运算,然后再向右移一位;

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

@Override
public Result signCount() {
    Long userId = UserHolder.getUser().getId();
    LocalDate now = LocalDate.now();
    String format = now.format(DateTimeFormatter.ofPattern("yyyy:MM"));
    String key=RedisConstants.USER_SIGN_KEY+userId+format;
    int dayOfMonth = now.getDayOfMonth();
    //bitfield key get u14 0表示获取从0开始14个字节,放到这就是从0开始到当前日的所有签到数据
    List<Long> longs = stringRedisTemplate.opsForValue().bitField(key,
            BitFieldSubCommands.create().
                    get(BitFieldSubCommands.BitFieldType.unsigned(dayOfMonth)).valueAt(0));
    //健壮性判断
    if (longs==null||longs.isEmpty()){
        return Result.ok();
    }
    //我们虽然得到的是一个集合,但是我们的值只有一个直接获取就行
    Long res = longs.get(0);
    if (res==0||res==null){
        return Result.ok();
    }
    //计数器
    Integer count=0;
    //循环统计
    while (true){
        //与1做与运算,得到当前最后一位是0还是1
        long i =  (res&1);
        //是1就计数器加1
        if (i==1){
            count++;
        }else {
            //不是1直接结束循环
            break;
        }
        //最后要将数字向右移一位,不然会死循环
        res>>>=1;
    }
    return Result.ok(count);
}

uv统计

一:hyperloglog的用法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

uv:用户量统计

pv:点击量统计

hhl在redis中如何使用:

pfadd:将要统计的值添加进去,比如用户id

pfcount:统计

pfmerge:合并统计量

二:测试百万数据的t’ji

存中…(img-80mHMYws-1730682836468)]

[外链图片转存中…(img-Jn0VjHSl-1730682836468)]

uv:用户量统计

pv:点击量统计

hhl在redis中如何使用:

pfadd:将要统计的值添加进去,比如用户id

pfcount:统计

pfmerge:合并统计量

二:测试百万数据的t’ji

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传


http://www.kler.cn/a/381880.html

相关文章:

  • CSS基础知识六(浮动的高度塌陷问题及解决方案)
  • iptables 规则备份和恢复
  • 小菜家教平台:基于SpringBoot+Vue打造一站式学习管理系统
  • 基于python深度学习的交通标志图像识别设计与实现,卷积神经网络(CNN)作为主要架构
  • 蓬勃发展:移动开发——关于软件开发你需要知道些什么
  • 详解数据字典及其主要条目
  • 如何使用RabbitMQ和Python实现广播消息
  • 深度学习基础知识-Batch Normalization(BN)超详细解析
  • 第二节 管道符、重定向与环境变量
  • 手写一个axios方法
  • python爬取旅游攻略(1)
  • SparkSql读取数据的方式
  • 多模态PaliGemma——Google推出的基于SigLIP和Gemma的视觉语言模型
  • 十四届蓝桥杯STEMA考试Python真题试卷第二套第四题
  • (八)JavaWeb后端开发——Tomcat
  • 使用GitHub Actions实现CI/CD流程
  • JavaScript数据类型- Symbol 详解
  • 各种网络设备的工作原理
  • Hive SQL中判断内容包含情况的全面指南
  • MR30分布式IO模块与高效PLC协同
  • 鸥柏(OBOO)户外触摸广告屏科技创新 高速服务区收费站案例
  • SAP ABAP开发学习——WDA 二 控制器
  • 【笔记】变压器-热损耗-频响曲线推导 - 02 预备知识
  • 如何完全禁用Ant Design Vue 4自带样式
  • 如何使用Web-Check和cpolar实现安全的远程网站监测与管理
  • 华为HarmonyOS借助AR引擎帮助应用实现虚拟与现实交互的能力2-管理AR会话