二进制搜索或Btree索引更新问题

时间:2008-10-30 00:52:08

标签: search tree binary-search-tree binary-search b-tree

想象一下,你每天都会从作者那里收到一本新书。 这本书正在进行中。 他没有告诉你他改变或添加了什么。

您的工作是确定更改和添加内容,并将这些内容传递给发布者(他们没有时间每天阅读整本书)

出于这个问题的目的,本书由1m行的ascii文本和增长(实际上是MySQL备份文件)组成。

我目前的想法是制作每行(1k Chars)的安全散列(例如SHA256)并将其存储在HD上。由于哈希只有32字节,因此文件只有32MB。

然后,当我们明天获得下一个文件时,我们会逐行检查,为每一行创建一个新的哈希值,并将其与前一天的哈希值进行比较。

当流程完成后,我们会覆盖第二天准备好的哈希文件。

比较使用字符串比较的二进制搜索方法(>< operands) 这将返回平均四次迭代的结果。

我还没有编写btree索引解决方案,但你会如何解决这个问题呢?

6 个答案:

答案 0 :(得分:1)

我会使用diff

如果我需要在我自己的程序中实现它,我会使用其中一种算法来查找两个序列的longest common subsequence,将每个文件视为一系列行。

答案 1 :(得分:0)

“然后当我们明天收到下一个文件时,我们会逐行检查,为每一行创建一个新的哈希值,并将其与前一天的哈希值进行比较。”

得到它:今天的哈希值1m行与昨天的值的1m行相比。

是否插入或删除了行?如果没有,这是一组简单的并行读取,以查看散列是否不同。

如果有添加或删除,则必须使用diff算法来确定更改的范围。

一切都很好。实施起来并不困难。

在这种情况下,以下内容毫无意义。

  

比较使用二进制搜索   字符串比较的方法(><   operands)返回一个结果   平均四次迭代。

哈希值是否有某种排序?还是一些树形结构?

答案 2 :(得分:0)

一本100万行的书是巨大的:每页大概有30-50行,所以让我们慷慨并假设每页100行,这意味着书中有10,000页。

1 KB的线也比正常线大得多;基本的可读性表明,每行不会有那么多字符。您打算散列最大1 KB的行,还是以1 KB块的形式对文件进行分块?你的方案的一个问题是任何重复的行都会有重复的哈希值;你永远无法确定何时添加或删除了其中一行。

您可能需要通知发布商已删除的行。

与Glomek一样,我会在文件上使用diff。如果您将文件保留在RCS或CVS控制下,您将只拥有该文件的当前版本以及存储的先前版本之间的差异。有了这个,您也可以提供一周或一个月的累积差异。

我可能不会开发自己的B-Tree索引。

答案 3 :(得分:0)

您描述的解决方案与rsync算法有些类似。一个重要的一点是,rsync必须识别目标文件中任何位置的现有块,与原始文件的任何偏移量。

如果你的文件真的是记录结构,你可以像你提议的那样简化一下。如果没有,你需要一个滚动校验和。

另外,你必须承认重新排序吗?或仅插入/删除/替换?

最通用的情况是完整的rsync算法,如下所示:

  • 参数定义:

    1. 选择块大小512,或1k通常正常工作。
      • 选择“强”校验和。类似MD4左右的东西。 64位很多。
      • 选择“弱”滚动校验和。允许你“减去”尾字节并“添加”一个头字节以获得1字节前向块的校验和。通常一个16位校验和工作正常。
  • 旧文件的签名:

    1. 遍历整个旧文件,在每个块上计算弱校验和强校验和。 16位和64位校验和,512字节块表示每块10字节,或每兆字节20KB。这是'签名'
  • 使用新文件创建'patch',以及旧文件的签名:

    1. 加载旧文件的签名,最好是哈希表,弱校验和作为键,强校验和和块位置是值。
      • 阅读新文件的第一个块
      • 计算加载块的弱校验和
      • 检查哈希表以查看弱校验和是否存在。
      • 如果找到,计算强校验和并与散列中找到的校验和进行比较
      • 如果两个校验和匹配,则在散列中使用块引用标记为“得到它”,前进一整个块大小并返回到步骤3
      • 如果强校验和不匹配,或者弱校验和不在哈希中,则“滚动”弱校验和,即“添加”块之后的下一个字节,并“减去”第一个来自尾巴的字节。
      • 将尾部的'substracted'字节添加到补丁
      • 中的'new'字节列表中
      • 返回第4步
  • 将补丁应用于旧文件

    1. 'patch'是滚动校验和时丢弃的“新”字节列表,以及与旧文件匹配的“获取”块列表。

