4. Feed流








127.0.0.1:6379> ZREVRANGEBYSCORE z1 1000 0 WITHSCORES LIMIT 0 3根据分数查询z1 最大当前时间 最小时间 显示分数 从0开始查3条127.0.0.1:6379> ZREVRANGEBYSCORE z1 5 0 WITHSCORES LIMIT 1 3上次查询最小的是 5 所以最大从5 开始最小值不管 然后 LIMIE 后面找下一个 不包括5 所以为1 查询3条
根据Zset查询 因为第一次查询没有上一次的最小值 所以为当前时间戳 然后
LIMIT开始给0滚动查询 每一次查询上一次查询的最小值(分数)开始 防止Feed新消息导致消息混乱
但是当查询到的元素有score一样的情况 任然会混乱 所以LIMIT跳过的应当为上一次查询的最小值重复的个数


Controller
@GetMapping("of/follow")public Result getFeedBlog(@RequestParam("lastId") Long max, // 上一次查询的最小值的时间戳@RequestParam(value = "offset", defaultValue = "0") Integer offset// 偏移量 第一次没有 默认0) {return followService.queryFeedById(max, offset);}
Service
public Result queryFeedById(Long max, Integer offset) {// 获取当前用户idLong userId = UserHolder.getUser().getId();if (userId == null) {return Result.fail("请登录!");}String key = BlogConst.FAN_INBOX + userId;// 查询收件箱Set<ZSetOperations.TypedTuple<String>> blogIdByScores = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, 0, max, offset, 3);if (blogIdByScores == null || blogIdByScores.isEmpty()) {return Result.ok();}// 解析数据List<Long> ids = new ArrayList<>(blogIdByScores.size());long minTime = 0; // 这个Set底层是TreeSetint os = 1; // 初始化为1for (ZSetOperations.TypedTuple<String> blogIdByScore : blogIdByScores) {String idStr = blogIdByScore.getValue();long time = blogIdByScore.getScore().longValue(); // 5 4 4 2 2 不置为1的话offset为 4 就错了if (time == minTime) {os++;} else {minTime = time;os = 1;}ids.add(Long.valueOf(idStr));}// 根据id查询blogList<Blog> blogs = query().in("id",ids).last("ORDER BY FIELD( id"+StrUtil.join(",",ids)+")").list();blogs.forEach(blog -> {queryBlogUser(blog); // 查询有关用户isBlogLiked(blog); // 查询是否被点赞});// 封装返回ScoreResult<Blog> result = new ScoreResult<>(blogs,minTime,offset);return Result.ok(result);}
4 附近商铺
4.1 GEO数据类型


$ 1GEOADD g1 116.378248 39.865275 bjn 116.42803 39.903738 bj 116.322287 39.893729 bjx$ 2127.0.0.1:6379> GEODIST g1 bjx bj"9091.5648"127.0.0.1:6379> GEODIST g1 bjx bj KM"9.0916"$ 3127.0.0.1:6379> GEOSEARCH g1 FROMLONLAT 116.397904 39.909005 BYRADIUS 10 km WITHDIST1) 1) "bj"2) "2.6361"2) 1) "bjn"2) "5.1452"3) 1) "bjx"2) "6.6723"GEOSEARCH key [FROMMEMBER member] [FROMLONLAT longitude latitude] [BYRADIUS radius M|KM|FT|MI] [BYBOX width height M|KM|FT|MI] [ASC|DESC] [COUNT count [ANY]] [WITHCOORD] [WITHDIST] [WITHHASH]summary: Query a sorted set representing a geospatial index to fetch members inside an area of a box or a circle.since: 6.2.0
4.2 java
@Testvoid shopImportGeo() {Map<Long, List<Shop>> listMap = shopService.list().stream().collect(Collectors.groupingBy(Shop::getTypeId));for (Map.Entry<Long, List<Shop>> entry : listMap.entrySet()) {Long typeId = entry.getKey();List<Shop> shopList = entry.getValue();List<RedisGeoCommands.GeoLocation<String>> loctions = shopList.stream().map(shop ->new RedisGeoCommands.GeoLocation<>(shop.getId().toString(), new Point(shop.getX(), shop.getY()))).collect(Collectors.toList());redisTemplate.opsForGeo().add(CacheConst.SHOP_GEO_PREFIX + typeId, loctions);}}

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><exclusions><exclusion><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId></exclusion><exclusion><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>2.6.2</version></dependency><dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId><version>6.1.8.RELEASE</version></dependency>
@Overridepublic Result queryShopByType(Integer typeId, Integer current, Double x, Double y) {// 1.判断是否需要根据坐标查询if (x == null || y == null) {// 不需要坐标查询,按数据库查询Page<Shop> page = query().eq("type_id", typeId).page(new Page<>(current, SystemConstants.DEFAULT_PAGE_SIZE));// 返回数据return Result.ok(page.getRecords());}// 2.计算分页参数int from = (current - 1) * SystemConstants.DEFAULT_PAGE_SIZE;int end = current * SystemConstants.DEFAULT_PAGE_SIZE;// 3.查询redis、按照距离排序、分页。结果:shopId、distanceString key = SHOP_GEO_KEY + typeId;GeoResults<RedisGeoCommands.GeoLocation<String>> results = stringRedisTemplate.opsForGeo() // GEOSEARCH key BYLONLAT x y BYRADIUS 10 WITHDISTANCE.search(key,GeoReference.fromCoordinate(x, y),new Distance(5000),// RedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs() eRedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs().includeDistance().limit(end));// 4.解析出idif (results == null) {return Result.ok(Collections.emptyList());}List<GeoResult<RedisGeoCommands.GeoLocation<String>>> list = results.getContent();if (list.size() <= from) {// 没有下一页了,结束return Result.ok(Collections.emptyList());}// 4.1.截取 from ~ end的部分List<Long> ids = new ArrayList<>(list.size());Map<String, Distance> distanceMap = new HashMap<>(list.size());list.stream().skip(from).forEach(result -> {// 4.2.获取店铺idString shopIdStr = result.getContent().getName();ids.add(Long.valueOf(shopIdStr));// 4.3.获取距离Distance distance = result.getDistance();distanceMap.put(shopIdStr, distance);});// 5.根据id查询ShopString idStr = StrUtil.join(",", ids);List<Shop> shops = query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();for (Shop shop : shops) {shop.setDistance(distanceMap.get(shop.getId().toString()).getValue());}// 6.返回return Result.ok(shops);}
5 BitMap


11110000BITFIELD b1 GET u2 0# BITFIELD key GET u(无符号)2(获取几位) 0(从0开始)# 获取到 11 转换10进制就是3
5.1 Java

5.2 统计签到

从当前时间判断之前的时间里是否为0 为0表示断签
运算符 https://cloud.tencent.com/developer/article/1338265
Long userId = user.getId();LocalDate now = LocalDate.now();String key = CacheConst.getCurrentUserSign(now, userId);// 返回签到记录 为十进制数字List<Long> result = redisTemplate.opsForValue().bitField(key,BitFieldSubCommands.create().get(BitFieldSubCommands.BitFieldType.unsigned(now.getDayOfMonth())).valueAt(0));if (result == null || result.isEmpty()) {return Result.ok(0);}// 循环遍历Long num = result.get(0);int count = 0;if (num == null || num == 0) {return Result.ok(0);}// 与1做与运算 得到数字最后一个Bit位while (true) {if ((num & 1) == 0) {// 为0 直接结束break;}else {// 不为0 计数加一count++;}// 数字右移动num >>>= 1;}// 判断bit位是否为0 不为0 加1return Result.ok(count);
& 按位与运算 将两个数字的二进制位做对比 都为1 才是一
110111 55
111000 56
=
110000 48 55&56=48
\n
1100011 99
10100 20 [不足左边补0]
=
0000000 0 99&20=0
| 按位或 有一边为1就为1
1010 10
001 1
=
1011 11
5 101
9 1000
=
13 1101
6 HyperLogLog



