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

【Redis】深入探索 Redis 的数据类型 —— 哈希表 hash

文章目录

  • 前言
  • 一、hash 类型相关命令
    • 1.1 HSET 和 HSETNX
    • 1.2 HGET 和 HMGET
    • 1.3 HKEYS、HVALS 和 HGETALL
    • 1.4 HEXISTS 和 HDEL
    • 1.5 HLEN
    • 1.6 HINCRBY 和 HINCRBYFLOAT
    • 1.7 哈希相关命令总结
  • 二、hash 类型内部编码
  • 三、hash 类型的应用场景
  • 四、原生,序列化,哈希类型缓存方式对比
    • 4.1 原生字符串类型
    • 4.2 序列化字符串类型(例如JSON格式)
    • 4.3 哈希类型
    • 4.4 总结


前言

在构建和优化应用程序时,数据缓存是提高性能和降低数据库负载的关键策略之一。Redis(Remote Dictionary Server)是一个高性能的内存数据库,广泛用于数据缓存和快速数据访问。其中,哈希类型(Hash)是 Redis 中的一种强大数据结构,通常用于存储对象、映射关系和键值对等数据。

在本文中,我们将深入探讨Redis中的哈希类型。我们将从哈希类型的基本命令入手,逐步介绍它们的使用方法、内部编码方式以及在实际应用场景中的应用。通过学习和理解 Redis 哈希类型,可以帮助我们够更好地利用 Redis 来优化数据存储和访问,提高应用程序的性能。

接下来,让我们深入了解 Redis 哈希类型的相关内容。

一、hash 类型相关命令

1.1 HSET 和 HSETNX

  1. HSET
  • 作用 : 指定的哈希表中设置字段的值,如果字段存在则更新,否则创建。并且可以同时设置多组字段。

  • 语法:

    HSET key field value [field value ... ]
    
  1. HSETNX
  • 作用:仅在字段不存在时,在指定的哈希表中设置字段的值。设置成功返回 1,否则返回 0。
  • 语法:
    HSETNX key field value 
    
  1. 使用示例

1.2 HGET 和 HMGET

  1. HGET
  • 作用:获取指定哈希表中字段的值。
  • 语法:
    HGET key field
    
  1. HMGET
  • 作用:是获取指定哈希表中多个字段的值。
  • 语法:
    HMGET key field1 [field2 ...]
    
  1. 使用示例

当然,我会继续完善下面的部分,以涵盖哈希类型相关命令的详细说明:

1.3 HKEYS、HVALS 和 HGETALL

  1. HKEYS
  • 作用:获取指定哈希表中所有字段的名称。
  • 语法
    HKEYS key
    
  1. HVALS
  • 作用:获取指定哈希表中所有字段的值。
  • 语法
    HVALS key
    
  1. HGETALL
  • 作用:获取指定哈希表中所有字段和对应的值。
  • 语法
    HGETALL key
    
  1. 使用案例

1.4 HEXISTS 和 HDEL

  1. HEXISTS
  • 作用:检查指定哈希表中是否存在某个字段。
  • 语法
    HEXISTS key field
    
  1. HDEL
  • 作用:删除指定哈希表中的一个或多个字段。
  • 语法
    HDEL key field1 [field2 ...]
    
  1. 使用案例

1.5 HLEN

  1. HLEN
  • 作用:获取指定哈希表中字段的数量(即哈希表的大小)。
  • 语法
    HLEN key
    
  1. 使用案例

1.6 HINCRBY 和 HINCRBYFLOAT

  1. HINCRBY
  • 作用:将哈希表中指定字段的值增加一个整数。
  • 语法
    HINCRBY key field increment
    
  1. HINCRBYFLOAT
  • 作用:将哈希表中指定字段的值增加一个浮点数。
  • 语法
    HINCRBYFLOAT key field increment
    
  1. 使用案例

1.7 哈希相关命令总结

以下是哈希类型相关命令的总结,包括命令、作用和时间复杂度:

命令作用时间复杂度
HSET在哈希表中设置字段的值,存在则更新,否则创建。可同时设置多组字段。O(1)
HSETNX仅在字段不存在时,在哈希表中设置字段的值,成功返回1,否则返回0。O(1)
HGET获取指定哈希表中字段的值。O(1)
HMGET获取指定哈希表中多个字段的值。O(N),N为字段数
HKEYS获取指定哈希表中所有字段的名称。O(N),N为字段数
HVALS获取指定哈希表中所有字段的值。O(N),N为字段数
HGETALL获取指定哈希表中所有字段和对应的值。O(N),N为字段数
HEXISTS检查指定哈希表中是否存在某个字段。O(1)
HDEL删除指定哈希表中的一个或多个字段。O(N),N为被删除的字段数
HLEN获取指定哈希表中字段的数量(即哈希表的大小)。O(1)
HINCRBY将哈希表中指定字段的值增加一个整数。O(1)
HINCRBYFLOAT将哈希表中指定字段的值增加一个浮点数。O(1)

二、hash 类型内部编码

Redis 是一种高性能的内存数据库,支持多种数据结构,包括哈希(Hash)。在 Redis 中,哈希数据类型有两种内部编码方式,分别是 ziplist(压缩列表)和 hashtable(哈希表)。这两种编码方式的选择取决于哈希的大小和存储特性。

1. ziplist(压缩列表):

ziplist 是 Redis 中用于内部编码较小哈希的紧凑数据结构。以下是一些关于 ziplist 的关键特性:

  • 当哈希类型的元素个数相对较少,且所有字段和对应的值都满足一定的限制条件时,Redis 会使用 ziplist 作为哈希的内部实现。
  • 默认情况下,Redis 会选择 ziplist。具体来说,如果哈希的元素个数不超过 512 个,并且所有值都小于 64 字节,那么 ziplist 就是首选的编码方式。
  • Ziplist 是一种紧凑的数据结构,它能够在节省内存方面表现得比 hashtable 更出色。它将多个哈希元素连续存储在一起,有效地减少了内存占用。

2. hashtable(哈希表):

hashtable 是 Redis 中用于存储大规模哈希数据的内部编码方式。以下是 hashtable 的关键特性:

  • 当哈希类型的元素个数超过了 ziplist 的配置限制,或者有字段对应的值大于 64 字节时,Redis 会将内部编码切换为 hashtable。
  • Hashtable 是一种散列表数据结构,它具有 O(1) 的读写时间复杂度,适用于大规模的哈希数据集。
  • 切换到 hashtable 可以提供更好的性能和内存管理,特别是在处理大型哈希或包含大值的情况下。

根据上述描述,下面是一些示例演示哈希数据类型的内部编码以及在何种条件下会发生编码转换:

示例 1:使用 ziplist 编码

> hmset hashkey f1 v1 f2 v2
OK
> object encoding hashkey
"ziplist"

在此示例中,由于字段数较少且值满足条件,Redis 使用 ziplist 作为内部编码。

示例 2:切换到 hashtable 编码

> hset hashkey f3 "one string is bigger than 64 bytes ..." 1
OK
> object encoding hashkey
"hashtable"

在此示例中,因为有一个字段对应的值大于 64 字节,Redis 将内部编码切换为 hashtable。

示例 3:切换到 hashtable 编码

> hmset hashkey f1 v1 h2 v2 f3 v3 ... (超过 512 个字段) ...
OK
> object encoding hashkey
"hashtable"

在此示例中,由于字段数超过了 512 个,Redis 将内部编码转换为 hashtable。

这些内部编码方式的选择是为了在不同情况下平衡内存占用和性能。Redis 会根据需要自动进行这些编码转换,以优化存储和操作效率。无论您的哈希数据集大小如何,Redis 都会根据配置和数据特性智能地选择适当的内部编码方式。这种自动优化确保了 Redis 在各种工作负载下的出色性能表现。

三、hash 类型的应用场景

在本部分,我们将探讨哈希类型在应用程序中的实际应用场景。首先,让我们回顾一下关系型数据库中保存用户信息的结构。

关系型数据表保存用户信息

上图展示了关系型数据表记录的两条用户信息,其中用户的属性表现为表的列,每条用户信息则表现为行。如果我们想在 Redis 中映射这两个用户信息,可以使用哈希类型。

使用哈希类型映射用户信息:

映射关系表示用户信息

