3、Redis Stack扩展功能

news2024/10/8 12:14:12

文章目录

  • 一、了解Redis产品
  • 二、申请RedisCloud实例
  • 三、Redis Stack体验
    • 1、RedisStack有哪些扩展?
    • 2、Redis JSON
      • 1、Redis JSON是什么
      • 2、Redis JSON有什么用
      • 3、Redis JSON的优势
    • 3、Search And Query
      • 1、传统Scan搜索
      • 2、Search And Query搜索
    • 4、Bloom Filter
      • 1、布隆过滤器是什么
      • 2、Guava的布隆过滤器示例
      • 3、Redis的BloomFilter使用示例
    • 5、Cuckoo Filter
      • 1、CuckooFilter是什么?
      • 2、CuckooFilter使用示例
  • 四、Redis Stack补充
    • 1、手动安装Redis扩展模块
    • 2、Java客户端调用扩展模块

一、了解Redis产品

目前,在Redis的官网上,可以看到Redis已经包含了多个产品。

在这里插入图片描述

其中,Redis Cloud是Redis的云服务,Redis Insight是Redis官方推出的图形化客户端。解决了Redis客户端群龙无首的囧境。

而Redis本身,也已经划分成了几个版本。Redis OSS就是我们之前用的Redis。 Redis Stack可以理解为是Redis加上一系列的扩展产品。Redis Enterprise是Redis的企业版。

这次我们就一起来体验一下Redis Stack的扩展功能。

二、申请RedisCloud实例

Redis Stack可以在我们之前安装的Redis服务上,自行下载安装新的扩展模块。在目前阶段,在RedisCloud上可以申请一个免费的RedisStack实例,快速体验Redis Stack的功能。

从Redis官网的右上角,就有Redis Cloud的登录链接。目前Redis Cloud提供了多种第三方登录的方式,可以选择合适的方式注册账号。
在这里插入图片描述

注册登录后,Redis Cloud就会分配一个免费的Redis实例。提供了Redis Stack功能支持。

在这里插入图片描述

接下来使用命令行,就可以连上这个Redis实例。

这个实例空间非常有限,而且无法长期使用。如果有更多需求,可以去了解一下付费版本。基础付费5美元/月

三、Redis Stack体验

1、RedisStack有哪些扩展?

目前Redis的官网上,单独构建了Redis的指令页面。在这个页面可以直接搜索相关的功能。

在这里插入图片描述

另外, 在redis-cli客户端也可以使用module list指令查看当前Redis服务中有哪些扩展。

Redis Stack的这些扩展功能,也可以手动添加到自己的Redis服务中。但是通常并不是必须的。我们可以使用Redis Cloud上的实例先完整体验一下,再考虑要不要使用这些扩展。

接下来找几个比较常见的扩展模块,体验一下。

2、Redis JSON

1、Redis JSON是什么

RedisJSON是Redis的一个扩展模块,它提供了对JSON数据的原生支持。通过RedisJSON,我们可以将JSON数据直接存储在Redis中,并利用丰富的命令集进行高效的查询和操作。RedisJSON不仅简化了数据处理的流程,还大幅提升了处理JSON数据的性能。

2、Redis JSON有什么用

Redis JSON的常用指令,在官网的Commands页面搜索JSON组就能看到

在Redis服务端,这些扩展指令并没有严格分组,而是都放在一个叫做module的组

redis-17998.c295.ap-southeast-1-1.ec2.redns.redis-cloud.com:17998> help JSON.SET

  JSON.SET (null)
  summary: (null)
  group: module

Redis JSON模块为Redis添加了JSON数据类型的支持,并且对JSON数据提供了快速进行增、删、改、查的操作。

-- 设置一个JSON数据
JSON.SET user $ '{"name":"loulan","age":18}'
## key是user,value就是一个JSON数据。其中$表示JSON数据的根节点。
-- 查询JSON数据
JSON.GET user
-- 查询JSON对象的name属性
JSON.GET user $.name
-- 查看数据类型
JSON.TYPE user    -- object
JSON.TYPE user $.name   --- string
JSON.TYPE user $.age    --- integer
--修改JSON数据 年龄加2
JSON.NUMINCRBY user $.age 2
-- 添加新的字段
JSON.SET user $.address '{"city": "Changsha", "country": "China"}' NX
## NX 表示只有当address字段不存在的时候才进行设置。
-- 在JSON数组中添加元素
JSON.SET user $.hobbies '["reading"]'
JSON.ARRAPPEND user $.hobbies '"swimming"'
-- 查看JSON对象中key的个数
JSON.OBJLEN user $.address


