DBS note6:Hashing(哈希存储)

2023-11-30 20:44
文章标签 哈希 存储 note6 hashing dbs

本文主要是介绍DBS note6:Hashing(哈希存储),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、一般策略

二、算法简述

三、哈希缺点(Drawbacks of Hashing)

四、举例

五、外部哈希的分析


一、一般策略

由于我们无法一次性将所有数据放入内存中,我们需要构建多个不同的哈希表并将它们连接在一起。然而,这个想法存在一个问题。

如果我们构建了两个分开的哈希表,它们中都包含相同的值(例如,“Brian” 同时出现在两个表中),那么连接这两个表将导致一些 “Brian” 并非相邻。

为了解决这个问题,在将内存中的数据构建成哈希表之前,我们需要确保如果某个特定值存在于内存中,那么它的所有出现也都在内存中。换句话说,如果 “Brian” 至少在内存中出现一次,那么只有当我们的数据中的每个 “Brian” 出现都在内存中时,我们才能构建哈希表。这确保了值只能出现在一个哈希表中,使得哈希表可以安全连接。

二、算法简述

我们将使用分治算法来解决这个问题。在 “divide” 阶段,我们执行分区传递,在 “conquer” 阶段,我们构建哈希表。就像在排序笔记中一样,我们假设有 B 个可用的缓冲帧。在对数据进行哈希时,我们将使用其中 1 个缓冲区作为输入缓冲区,剩下的 B-1 个缓冲区作为输出缓冲区。

我们开始将数据从磁盘流式传输到一个输入缓冲区。有了这些输入数据后,我们希望将它们分成几个部分。每个部分都是一组页面,这些页面上的值通过特定的哈希函数都被映射到相同的哈希值。在第一轮分割中,我们会将输入缓冲区中的每条记录通过哈希函数分到 B-1 个部分中,每个部分对应 B-1 个输出缓冲区中的一个。如果某个输出缓冲区已满,相应的页面就会被写入磁盘,然后哈希过程继续。所有来自同一缓冲区的刷新页面都会在磁盘上相邻存储。第一轮分割结束时,我们在磁盘上存储了 B-1 个部分,每个部分的数据都是连续存储的。

分区的一个重要特性是,如果某个值出现在一个分区中,我们数据中所有该值的出现都会位于同一个分区。这是因为相同的值将被哈希到相同的位置。例如,如果 “Brian” 出现在一个分区中, “Brian” 将不会出现在任何其他分区中。

在第一轮分割后,我们得到了 B-1 个大小不同的分区。对于能够放入内存的分区(分区的大小小于或等于 B 页),我们可以直接进入“conquer ”阶段,开始构建哈希表。对于太大的分区,我们需要使用不同于第一轮中使用的哈希函数进行递归分区。为什么要使用不同的哈希函数呢?如果我们重复使用原始函数,每个值都将哈希到其原始分区,因此分区的大小不会减小。我们可以使用不同的哈希函数进行递归分区,直到所有分区最多有 B 页为止。

一旦所有的分区都能够放入内存,并且相同的值都出现在同一个分区中(根据分区的特性),我们就可以开始 “conquer” 阶段。首先,我们为构建最终哈希表选择一个新的哈希函数。然后,对于每个分区,我们将分区流式传输到内存中,使用新的哈希函数创建哈希表,并将生成的哈希表刷新回磁盘。

三、哈希缺点(Drawbacks of Hashing)

需要注意的是,哈希对数据倾斜非常敏感。数据倾斜发生在我们进行哈希的值不符合均匀分布的情况下。由于哈希分区的特性(相同值的所有哈希最终都会在同一个分区中),数据倾斜可能导致分区大小非常不均匀,这对我们的目的来说是不理想的。此外,并非所有的哈希函数都是相同的。在最理想的情况下,我们的哈希函数是一个均匀的哈希函数,将数据分成“均匀”的大小相等的分区。然而,哈希函数通常是非均匀的,会在所有分区之间不均匀地分布数据。在本课程中,除非另有说明,我们将使用均匀哈希函数。在下面的两个图像中,圆柱体表示在磁盘上发生的步骤,正方形表示在内存中发生的步骤,两者之间的线表示数据在磁盘和内存之间的流动。

