Redis实战(黑马点评)——redis存储地理信息、位图、HyperLogLog 用法
Redis存储geo数据类型基本介绍
geo 就是 geolocation 的简写形式,代表地理坐标。redis 在 3.2 版本中加入了对 geo 的支持,允许存储地理坐标信息,帮助我们根据经纬度来检索数据。常见的命令有:
geoadd:添加一个地理空间信息,包含:经度(longitude)、纬度(latitude)、值(member)
geoadd g1 116.378248 39.865275 bjn 116.428003 39.903738 bjz 116.322287 39.893729 bjx
# 添加城市
GEOADD g1 116.3883 39.9289 "Beijing"
GEOADD g1 121.4737 31.2304 "Shanghai"
GEOADD g1 114.0667 22.5485 "Guangzhou"
geoadd <GEOkey> <经度(longitude)> <纬度(latitude)> <GEOname>
添加的数据如下
geopos:获取一个或多个成员的地理位置(经度和纬度)
GEOPOS key member
GEOPOS g1 bjx
geodist:计算指定的两个点之间的距离并返回
GEODIST key member1 member2 [unit]geodist g1 bjn bjx km
georadius:指定圆心、半径,找到该圆内包含的所有 member,并按照与圆心之间的距离排序返回。
GEORADIUS key longitude latitude radius [unit] [WITHDIST] [WITHCOORD] [WITHHASH] [COUNT count]GEORADIUS g1 116.397904 39.909005 10 km withdist
geohash:将指定的 member 的坐标转换为 hash 字符串并返回
GEOADD key longitude latitude membergeohash g1 bjz
Java操作redis对geo数据类型的操作
添加一个地理坐标
String redisKey = "geo1";
redisTemplate.opsForGeo().add(redisKey,new Point(113.883078,22.553291),"shenzhen");
删除一个键对应的地理成员
redisTemplate.opsForGeo().remove(String key, String member);
redisTemplate.opsForGeo().remove(redisKey, "shenzhen");
查询member坐标
List<Point> list = redisTemplate.opsForGeo().position(redisKey, "shenzhen","guangzhou");
查询以某点画圆所圈定的member
Point center = new Point(113.8830,22.553); // 中点Circle circle = new Circle(center, 100000); // 单位为米GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius(redisKey, circle); // 查询的中点和半径List<String> locations = results.getContent().stream().map(result -> result.getContent().getName()).collect(Collectors.toList()); // 获取成员的字段System.out.println(locations); // 默认是按照由近到远排序
计算两点距离
double value = redisTemplate.opsForGeo().distance(redisKey, "广州", "深圳", KILOMETERS).getValue();
获取以某点画圆所圈定的member以及对应的距离
// 创建一个Point对象,表示圆心的经纬度
Point center = new Point(116.373, 39.157);// 创建一个Circle对象,表示以center为圆心,半径为120公里的圆
// 注意:这里半径的单位是公里,而不是米
Circle circle = new Circle(center, new Distance(120, Metrics.KILOMETERS));// 使用RedisTemplate的opsForGeo().radius()方法查询圆内的member和距离
// redisKey是Redis中存储地理信息的key
// circle是查询的圆
// RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance()表示返回结果中包含距离
GeoResults<RedisGeoCommands.GeoLocation<Object>> results = redisTemplate.opsForGeo().radius(redisKey, circle, RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance());// 创建一个HashMap,用于存储member和到圆心的距离
Map<String, Double> distanceMap = new HashMap<>();// 遍历查询结果
for (GeoResult<RedisGeoCommands.GeoLocation<Object>> geoResult : results.getContent()) {// 获取member的idString member = geoResult.getContent().getName().toString(); // member// 获取member到圆心的距离double distanceToCenter = geoResult.getDistance().getValue(); // 到圆心的距离// 将member和距离存储到distanceMap中distanceMap.put(member, distanceToCenter);
}// 打印结果
System.out.println(distanceMap);
黑马点评中按照距离远近的顺序查询店铺具体代码实现
@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;Point center = new Point(x, y); // 中点Circle circle = new Circle(center, 5000); // 单位为米GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo().radius(key, circle, RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs().includeDistance().sortAscending()); // 查询的中点和半径,并按距离升序排序// 4.解析出idif (results == null || results.getContent().isEmpty()) {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).limit(end - 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查询ShopList<String> idStrList = ids.stream().map(String::valueOf).collect(Collectors.toList());String idStr = StrUtil.join(",", idStrList);List<Shop> shops = query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();for (Shop shop : shops) {Distance distance = distanceMap.get(shop.getId().toString());if (distance != null) {shop.setDistance(distance.getValue());}}// 6.返回return Result.ok(shops);}
BitMap位图
把每一个 bit 位对应当月的每一天,形成了映射关系。用 0 和 1 标示业务状态,这种思想就称为位图(BitMap)。比如签到。
Redis 中是利用 string 类型数据结构实现 BitMap,因此最大上限是 512M,转换为 bit 则是 2^32 个 bit 位。
bitmap的操作命令有:
- setbit: 向指定位置(offset)存入一个0或1
- getbit: 获取指定位置(offset)的bit值
- bitcount: 统计bitmap中值为1的bit位的数量
- bitfield: 操作(查询、修改、自增)bitmap中bit数组中的指定位置(offset)的值
- bitfield_ro: 获取bitmap中bit数组,并以十进制形式返回
- bitop: 将多个bitmap的结果做位运算(与、或、异或)
- bitpos: 查询bit数组中指定范围内第一个0或1出现的位置
实现签到功能
实现签到
@Overridepublic Result sign() {// 获取当前用户idLong Id = BaseContext.getCurrent().getId();// 获取当前时间LocalDate currentDate = LocalDate.now();// 将当前时间String化// 将当前时间转为对应天数String formattedDate = currentDate.format(DateTimeFormatter.ofPattern(":yyyy:MM"));// 获取当日是这个月的第几天int dayOfMonth = currentDate.getDayOfMonth();// redis签到redisTemplate.opsForValue().setBit("user" + Id + formattedDate, dayOfMonth , true);return Result.ok();}
统计这个月的签到天数
@Overridepublic Result GetSignDays() {Long Id = BaseContext.getCurrent().getId();// 获取当前时间LocalDate currentDate = LocalDate.now();// 将当前时间String化// 将当前时间转为对应天数String formattedDate = currentDate.format(DateTimeFormatter.ofPattern(":yyyy:MM"));// 获取当日是这个月的第几天String key = "user" + Id + formattedDate;Long execute = (Long)redisTemplate.execute((RedisCallback<Long>) connection ->connection.bitCount(key.getBytes()) // 使用字符串序列化转为字节数组);return Result.ok(execute);}
HyperLogLog 用法
首先我们理解两个概念:
- UV (Unique Visitor):全称 Unique Visitor,也叫独立访客量,是指通过互联网访问该网站的自然人。1天内同一个用户多次访问该网站,只记录1次。
- PV (Page View):全称 Page View,也叫页面访问量或点击量。用户每访问网站的一个页面,记录1次 PV;用户多次打开同页面,则记录多次 PV。
UV 统计在服务端做会比较麻烦,因为需要判断该用户是否已经统计过了,需求将统计过的用户信息保存。
// TODO
相关文章:
Redis实战(黑马点评)——redis存储地理信息、位图、HyperLogLog 用法
Redis存储geo数据类型基本介绍 geo 就是 geolocation 的简写形式,代表地理坐标。redis 在 3.2 版本中加入了对 geo 的支持,允许存储地理坐标信息,帮助我们根据经纬度来检索数据。常见的命令有: geoadd:添加一个地理空…...
判断1到100之间有多少个素数,并输出所有的素数。
def is_prime(num): #判断一个数是否素数if num<1:return False #因为1和负数都不是素数for i in range(2,int(num**0.5)1): #从2开始到根号num的整数结束,因为一个数num不是素数,那么把必定有一个小于或等于根号num的因素if num%i0:return False #如…...
JAVA:利用 Content Negotiation 实现多样式响应格式的技术指南
1、简述 Content Negotiation(内容协商) 是 RESTful 服务的重要特性,允许客户端和服务器根据请求的不同特性动态选择适合的响应格式。它是一种在 HTTP 协议中实现的机制,通过它,服务器能够根据客户端需求返回适合的内…...
layui Table单元格编辑支持Enter键换行,包括下拉框单元格
layui Table表格编辑支持Enter键换行 可编辑单元格 $(".layui-table td").keydown(function (e) {// console.log("111",e);var index $(this).index(),tr $(this).parent(tr),isKeydown (event.type "keydown");if (e.code "Enter&q…...
Swoole的MySQL连接池实现
在Swoole中实现MySQL连接池可以提高数据库连接的复用率,减少频繁创建和销毁连接所带来的开销。以下是一个简单的Swoole MySQL连接池的实现示例: 首先,确保你已经安装了Swoole扩展和PDO_MySQL扩展(或mysqli,但在这个示…...
无人机红外热成像:应急消防的“透视眼”
无人机红外热成像:应急消防的“透视眼” 亲爱的小伙伴们,每年一到夏天,应急消防的战士们就像上紧了发条的闹钟,时刻准备应对各种灾害。炎热天气让火灾隐患“蹭蹭”往上涨,南北各地还有防洪救灾、台风、泥石流等灾害轮…...
【redis】Redis操作String类型key的发生了什么?
关于Redis操作(添加、删除、修改、查询)String类型key的完整过程,包括引用源码数据、时序图、磁盘IO读写、数据长度限制和故障处理机制。 数据结构 Redis对象(robj) typedef struct redisObject {unsigned type:4; …...
hdfs之读写流程
写入流程: 客户端Client想将文件a.txt上传至hdfs,首先向Namenode发送请求进行权限校验,Namenode通过后会计算出来三个节点,并将这三个节点告知客户端,客户端将输入进行切割成块,一个一个的块进行传输&…...
研发的立足之本到底是啥?
0 你的问题,我知道! 本文深入T型图“竖线”的立足之本:专业技术 技术赋能业务能力。研发在学习投入精力最多,也误区最多。 某粉丝感发展遇到瓶颈,项目都会做,但觉无提升,想跳槽。于是&#x…...
Baklib揭示内容中台与人工智能技术的创新协同效应
内容概要 在当今信息爆炸的时代,内容的高效生产与分发已成为各行业竞争的关键。内容中台与人工智能技术的结合,为企业提供了一种新颖的解决方案,使得内容创造的流程更加智能化和高效化。 内容中台作为信息流动的核心,能够集中管…...
智慧消防营区一体化安全管控 2024 年度深度剖析与展望
在 2024 年,智慧消防营区一体化安全管控领域取得了令人瞩目的进展,成为保障营区安全稳定运行的关键力量。这一年,行业在政策驱动、技术创新应用、实践成果及合作交流等方面呈现出多元且深刻的发展态势,同时也面临着一系列亟待解决…...
自定义数据集,使用 PyTorch 框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测
在本文中,我们将展示如何使用 NumPy 创建自定义数据集,利用 PyTorch 实现一个简单的逻辑回归模型,并在训练完成后保存该模型,最后加载模型并用它进行预测。 1. 创建自定义数据集 首先,我们使用 NumPy 创建一个简单的…...
UE5 特效
能帮到你的话,就给个赞吧 😘 文章目录 post processexposurebloomvignettesaturationunbound material材质蓝图alt z base colorconstant3Vector roughnessconstant metallicconstant pbrroughnessmetallicmake more realmake some areas rougher than o…...
CMAKE工程编译好后自动把可执行文件传输到远程开发板
# 设置 CMake 最低版本要求 cmake_minimum_required(VERSION 3.10)# 设置项目名称 project(MyProject)# 添加可执行文件,这里以项目名作为可执行文件的名称 add_executable(${PROJECT_NAME} main.cpp)# 设置开发板信息 set(DEVELOPMENT_BOARD_IP "192.168.1.10…...
Windows 程序设计7:文件的创建、打开与关闭
文章目录 前言一、文件的创建与打开CreateFile1. 创建新的空白文件2. 打开已存在文件3. 打开一个文件时,如果文件存在则打开,如果文件不存在则新创建文件4.打开一个文件,如果文件存在则打开文件并清空内容,文件不存在则 新创建文件…...
策略模式 - 策略模式的使用
引言 在软件开发中,设计模式是解决常见问题的经典解决方案。策略模式(Strategy Pattern)是行为型设计模式之一,它允许在运行时选择算法的行为。通过将算法封装在独立的类中,策略模式使得算法可以独立于使用它的客户端…...
具身智能研究报告
参考: (1)GTC大会&Figure:“具身智能”奇点已至 (2)2024中国具身智能创投报告 (3)2024年具身智能产业发展研究报告 (4)具身智能行业深度:发展…...
Windows安装Milvus
安装Milvus 安装Docker前置条件: 安装Mlivus方案一方案二 Attu管理端 安装Docker 系统:Windows 11 家庭中文版 Mlivus:V2.3.0 Attu: V2.3.10 前置条件: 启用“适用于 Linux 的 Windows 子系统”可选功能,才能在 Win…...
Excel分区间统计分析(等步长、不等步长、多维度)
在数据分析过程中,可能会需要统计不同数据区间的人数、某个数据区间的平均值或者进行分组区间统计,本文从excel函数到数据透视表的方法,从简单需求到复杂需求,采用不同的方法进行讲解,尤其是通过数据透视表的强大功能大…...
宝塔mysql数据库容量限制_宝塔数据库mysql-bin.000001占用磁盘空间过大
磁盘空间占用过多,排查后发现网站/www/wwwroot只占用7G,/www/server占用却高达8G,再深入排查发现/www/server/data目录下的mysql-bin.000001和mysql-bin.000002两个日志文件占去了1.5G空间。 百度后学到以下知识,做个记录。 mysql…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