相比于使用 JSON 格式的字符串缓存用户信息,哈希类型更加直观,并且在更新操作上更加灵活。我们可以将每个用户的 ID 定义为键的后缀,然后使用多个 field-value 对应用户的各个属性,类似以下伪代码:

UserInfo getUserInfo(long uid) {// 根据 uid 得到 Redis 的键String key = "user:" + uid;// 尝试从 Redis 中获取对应的值userInfoMap = Redis 执行命令:hgetall key;// 如果缓存命中(hit)if (userInfoMap != null) {// 将映射关系还原为对象形式UserInfo userInfo = 利用映射关系构建对象(userInfoMap);return userInfo;}// 如果缓存未命中(miss)// 从数据库中,根据 uid 获取用户信息UserInfo userInfo = MySQL 执行 SQL:select * from user_info where uid = <uid>;// 如果表中没有 uid 对应的用户信息if (userInfo == null) {响应 404;return null;}// 将缓存以哈希类型保存Redis 执行命令:hmset key name userInfo.name age userInfo.age city userInfo.city;// 写入缓存,为了防止数据腐烂(rot),设置过期时间为 1 小时(3600 秒)Redis 执行命令:expire key 3600;// 返回用户信息return userInfo;
}

上述代码演示了一个常见的缓存策略,首先尝试从 Redis 缓存中获取数据,如果未命中则从数据库中检索,并将结果存储到 Redis 中以便后续访问。这种策略可以提高访问性能并减轻数据库负担。

然而,需要注意的是哈希类型和关系型数据库存在两个主要差异:

  • 哈希类型的稀疏性: 哈希类型允许每个键具有不同的 field,而关系型数据库在添加新的列时需要为所有行设置值,即使是 null。

  • 复杂关系查询的不适用性: 关系型数据库支持复杂的关系查询,而 Redis 不适用于模拟关系型复杂查询,例如联表查询和聚合查询,维护成本较高。

关系型数据库的稀疏性示例:

关系型数据库稀疏性

通过哈希类型,我们可以更直观地映射和存储用户信息,适应不同应用场景的需求。哈希类型的使用方式简单、直观、灵活,特别适合局部属性的变更和查询操作,同时也具有较好的内存效率。

四、原生,序列化,哈希类型缓存方式对比

当涉及到缓存用户信息时,有多种不同的缓存方式可供选择。以下是对三种常见的缓存方式进行详细比较和分析:原生字符串类型、序列化字符串类型(例如JSON格式),以及哈希类型。这里探讨它们的实现方法、优点和缺点,以帮助您更好地选择适用于您应用程序的缓存策略。

4.1 原生字符串类型

实现方法: 使用原生字符串类型,将每个用户属性存储为单独的键值对,例如:

set user:1:name James
set user:1:age 23
set user:1:city Beijing

优点:

  • 实现简单,每个属性都以单独的键存储,易于理解和维护。
  • 针对个别属性变更很灵活。

缺点:

  • 占用过多的键,导致内存占用量较大。
  • 用户信息在Redis中分散存储,缺少内聚性,不便于批量操作和管理。
  • 不适用于需要一次性获取完整用户信息的情况,需要大量的键操作。

适用场景: 这种方式适合于需要对用户属性进行个别、频繁变更的场景,但不适用于需要一次性获取完整用户信息的情况。

4.2 序列化字符串类型(例如JSON格式)

实现方法: 使用序列化字符串类型,将用户信息以JSON格式等方式序列化后存储为一个键值对,例如:

set user:1 {"name": "James", "age": 23, "city": "Beijing"}

优点:

  • 适用于以整体作为操作单元的信息存储,编程较为简单。
  • 可以高效地使用内存,特别适合存储大对象或数据结构。

缺点:

  • 序列化和反序列化需要一定开销。
  • 不适合频繁进行个别属性的更新或查询,缺乏灵活性。

适用场景: 这种方式适用于需要一次性获取完整用户信息的场景,特别是当用户信息是复杂对象或数据结构时。

4.3 哈希类型

实现方法: 使用哈希类型,将用户信息存储为Redis的哈希类型,例如:

hmset user:1 name James age 23 city Beijing

优点:

  • 简单、直观、灵活。
  • 适用于信息的局部变更或获取操作,支持对单个属性的读写。
  • 内部编码可以是 ziplist 或 hashtable,具有较好的灵活性和内存效率。