下面的图像展示了哈希的两个阶段 - divide 和 conquer - 当不需要递归分区时。这意味着在初始分区后,所有分区都适合于 B 页内。请注意,在 “divide ” 阶段中,1 个缓冲页专用于输入缓冲区,其余的 B-1 个用于分区。然后,在 “conquer ” 阶段中,对每个单独的分区使用不同的哈希函数 h_r 来形成内存中的哈希表。

下面的图像显示了递归分区。请注意,附加的阶段仅适用于大小大于 B 页的分区(灰色分区)。

四、举例

在以下示例中,我们假设我们有 B=3 个缓冲页可用。我们还假设对于第一个哈希函数,Brian 和 Eric 哈希到相同的值,但对于第二个哈希函数,它们哈希到不同的值,而 Jamie 和 Lakshya 对于第一个哈希函数哈希到相同的值。

在第一次分区传递(分区传递 1)后,分区 0 有 4 页,分区 1 有 2 页。分区 1 可以放入内存,但分区 0 不能。这意味着我们必须对分区 0 进行递归分区。

经过第二次分区传递后,分区 0 被分为两部分:分区 0.a 有 2 页,分区 0.b 有 2 页。由于分区 1 已经适应内存,所以在第二次分区传递期间它没有被分区。

一旦所有分区(0.a、0.b、1)适应内存,我们执行 "conquer" 并构建哈希表。可以看到在最终的 "conquer" 后,所有相同值都在一起,这是我们的最终目标。

五、外部哈希的分析

我们无法像排序算法中那样简单地创建一个计算I/O数量的公式,因为我们不知道分区的大小。我们首先需要认识到的一件事是,在分区后表的页数可能会增加。为了理解这一点,考虑下面的表,我们可以在一页上容纳两个整数:

[1, 2] [1, 4] [3, 4]

假设B=3,因此我们只将数据分为2个分区。假设1和3散列到分区1,2和4散列到分区2。分区后,分区1将包含:

[1, 1],[3]

而分区2将包含:

[4, 2],[4]

请注意,我们现在有4页,而我们一开始只有3页。因此,计算 I/O 数量的唯一可靠方法是查看每个阶段,看看将读取什么和将写入什么。设 m 为所需的总分区次数,r_i为第 i 个分区阶段需要读取的页数,w_i 为第 i 个分区阶段需要写出的页数,X 为分区后我们需要构建哈希表的总页数。以下是 I/O 数量的公式:

$(\sum_{i=1}^{m}r_i+w_i)+2X$

这个求和并没有告诉我们任何我们之前不知道的东西;我们需要逐个阶段地查看并弄清楚究竟读取了什么和写入了什么。最后的2X部分表示,为了构建我们的哈希表,我们需要读取和写入分区后拥有的每一页。

以下是一些重要的性质:

  1. r_0 = N
  2. r_i \leq w_i
  3. w_i \geq r_i+1
  4. X \geq N

性质 1 表示我们在第一次分区时必须读取每一页。这直接来自算法。

性质 2 表示在分区期间,我们将写出至少与读入的页数相同的页面。这直接来自上面的解释 - 我们可能在分区 partitioning pass 期间创建额外的页面。

性质 3 表示我们在分区通行期间读入的页面数不会超过之前写出的页面数。在最坏的情况下,第 i 次通行的每个分区都需要重新分区,因此这将要求我们读入每一页。然而,在大多数情况下,某些分区将足够小以适应内存,因此我们可以读入比上一次通行期间产生的页面更少的页面。