答案 4 :(得分:0)

这是一种用于数据仓库incremental loading的技术。在您无法识别源系统中已更改数据的情况下,您可以获取数据的快照并将其与上一个快照进行比较以识别差异。这项技术甚至在Ralph Kimball's book on the subject中提及,并在an application I was involved in the design of.

中使用

您需要一个具有非常宽密钥的散列算法,因为此方法容易受birthday attacks攻击。 MD5或任何SHA系列都会很好。如果没有经过差异查找丢失的自然键的后处理,它也无法检测到删除。这个计算实际上需要知道表结构。

答案 5 :(得分:0)

  

你的方案的一个问题是任何重复的行都会有重复的哈希值;你永远无法确定何时添加或删除了其中一行

非常好,但不是问题。重复的行是重复的,并且在下一个处理阶段中删除所有重复的行。所以是的,你是对的,但这不是问题。

“diff”链接将我带到一个页面,其中描述了我认为是应用程序的内容? 没有下载链接,没有任何语言的代码......我在这里缺少什么?

有些人谈到了字节级粒度。这不是必需的。只需要行级别粒度,因为如果行上的任何内容都已更改,则必须重新处理整行(记录),因为行内的任何更改都会影响整行。

所以我们在两个文件(今天的快照和昨天的快照)中比较大约1000个字符(没有二进制)的行,每个文件大约有1米行。

因此使用像SHA256这样的安全散列(MD5有冲突并且相比较慢)我可以在我的HO笔记本电脑上处理大约30MB /秒。服务器当然会更快地咀嚼它。

因此,如果文件是1GB,那么所有的hases大约需要33秒,而使用Windows页面内存读取1Gb文件需要大约30秒。不可怕

现在我们有两个散列数组,表示每个文件中的行。 如果我们对它们进行排序,我们现在可以使用二进制搜索,因此我们遍历新文件哈希,寻找旧文件哈希中的匹配项。如果我们找不到它,该行将被添加到更改文件中。

请记住,线条书(遗留数据库)在各个方面都是未知的。无法保证线路顺序,更改位置,更改类型。

逐页阅读​​前提的建议是好的,但假设这两个文件处于最佳状态,直到第一次更改。这不能假设。行(行)可以是任何顺序。选择任意块大小也会违反行的粒度。出于此任务的目的,行是不可变的。

从invrementa加载的优秀链接: 文件比较捕获:此方法也称为快照差异方法。此方法通过保留数据仓库关注的文件的图像之前和之后来工作。比较记录以查找更改,并比较记录键以查找插入和删除。由于触发器通常不存在且事务日志不存在或以专有格式存在,因此该技术在遗留系统的情况下是最合适的。由于大多数旧数据库都有一些将数据转储到文件中的机制,因此该技术会创建定期快照,然后比较结果以生成更改记录。当然,静态捕获的所有问题都存在于此。通过比较整行信息以及通过密钥识别和匹配的挑战引入了增加的复杂性。这种技术本质上是复杂的,通常是不可取的,但在某些情况下,可能是唯一的解决方案。

这是最相关的: 当我们进入TB级数据仓库的领域时,每晚从头开始重建数据仓库的能力将成为恐龙的方式。更新数据仓库的逻辑和有效方法涉及某种形式的增量更新策略。

所以我猜我现在正走在正确的轨道上? btree指数不会有优势吗?

相关问题