缺点:

  • 需要控制哈希在 ziplist 和 hashtable 两种内部编码之间的转换,可能会带来内存消耗。
  • 不适合需要一次性获取完整用户信息的情况,可能需要多次读取。

适用场景: 哈希类型适用于需要对用户属性进行局部变更或频繁单独属性操作的场景,也适合需要对属性进行灵活查询的情况。

4.4 总结

选择合适的缓存方式应根据具体的应用需求和访问模式来确定。通常情况下,可以根据不同的数据特点和操作需求,综合考虑这三种缓存方式,并在应用程序中进行适当的组合和使用,以获得最佳性能和灵活性。

例如,可以使用哈希类型缓存来处理局部属性的变更和查询,同时使用序列化字符串类型缓存来获取完整用户信息。这样,可以充分发挥Redis的优势,提高数据访问的效率,同时保持灵活性和可维性。

相关文章:

【Redis】深入探索 Redis 的数据类型 —— 哈希表 hash

文章目录 前言一、hash 类型相关命令1.1 HSET 和 HSETNX1.2 HGET 和 HMGET1.3 HKEYS、HVALS 和 HGETALL1.4 HEXISTS 和 HDEL1.5 HLEN1.6 HINCRBY 和 HINCRBYFLOAT1.7 哈希相关命令总结 二、hash 类型内部编码三、hash 类型的应用场景四、原生&#xff0c;序列化&#xff0c;哈希…...

网络安全应急响应典型案例-(DDOS类、僵尸网络类、数据泄露类)

一、DDOS类事件典型案例 DDOS攻击&#xff0c;即分布式拒绝服务攻击&#xff0c;其目的在于使目标电脑的网络或系统资源耗尽&#xff0c;使服务暂时中断或停止&#xff0c;导致其正常用户无法访问。CC攻击使用代理服务器向受害服务器发送大量貌似合法的请求&#xff08;通常…...

【测试开发】Mq消息重复如何测试?

本篇文章主要讲述重复消费的原因&#xff0c;以及如何去测试这个场景&#xff0c;最后也会告诉大家&#xff0c;目前互联网项目关于如何避免重复消费的解决方案。 Mq为什么会有重复消费的问题? Mq 常见的缺点之一就是消息重复消费问题&#xff0c;产生这种问题的原因是什么呢…...

C++和C#程序语言的区别

一直学习C++和C#,两者之间的区别总结一下 目录 一、两种语言概述 C++语言 C#语言 二、两种语言对比 2.1运行依赖...

CentOS配置Java环境报错-bash: /usr/local/jdk1.8.0_381/bin/java: 无法执行二进制文件

CentOS配置Java环境后执行java -version时报错&#xff1a; -bash: /usr/local/jdk1.8.0_381/bin/java: 无法执行二进制文件原因是所使用的jdk的版本和Linux内核架构匹配不上 使用以下命令查看Linux架构&#xff1a; [rootlocalhost ~]# cat /proc/version Linux version 3.1…...

MySQL进阶 —— 超详细操作演示!!!(上)

MySQL进阶 —— 超详细操作演示&#xff01;&#xff01;&#xff01;&#xff08;上&#xff09; 一、存储引擎1.1 MySQL 体系结构1.2 存储引擎介绍1.3 存储引擎特点1.4 存储引擎选择 二、索引2.1 索引概述2.2 索引结构2.3 索引分类2.4 索引语法2.5 SQL 性能分析2.6 索引使用2…...

一条爬虫抓取一个小网站所有数据

一条爬虫抓取一个小网站所有数据 ​ 今天闲来无事&#xff0c;写一个爬虫来玩玩。在网上冲浪的时候发现了一个搞笑的段子网&#xff0c;发现里面的内容还是比较有意思的&#xff0c;于是心血来潮&#xff0c;就想着能不能写一个Python程序&#xff0c;抓取几条数据下来看看&am…...

八大排序——快速排序

Hello&#xff0c;大家好&#xff0c;今天分享的八大排序里的快速排序&#xff0c;所谓快速排序是一个叫霍尔的人发明&#xff0c;有很多人可能会觉得为什么不叫霍尔排序&#xff0c;其中原因就是因为它快&#xff0c;快速则体现了它的特点&#xff0c;今天我们就来讲一下快速排…...