性质 4 表示我们用于构建哈希表的页面数至少与我们开始时的数据页面数一样多。这源于分区pass期间只能增加数据页数,而不能减少。

以上,DBS note6:Hashing(哈希存储)

祝好。

这篇关于DBS note6:Hashing(哈希存储)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/438476

相关文章

MySQL存储过程之循环遍历查询的结果集详解

《MySQL存储过程之循环遍历查询的结果集详解》:本文主要介绍MySQL存储过程之循环遍历查询的结果集,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言1. 表结构2. 存储过程3. 关于存储过程的SQL补充总结前言近来碰到这样一个问题:在生产上导入的数据发现

MySQL 存储引擎 MyISAM详解(最新推荐)

《MySQL存储引擎MyISAM详解(最新推荐)》使用MyISAM存储引擎的表占用空间很小,但是由于使用表级锁定,所以限制了读/写操作的性能,通常用于中小型的Web应用和数据仓库配置中的只读或主要... 目录mysql 5.5 之前默认的存储引擎️‍一、MyISAM 存储引擎的特性️‍二、MyISAM 的主

Linux lvm实例之如何创建一个专用于MySQL数据存储的LVM卷组

《Linuxlvm实例之如何创建一个专用于MySQL数据存储的LVM卷组》:本文主要介绍使用Linux创建一个专用于MySQL数据存储的LVM卷组的实例,具有很好的参考价值,希望对大家有所帮助,... 目录在Centos 7上创建卷China编程组并配置mysql数据目录1. 检查现有磁盘2. 创建物理卷3. 创

使用Python实现调用API获取图片存储到本地的方法

《使用Python实现调用API获取图片存储到本地的方法》开发一个自动化工具,用于从JSON数据源中提取图像ID,通过调用指定API获取未经压缩的原始图像文件,并确保下载结果与Postman等工具直接... 目录使用python实现调用API获取图片存储到本地1、项目概述2、核心功能3、环境准备4、代码实现

SpringBoot项目中Redis存储Session对象序列化处理

《SpringBoot项目中Redis存储Session对象序列化处理》在SpringBoot项目中使用Redis存储Session时,对象的序列化和反序列化是关键步骤,下面我们就来讲讲如何在Spri... 目录一、为什么需要序列化处理二、Spring Boot 集成 Redis 存储 Session2.1

基于MongoDB实现文件的分布式存储

《基于MongoDB实现文件的分布式存储》分布式文件存储的方案有很多,今天分享一个基于mongodb数据库来实现文件的存储,mongodb支持分布式部署,以此来实现文件的分布式存储,需要的朋友可以参考... 目录一、引言二、GridFS 原理剖析三、Spring Boot 集成 GridFS3.1 添加依赖

Java如何将文件内容转换为MD5哈希值

《Java如何将文件内容转换为MD5哈希值》:本文主要介绍Java如何将文件内容转换为MD5哈希值的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java文件内容转换为MD5哈希值一个完整的Java示例代码代码解释注意事项总结Java文件内容转换为MD5

java变量内存中存储的使用方式

《java变量内存中存储的使用方式》:本文主要介绍java变量内存中存储的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍2、变量的定义3、 变量的类型4、 变量的作用域5、 内存中的存储方式总结1、介绍在 Java 中,变量是用于存储程序中数据

SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法

《SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法》在SQLyog中执行存储过程时出现的前置缩进问题,实际上反映了SQLyog对SQL语句解析的一个特殊行为,本文给大家介绍了详... 目录问题根源正确写法示例永久解决方案为什么命令行不受影响?最佳实践建议问题根源SQLyog的语句分

关于MongoDB图片URL存储异常问题以及解决

《关于MongoDB图片URL存储异常问题以及解决》:本文主要介绍关于MongoDB图片URL存储异常问题以及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录MongoDB图片URL存储异常问题项目场景问题描述原因分析解决方案预防措施js总结MongoDB图