-- 查看user对象的所有key
JSON.OBJKEYS user

-- 删除JSON中的key
JSON.DEL user $.address

3、Redis JSON的优势

JSON是现代应用程序中经常用到的一种数据类型。很多时候,就算没有Redis JSON插件,我们也会采用JSON格式来缓存复杂的数据类型。比如在分布式场景下做用户登录功能,我们就可以将用户信息以JSON字符串的形式保存到Redis中,来代替单体应用中的Session,从而实现统一的登录状态管理。这些数据使用Redis JSON插件来管理,就显得顺理成章了。

并且Redis JSON插件相比用string管理这种JSON数据,还能带来一些很明显的优势。

  • Redis JSON存储数据的性能更高。Redis JSON底层其实是以一种高效的二进制的格式存储。相比简单的文本格式,二进制格式进行JOSN格式读写的性能更高,也更节省内存。根据官网的性能测试报告,使用Redis JSON读写JSON数据,性能已经能够媲美MongoDB以及ElasticSearch等传统NoSQL数据库。
  • Redis JSON使用树状结构来存储JSON。这种存储方式可以快速访问子元素。与传统的文本存储方案相比,树状存储结构能够更高效的执行查询操作。
  • 与Redis生态集成度高。作为Redis的扩展模块,Redis JSON和Redis的其他功能和工具无缝集成。这意味着开发者可以继续使用TTL、Redis事务、发布/订阅、Lua脚本等功能。

3、Search And Query

当Redis中存储的数据比较多时,搜索Redis中的数据是一件比较麻烦的事情。通常使用的 keys * 这样的指令,在生产环境一般都是直接禁用的,因为这样会产生严重的线程阻塞,影响其他的读写操作。

如何快速搜索Redis中的数据(主要是key)呢? Redis中原生提供了Scan指令,另外在Redis Stack中也增加了Search And Query模块。

1、传统Scan搜索

Scan指令的官方介绍:https://redis.io/docs/latest/commands/scan/

Scan指令的基础思想就是每次只返回想要查询的一部分结果数据,然后通过迭代的方式,逐步返回完整数据。

scan指令的基础使用方式:

SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]

这几个核心参数介绍如下:

  • cursor: 游标。代表每次迭代返回的偏移量。通常一次查询,cursor从0开始,然后scan指令会返回下一次迭代的起始偏移量。用户可以用这个返回值作为cursor,继续迭代下一批。直到cursor返回0,表示所有数据都过滤完成了。
  • pattern:匹配字符串。用来匹配要查询的key。 例如 user* 表示以user开头的字符串。
  • count:数字,表示每次迭代多少条数据。
  • type是key的类型,比如可以指定string ,set,zset等。

另外,针对不同key类型,还有一些不同的指令。 比如 SSCAN针对Set类型。HSCAN针对HASH类型。 ZSCAN针对ZSet类型。

简单示例如下:

-- 准备数据
eval 'for i = 1,30,1 do redis.call("SET","k"..tostring(i),"v"..tostring(i)) end' 0

--简单按照cursor过滤所有key。
scan 0
1) 18      ## 下一次迭代的cursor
....
scan 18
1) 21
....
scan 21
1) 0       ## 返回0表述所有数据过滤完成
....


-- 按照patern过滤 查询所有k开头的key
scan 0 MATCH k*
1) 18
...
scan 18 MATCH k*
1) 21
...
scan 21 MATCH k* 
1) 0

-- 设置迭代次数
scan 0 MATCH k* count 20
1) 21
...
scan 21 MATCH k* count 20
1) 0

2、Search And Query搜索

传统的SCAN搜索方式,只能简单的过滤Key。如果想要做一些复杂的搜索,就力不从心了。

比如在电商场景中,我们通常会用Redis来缓存商品信息,但是如果要做按品牌、型号、价格等等各种条件过滤商品的场景,Redis就不够用了。以往我们会选择将商品数据导入到MongoDB或者ElasticSearch这样的搜索引擎进行复杂过滤。