【ES】笔记-Class类剖析

Class Class介绍与初体验ES5 通过构造函数实例化对象ES6 通过Class中的constructor实列化对象 Class 静态成员实例对象与函数对象的属性不相通实例对象与函数对象原型上的属性是相通的Class中对于static 标注的对象和方法不属于实列对象&#xff0c;属于类。 ES5构造函数继承Cl…...

数学建模--Seaborn库绘图基础的Python实现

目录 1.绘图数据导入 2. sns.scatterplot绘制散点图 3.sns.barplot绘制条形图 4.sns.lineplot绘制线性图 5.sns.heatmap绘制热力图 6.sns.distplot绘制直方图 7.sns.pairplot绘制散图 8.sns.catplot绘制直方图 9.sns.countplot绘制直方图 10.sns.lmplot绘回归图 1.绘图数…...

lv3 嵌入式开发-2 linux软件包管理

目录 1 软件包管理 1.1流行的软件包管理机制 1.2软件包的类型 1.3软件包的命名 2 在线软件包管理 2.1APT工作原理 2.2更新软件源 2.3APT相关命令 3 离线软件包管理 1 软件包管理 1.1流行的软件包管理机制 Debian Linux首先提出“软件包”的管理机制---Deb软件包 …...

智能小区与无线网络技术

1&#xff0e;1 智能小区 智能小区指的是具有小区智能化系统的小区。所谓小区智能化系统&#xff0c;指的是在 现代计算机网络和通信技术的基础上&#xff0c;将传统的土木建筑技术与计算机技术、自动 控制技术、通信与信息处理技术、多媒体技术等先进技术相结合的自动化和综…...

如何传输文件流给前端

通过链接下载图片&#xff0c;直接http请求然后将文件流返回 注&#xff1a;music.ly是一个下载tiktok视频的免费接口 https://api19-core-c-useast1a.musical.ly/aweme/v1/feed/?aweme_idxxx func (m *FileBiz) DownloadFileV2(ctx *ctrl.Context, fileLink, fileName strin…...

Spring Security OAuth2 远程命令执行漏洞

文章目录 一、搭建环境二、漏洞验证三、准备payload四、执行payload五、变形payload 一、搭建环境 cd vulhub/spring/CVE-2016-4977/ docker-compose up -d 二、漏洞验证 访问 http://192.168.10.171:8080/oauth/authorize?response_type${233*233}&client_idacme&s…...

Python之并发编程介绍

一、并发编程介绍 1.1、串行、并行与并发的区别 串行(serial)&#xff1a;一个CPU上&#xff0c;按顺序完成多个任务并行(parallelism)&#xff1a;指的是任务数小于等于cpu核数&#xff0c;即任务真的是一起执行的并发(concurrency)&#xff1a;一个CPU采用时间片管理方式&am…...

GO语言网络编程(并发编程)并发介绍,Goroutine

GO语言网络编程&#xff08;并发编程&#xff09;并发介绍&#xff0c;Goroutine 1、并发介绍 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。 B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更…...

英语连词总结

前言 总结一些常用的英语连词&#xff0c;以下用法只是我希望我自己这么用。分类我可能分的不好&#xff0c;慢慢积累&#xff0c;慢慢改进。 1&#xff09;表递进: firstly、secondly、thirdly、finally、af first、at the beginning、in the end、to begin with&#xff0…...

LeetCode 92. Reverse Linked List II【链表,头插法】中等

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…...

【图论】Floyd

算法提高课笔记&#xff09; 文章目录 例题牛的旅行题意思路代码 排序题意思路代码 观光之旅题意思路代码 例题 牛的旅行 原题链接 农民John的农场里有很多牧区&#xff0c;有的路径连接一些特定的牧区。 一片所有连通的牧区称为一个牧场。 但是就目前而言&#xff0c;你…...

SpringCloudAlibaba Gateway(三)-整合Sentinel功能路由维度、API维度进行流控