在这里插入图片描述

而Redis提供了RedisSearch插件,基本就可以认为是ElasticSearch这类搜索引擎的平替。大部分ES能够实现的搜索功能,在Redis里就能直接进行。这样就极大的减少了数据迁移带来的麻烦。

既然要做搜索,那就需要有能够支持搜索的数据结构。 Redis的哪些数据结构能够支持结构化查询呢?只有HASH和JSON。

--清空数据
flushall
-- 创建一个产品的索引
FT.CREATE productIndex ON JSON SCHEMA $.name AS name TEXT $.price AS price NUMERIC
## 索引为productIndex. 
## ON JSON 表示 这个索引会基于JSON数据构建,需要RedisJSON模块的支持。默认是ON HASH 表示检索所有HASH格式的数据
## SCHEMA表示根据哪些字段建立索引。  字段名 AS 索引字段名 数据类型  这样的组合。如果是JSON格式,字段名用$. 路径表示

-- 模拟一批产品信息
JSON.SET phone:1 $ '{"id":1,"name":"HUAWEI 1","description":"HUAWEI PHONE 1","price":1999}'
JSON.SET phone:2 $ '{"id":2,"name":"HUAWEI 2","description":"HUAWEI PHONE 2","price":2999}'
JSON.SET phone:3 $ '{"id":3,"name":"HUAWEI 3","description":"HUAWEI PHONE 3","price":3999}'
JSON.SET phone:4 $ '{"id":4,"name":"HUAWEI 4","description":"HUAWEI PHONE 4","price":4999}'
JSON.SET phone:5 $ '{"id":5,"name":"HUAWEI 5","description":"HUAWEI PHONE 5","price":5999}'
JSON.SET phone:6 $ '{"id":6,"name":"HUAWEI 6","description":"HUAWEI PHONE 6","price":6999}'
JSON.SET phone:7 $ '{"id":7,"name":"HUAWEI 7","description":"HUAWEI PHONE 7","price":7999}'
JSON.SET phone:8 $ '{"id":8,"name":"HUAWEI 8","description":"HUAWEI PHONE 8","price":8999}'
JSON.SET phone:9 $ '{"id":9,"name":"HUAWEI 9","description":"HUAWEI PHONE 9","price":9999}'
JSON.SET phone:10 $ '{"id":10,"name":"HUAWEI 10","description":"HUAWEI PHONE 10","price":19999}'

## 如果是ON HASH ,可以直接通过索引添加数据
## FT.ADD productIndex 'product:1'  1.0 FIELDS "id" 1 "name" "HUAWEI1" "description" "HUAWEI PHONE 1" "PRICE" 3999
## 数据的key 是producr:1 
## FIELDS 数据。 按照 key value 的格式组织 

-- 查看索引状态
FT.INFO productIndex

-- 搜索产品 
## 搜索条件: name包含 HUAWEI, price在1000到5000之间。返回id和name
FT.SEARCH productIndex "@name:HUAWEI @price:[1000 5000]" RETURN 2 id name
## 查询条件构建,参见官网 https://redis.io/docs/latest/develop/interact/search-and-query/query/

4、Bloom Filter

1、布隆过滤器是什么

一句话解释:一种快速检索一个元素是否在一个海量集合中的算法。

比如现在有一个签到活动,要求每个用户只能签到一次,重复签到无效。这种常见的需求怎么做?如果不考虑数量级,那么非常简单。把所有签到的用户ID存到一个集合里。签到前到集合里检查一下用户ID有没有就可以了。

但是,如果你要面对的是淘宝的海量用户信息呢?这个集合得要多大?在一个海量集合里检索一个数据,是不是很慢?这就需要一个更节省空间同时更高效的算法,能够在海量数据集合中快速判断一个元素存不存在。这就可以用布隆过滤器。

布隆过滤器的使用场景非常多,最典型的应用是作为缓存数据的前端过滤缓存。快速比如,在淘宝这种海量用户的登录场景,也可以用布隆过滤器,快速判断用户输入的用户名是不是存在。如果用户名不存在,那么就可以直接拒绝,不再需要去数据库里查了。这样就可以防止大部分无效数据查询,屏蔽很多恶意的请求。

布隆过滤器使用一个很长的二进制位数组和一系列哈希函数来保存元素。优点是非常节省空间,并且查询时间也非常快。缺点是有一定的误失败概率以及无法删除元素 ,也无法给元素计数。

  • 位数组(Bit Array):布隆过滤器使用一个长度固定的位数组来存储数据。每个位置只占用一个比特(0或1),初始时所有位都设置为0。位数组的长度和哈希函数的数量决定了过滤器的误报率和容量。
  • 哈希函数集合:布隆过滤器使用多个哈希函数,每个函数都会将输入数据映射到位数组的一个不同位置。哈希函数的选择对过滤器的性能有很大影响,理想的哈希函数应该具有良好的散列性,使得不同的输入尽可能均匀地映射到位数组的不同位置。

在这里插入图片描述

布隆过滤器判断一个元素不在集合中,那么这个元素肯定不在集合中。但是,布隆过滤器判断一个元素在集合中,那么这个元素有可能不在集合中。

2、Guava的布隆过滤器示例

布隆过滤器中,将一个原本不在集合中的元素判断成为在集合中,这就是误判。而误判率是布隆过滤器一个很重要的控制指标。

在算法实现时,误判率是可以通过设定更复杂的哈希函数组合以及做更大的位数组来进行控制的。所以,在布隆过滤器的初始化过程中,通常只需要指定过滤器的容量和误判率,就足够了。

pom.xml引入Guava

<dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>33.1.0-jre</version>
    </dependency>

使用Guava提供的布隆过滤器实现

public static void main(String[] args) {
        BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.stringFunnel(StandardCharsets.UTF_8),10000,0.01);

        //把 A~Z 放入布隆过滤器
        for (int i = 64; i <= 90 ; i++) {
            bloomFilter.put(String.valueOf((char) i));
        }
        System.out.println(bloomFilter.mightContain("A")); //true
        System.out.println(bloomFilter.mightContain("a")); //false
    }

3、Redis的BloomFilter使用示例

布隆过滤器是用的二进制数组来保存数据,所以,Redis的BitMap数据结构天生就非常适合做一个分布式的布隆过滤器底层存储。只是算法还是需要自己实现。有很多企业实际上也是这么做的。

现在Redis提供了BloomFilter模块后,BloomFilter的使用门槛就更低了。

-- 创建一个key为bf的布隆过滤器,容错率0.01,容量1000。NONSCALING 表示不扩容。如果这个过滤器里的数据满了,就直接报错
BF.RESERVE bf 0.01 1000 NONSCALING
-- 添加元素
BF.ADD bf A
.....
-- 批量添加元素
BF.MADD bf B C D E F G H I

-- 如果bf不存在,就创建一个key为bf的过滤器。
BF.INSERT bf CAPACITY 1000 ERROR 0.01 ITEMS hello
-- 查看容量
BF.CARD bf
-- 判断元素是否在过滤器中
## 返回值0表示不在,1表示在
BF.EXISTS bf a
-- 批量判断
BF.MEXISTS bf A a B b
-- 查看布隆过滤器状态
BF.INFO bf
# 依次迭代布隆过滤器中的位数组
BF.SCANDUMP bf 0
## 和SCAN指令使用很像,返回当前访问到的数据和下一次迭代的起点。 当下次迭代起点为0表示数据已经全部迭代完成。
## 主要是可以配合BF.LOADCHUNK 进行备份。

5、Cuckoo Filter

1、CuckooFilter是什么?

布隆过滤器最大的问题是无法删除数据。因此,后续诞生了很多布隆过滤器的改进版本。Cuckoo Filter 布谷鸟过滤器就是其中一种。

相比于布隆过滤器,Cuckoo Filter可以删除数据。而且基于相同的集合和误报率,Cuckoo Filter通常占用空间更少。相对的,算法实现也就更复杂。

不过他同样有误判率。即有可能将一个不在集合中的元素错误的判断成在集合中。布隆过滤器的误报率通过调整位数组的大小和哈希函数来控制,而CuckooFilter的误报率受指纹大小和桶大小控制。

BUSKETSIZE,表示每个桶Busket中存放的元素个数。Cuckoo Filter的数组里存的不是位,而是桶busket,每个桶里可以存放多个数据。同一个桶中存放的数据越多,空间利用率更高,相应的误判率也就越高,性能也更慢。Redis的CuckooFilter实现中,BUSKETSIZE应该是一个在1到255之间的整数,默认的BUSKETSIZE是2。