Gateway整合Sentinel ​ 前面使用过Sentinel组件对服务提供者、服务消费者进行流控、限流等操作。除此之外&#xff0c;Sentinel还支持对Gateway、Zuul等主流网关进行限流。 ​ 自sentinel1.6.0版开始&#xff0c;Sentinel提供了Gateway的适配模块&#xff0c;能针对路由(rou…...

【笔试强训选择题】Day38.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01; 文章目录 前言一、Day…...

DAY08_MyBatisPlus——入门案例标准数据层开发CRUD-Lombok-分页功能DQL编程控制DML编程控制乐观锁快速开发-代码生成器

目录 一 MyBatisPlus简介1. 入门案例问题导入1.1 SpringBoot整合MyBatisPlus入门程序①&#xff1a;创建新模块&#xff0c;选择Spring初始化&#xff0c;并配置模块相关基础信息②&#xff1a;选择当前模块需要使用的技术集&#xff08;仅保留JDBC&#xff09;③&#xff1a;手…...

分光棱镜BS、PB、NPBS的区别

BS&#xff08;分光棱镜&#xff09;&#xff1a;对入射偏振敏感&#xff0c;线偏振角度会影响分光比。若入射的是自然光或圆偏振光&#xff0c;则按50&#xff1a;50分光。分束的时候只管分能量&#xff0c;理想器件下出射的两路光偏振态还是原来的样子&#xff0c;实际工艺缺…...

人工智能论文通用创新点(一)——ACMIX 卷积与注意力融合、GCnet(全局特征融合)、Coordinate_attention、SPD(可替换下采样)

1.ACMIX 卷积与注意力融合 论文地址:https://arxiv.org/pdf/2111.14556.pdf 为了实现卷积与注意力的融合,我们让特征图经过两个路径,一个路径经过卷积,另外一个路径经过Transformer,但是,现在有一个问题,卷积路径比较快,Transformer比较慢。因此,我们让Q,K,V通过1*1的…...

您的计算机已被[new_day@torguard.tg].faust 勒索病毒感染?恢复您的数据的方法在这里!

导言&#xff1a; 随着科技的迅速发展&#xff0c;网络空间也变得越来越危险&#xff0c;而勒索病毒则是网络威胁中的一个严重问题。 [ new_daytorguard.tg ].faust 勒索病毒是最新的威胁之一&#xff0c;采用高度复杂的加密技术&#xff0c;将受害者的数据文件锁定&#xff0c…...

18--Elasticsearch

一 Elasticsearch介绍 1 全文检索 Elasticsearch是一个全文检索服务器 全文检索是一种非结构化数据的搜索方式 结构化数据&#xff1a;指具有固定格式固定长度的数据&#xff0c;如数据库中的字段。 非结构化数据&#xff1a;指格式和长度不固定的数据&#xff0c;如电商网站…...

代码随想录算法训练营 day59|503.下一个更大元素II、42. 接雨水

一、503.下一个更大元素II 力扣题目链接 可以不扩充nums&#xff0c;在遍历的过程中模拟走两边nums class Solution { public:vector<int> nextGreaterElements(vector<int>& nums) {vector<int> result(nums.size(), -1);if (nums.size() 0) return…...

MyBatis数据库操作

文章目录 前言一、MyBatis的各种查询功能1.查询一个实体类对象2.查询一个List集合3.查询单个数据4.查询一条数据为map集合5.查询多条数据为map集合方法一方法二 6.测试类 二、特殊SQL的执行1.模糊查询2.批量删除3.动态设置表名5.添加功能获取自增的主键6.测试类 三、自定义映射…...

python flask框架 debug功能

从今天开始&#xff0c;准备整理一些基础知识&#xff0c;分享给需要的人吧 先整理个flask的debug功能&#xff0c;首先列举一下debug加与不加的区别&#xff0c;然后再上代码和图看看差异 区别&#xff1a; &#xff08;1&#xff09;加了debug后&#xff0c;修改js&#xf…...

《深入浅出OCR》第六章:OCR数据集与评价指标

一、OCR技术流程 在介绍OCR数据集开始&#xff0c;我将带领大家和回顾下OCR技术流程&#xff0c;典型的OCR技术pipline如下图所示&#xff0c;其中&#xff0c;文本检测和识别是OCR技术的两个重要核心技术。 1.1 图像预处理&#xff1a; 图像预处理是OCR流程的第一步&#xf…...