桶Busket中并不实际保存数据本身,而是保存数据的指纹(可以认为是压缩后的数据,实际上是数据对象的几个低位数据)。指纹越小,HASH冲突造成误判的几率就越小。这个参数的调整比较复杂,Redis的CuckooFilter中不支持调整这个参数。

2、CuckooFilter使用示例

-- 创建默认值
## 容量1000,这个是必填参数。后面几个都是可选参数。这里填的几个就是Redis中的CuckooFilter的默认值
## BUSKETSIZE越大,空间利用率更高,但是误判率也更高,性能更差
## MAXITARATIONS越小,性能越好。如果设置越大,空间利用率就越好。
## EXPANSION 是指空间扩容的比例。
CF.RESERVE cf 1000 BUSKETSIZE 2 MAXITERATIONS 20 EXPANSION 1

其他使用,和布隆过滤器差不多。就是多了个CF.DEL删除元素的指令。

四、Redis Stack补充

1、手动安装Redis扩展模块

Redis Stack的这些扩展模块除了在Redis Cloud上直接使用外,也可以手动集成到自己的Redis服务当中。

登录Redis Cloud,进入下载中心,可以手动下载对应的扩展模块。下载时注意选择对应的Redis版本以及操作系统。

在这里插入图片描述

这是一个最简单的下载途径。另外更建议的方式,是去下载这些扩展模块的源码,然后编译,安装。

下载后获取以.so为后缀的扩展文件。上传到服务器后,在Redis的配置文件中加载这个扩展模块

# Load modules at startup. If the server is not able to load modules
# it will abort. It is possible to use multiple loadmodule directives.
#
loadmodule /root/myredis/redisbloom.so

然后重启Redis服务,就可以使用客户端,登录Redis后查看扩展模块的加载情况。

127.0.0.1:6379> MODULE LIST

1.
    1.  "name"
    2.  "bf"
    3.  "ver"
    4.  (integer) 20612
    5.  "path"
    6.  "/root/myredis/redisbloom.so"
    7.  "args"
    8.  (empty array)

注意:如果模块加载错误,那么Redis服务启动会失败的。这时要去查看日志逐步排查问题。

例如,如果redisbloom.so文件在Linux服务器上,没有添加可执行的x 权限,那么Redis就会启动失败

27425:M 18 Jun 2024 14:07:29.670 # Module /root/myredis/redisbloom.so failed to load: It does not have execute permissions.
27425:M 18 Jun 2024 14:07:29.670 # Can't load module from /root/myredis/redisbloom.so: server aborting

2、Java客户端调用扩展模块

这些扩展模块目前阶段都还是比较新的功能,需要手动进行扩展。所以目前Java的一些客户端工具都还没有集成这些功能。大部分情况下,只能通过lua脚本手动调用这些扩展功能。但是由于在客户端无法确定服务端是否安装了对应的扩展模块,所以,在写lua脚本调用时,一定要注意处理好各种各样的异常情况。

例如,以布隆过滤器为例

@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisStackTest {

    @Resource
    RedisTemplate<String,Object> redisTemplate;

    List<String> keys = List.of("a-bf");
    @Test
    public void createBloomFilter(){
        if(!redisTemplate.hasKey("a-bf")){
            try{
                String createFilterScriptText= """
                     return redis.call('BF.RESERVE', KEYS[1], '0.01','1000','NONSCALING')
                """;
                DefaultRedisScript<String> redisScript = new DefaultRedisScript<>(createFilterScriptText, String.class);
                String execute = redisTemplate.execute(redisScript,keys);
                System.out.println("CREATE BF:"+execute);
            }catch (Exception e){
 //               e.printStackTrace();
                System.out.println("COMMAND NOT SUPPORT");
            }
        }else{
            System.out.println("BF KEY is already exists");
        }
    }

    @Test
    public void addData(){
        if(!redisTemplate.hasKey("a-bf")){
            System.out.println("BF KEY is not exists");
        }else{
            try{
                String[] args = new String[]{"A","B","C","D","E","F","G"};
                String addDataScriptText= """
                for i,arg in ipairs(ARGV) do
                    local addRes = redis.call('BF.ADD',KEYS[1],arg)
                end
                return 'OK'
                """;
                DefaultRedisScript<String> redisScript = new DefaultRedisScript<>(addDataScriptText, String.class);
                System.out.println("ADDDATA BF:"+redisTemplate.execute(redisScript,  keys, args));
            }catch (Exception e){
//                e.printStackTrace();
                System.out.println("COMMAND NOT SUPPORTED");
            }
        }
    }

    @Test
    public void checkData(){
        if(!redisTemplate.hasKey("a-bf")){
            System.out.println("BF KEY is not exists");
        }else{
            String[] args = new String[]{"A","B","C","D","E","F","G"};
            String checkDataScriptText= """
                    local checkRes = redis.call('BF.EXISTS',KEYS[1],ARGV[1])
                    return checkRes
                    """;
            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(checkDataScriptText, Long.class);
            try{
                Long res = redisTemplate.execute(redisScript, keys, args);
                if(1L == res){
                    System.out.println("KEY EXISTS");
                } else if (0L==res) {
                    System.out.println("KEY NOT EXISTS");
                }else{
                    System.out.println("ERROR");
                }
            }catch (Exception e){
//                e.printStackTrace();
                System.out.println("COMMAND NOT SUPPORTED");
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2196325.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python_PySide6学习笔记(三十八)】基于QPushButton实现自定义的圆形按键指示灯类tQCircularButton

基于QPushButton实现自定义的圆形按键指示灯类tQCircularButton 基于QPushButton实现自定义的圆形按键指示灯类tQCircularButton前言正文1、Qt样式表1.1 Qt样式表1.2 样式属性 2、设置Qt样式表3、tQCircularButton类4、使用示例 基于QPushButton实现自定义的圆形按键指示灯类tQ…

系统规划与管理——1信息系统综合知识(3)

文章目录 1.3 信息系统1.3.1 信息系统定义1.3.2 信息系统的生命周期1.3.3 信息系统常用的开发方法 1.3 信息系统 1.3.1 信息系统定义 信息系统是一种以处理信息为目的的专门的系统类型。信息系统可以是手工的&#xff0c;也可以是计算机化的。计算机化的信息系统的组成部件包…

【JVM调优】JVM高频参数和最优实践

JVM高频参数 一、常用参数配置1. 堆内存设置方式1&#xff08;Java8及之前&#xff09;方式2&#xff08;Java9及之后&#xff09; 2. 新生代和老年代设置3. 垃圾收集器选择4. 调试和日志5. Metaspace设置6. 其他重要参数 二、参数设置最佳实践三、GC日志参数设置日志解析Minor…

构建宠物咖啡馆:SpringBoot框架的实现策略

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理基于Spring Boot的宠物咖啡馆平台的设计与…

Vue入门-使用Vue2完成简单的记事本Demo

需求&#xff1a; ①能够实现记录重复数据 ②全部清空 ③单条记录清空 页面效果&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content&quo…

2024年开放式蓝牙耳机品牌排行榜前十名,五个超实用开放式耳机品牌分享

​开放式耳机目前非常流行&#xff0c;它们以时尚、美观和舒适著称&#xff0c;迅速赢得了众多用户的喜爱&#xff0c;成为了耳机市场的新宠。与传统的入耳式耳机相比&#xff0c;开放式耳机佩戴更稳固&#xff0c;对耳朵也更为温和。尽管有些人认为它们价格不菲&#xff0c;甚…

【生命之光再启航】开颅术后苏醒之谜:揭秘康复之旅的时间窗

在医学的浩瀚星空中&#xff0c;开颅手术无疑是一颗璀璨而又充满挑战的星辰。它以其高风险、高技术含量&#xff0c;成为治疗颅脑疾病不可或缺的重要手段。然而&#xff0c;对于患者及家属而言&#xff0c;手术虽已完成&#xff0c;但“做完开颅手术多久能醒&#xff1f;”这一…

Ollama本地部署自定义大模型

Ollama本地部署自定义大模型 1. Ollama安装2. 模型选择3. Ollama使用3.1 创建模型3.2 运行模型-命令行3.3 运行模型-接口 4. 其他有用命令参考链接 Ollama是一个专为本地机器设计的开源框架&#xff0c;旨在简化大型语言模型&#xff08;LLM&#xff09;的部署和运行过程。它提…

AWS EC2 部署Echarts大屏展示项目

前言 Echarts简介 ECharts是一个由JavaScript开发的开源可视化库。它能使数据生动、直观、互动、高度个性化数据可视化图表。ECharts适用大部分浏览器&#xff0c;如IE6 、Chrome、Firefox、Safari等&#xff0c;同时支持PC和移动设备。 开源&#xff1a;ECharts是一个开源项目…

大模型RAG:文档分块方案与RAG全流程

一 RAG与文本分块 1.1 为什么要文档分块 我们知道&#xff0c;大模型在预训练阶段获取的知识是有限的&#xff0c;一般需要数据增强模块引入外部知识库&#xff0c;通过知识检索的方式搜索于用户提问相关的知识&#xff0c;这也是RAG相关应用架构出现的原因。但这又引申出另一…

一个简单的将产品图册转换为翻页电子产品图册的方法

​在数字化浪潮席卷全球的今天&#xff0c;企业纷纷寻求转型&#xff0c;纸质产品图册逐渐被翻页电子图册所替代。电子图册不仅具有环保、便捷、易于更新等优势&#xff0c;还能为企业节省大量印刷和物流成本。那么&#xff0c;如何将现有的实体产品图册转化为翻页电子图册呢 1…

YOLO11改进|注意力机制篇|引入反向残差移动快iRMB

目录 一、【iRMB】注意力机制1.1【iRMB】注意力介绍1.2【iRMB】核心代码 二、添加【iRMB】注意力机制2.1STEP12.2STEP22.3STEP32.4STEP4 三、yaml文件与运行3.1yaml文件3.2运行成功截图 一、【iRMB】注意力机制 1.1【iRMB】注意力介绍 反向残差移动快iRMB结构如下所示&#xf…

「Ubuntu」根目录存储空间不足

Linux系统不同于 Windows系统&#xff0c;复杂的文件系统常常让人头疼&#xff0c;特别是动不动就存储空间不足&#xff0c;简单的清空回收站根本不管用&#xff0c;在此推荐一个绝对好用的方法&#xff0c;并且还可以多学习一条 Linux命令 1、du 使用方法 通过使用命令 du&am…

LabVIEW激光诱导击穿光谱识别与分析系统

LabVIEW激光诱导击穿光谱&#xff08;LIBS&#xff09;分析系统利用高能量脉冲激光产生高温等离子体&#xff0c;通过分析等离子体发出的光谱来定性分析样品中的元素种类。该系统的开发集成了软件与硬件的设计&#xff0c;实现了自动识别和定性分析功能&#xff0c;适用于环境监…

华为OD机试 - 优雅子数组 - 暴力枚举(Python/JS/C/C++ 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

哦豁!有了这份学习路径,AI小白也能学懂大模型!!

小白如何规划大模型学习路径&#xff1f;&#xff1f; 元仔有求必应&#xff0c;为各位同学整理出一份完整的大模型学习路径规划&#xff01; 初识大模型&#xff1a;概念与趋势 首先&#xff0c;AI小白应从基础出发&#xff0c;理解什么是大模型。 大模型&#xff0c;顾名…

LeetCode讲解篇之98. 验证二叉搜索树

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们可以通过递归搜索的方式查询某棵树是不是二叉搜索树&#xff0c;二叉搜索树需要满足的最小值与最大值的约束并且左子树和右子树都是二叉搜索树或者当前节点为空&#xff0c;以当前节点为根节点的树才是二叉搜…

WPF中的布局

布局原则 1、不显式设置元素大小。 2、不使用绝对定位。 元素应该根据容器的内容来进行排列。绝对定位在开发前期会带来一些便捷&#xff0c;但扩展性比较差。一旦显示器尺寸或分辨率发生改变&#xff0c;界面的显示效果可能会达不到预期的效果。 3、布局容器可以嵌套使用 常…

Django 5 用后台admin 做一个简单 DIY 电脑组装报价系统

1. 注意点 合计价格 admin.register(ComputerConfiguration) class ComputerConfigurationAdmin(admin.ModelAdmin):inlines [ConfigurationComponentInline]list_display (config_id, user_id, config_name, total_price, total_jh_price, total_selling_price)list_display…