【问题标题】:Generating Verifyiable random numbers - Java生成可验证的随机数 - Java
【发布时间】:2012-10-03 01:16:23
【问题描述】:

我正在尝试验证一个属性数据库(实际上是一个文件系统,但对于本次讨论,我想保持简单)。该数据库具有以下属性:

它可以有 1 个或 2 个主键,它们必须是整数。 列可以是字符串(不允许使用 ascii)、整数、长整数或日期时间

我想验证我要求此数据库存储的值是否与大量记录(> 500k 记录)一起正确存储。因此,为此,我想扩展一个生成数据的工具,以便以后轻松验证。

所以基本上,说这是示例架构:

pk1 (int - primary key)
pk2 (int - primary key)
s1 (string)
l1 (long)
i1 (int)

我想用这个工具生成 50 万条记录。然后,在任何给定时间,我都希望能够对给定记录进行健全性检查。我可能会执行一系列操作(比如备份,然后恢复数据库),然后“抽查”一些记录。所以我希望能够快速验证主键(pk1 = 100,pk2 = 1)的记录条目是否有效。

为每列生成值以便以后轻松验证的最佳方法是什么。这些值不必是完全随机的,但它们也不应该经常重复,因此一些压缩逻辑也可能会受到影响。

例如,说“不知何故”该工具为一行生成了以下值:

pk1 = 1000
pk2 = 1
s1 = "foobar"
l1 = 12345
i1 = 17

现在我执行了几个操作,并且我想在这结束时验证该行没有损坏。在给定 pk1=1000 和 pk2=1 的情况下,我必须能够快速生成 s1、l1 和 i1 的预期值,这样才能非常快速地对其进行验证。

想法?

(由于我是新手,所以无法发布我自己的问题的答案,所以添加这个:) 好的,所以我必须采取可能的方法:

方法#1: 使用 HASH(tablename) ^ HASH(fieldname) ^ pk1 ^ pk2 作为种子。这样,我可以在验证时轻松计算每列的种子。另一方面,在为大量行生成数据时,这可能会很昂贵,因为种子需要每列计算一次。所以对于上述模式,我将有 500k*3 个种子(生成 500k 条记录)。

方法#2(由 Philipp Wendler 提出): 每行生成一个种子,并将种子存储在该行的第一列中。如果第一列是 int 或 long,则按原样存储值。如果第一列是字符串,则将种子存储在前 x 个字节中,然后使用使用该种子生成的字符将其填充到所需的字符串长度。

我更喜欢方法 #2,因为每行只有一个种子 - 使得数据生成比方法 #1 更快。

【问题讨论】:

  • 所以我正在考虑更有创意的解决方案...如果我以这种方式生成种子会怎样: Seed = HASH(tablename) ^ HASH (columnname) ^ pk1 ^ pk2 现在我可以轻松计算种子给定 pk1 和 pk2,同时仍然保持表之间的随机性。列名可以在表中重复相同的 pk1 和 pk2 值。但这没关系,因为从功能上讲,它们应该具有相同的值。。
  • 另一种选择是遵循 Philipp Wendler 建议的以下内容:使用表格的第一列来存储使用的种子。如果这是一个 int 或 long,只需将种子原样存储到其中。如果这是一个字符串,则使用前 n 个字节来存储种子,并使用使用该种子生成的字符将字段填充到所需的长度。
  • 你也生成主键吗?如果是,您可以使用它们来存储其他列的哈希。当然,这可能会在插入时给您一些冲突(但如果您随机生成 pk,这也可能发生)
  • @wmz 是的,我使用不同的种子来生成 PK。关于如何生成 PK 有不同的业务逻辑,所以我有一个很好的传播。例如,其中一个要求是 35% 的条目具有相同的 PK1 值,但唯一的 PK2 值。每个表都有不同的业务要求 - 但我想通过省略这些细节来简化问题,因为我可以自己弄清楚那部分。

标签: java testing random


【解决方案1】:

您可以生成任意随机数据,计算哈希码(例如 MD5,因为它不需要加密安全)并将哈希码与您的数据一起存储。您可以为哈希码设置一个单独的列,或者例如您可以将其附加到任何字符串列。

为了验证,将存储的哈希码与该行中的其余数据分开,重新计算哈希码并比较它们是否相等。如果它们不匹配,则说明您的数据已被修改。

这假设您只想保护您的数据免受意外修改(而不是恶意攻击者)。

【讨论】:

  • 不幸的是,修改架构不是一种选择。我认为的一个选择是从一个固定的种子开始作为应用程序的输入,然后对 pk1 和 pk2 进行异或运算。然后将其用作随机种子。所以,假设我使用输入种子作为 12345(它可以是任何东西 - 例如系统滴答声)。所以我的随机函数的种子是 12345 ^ 1000 ^ 1。然后使用 apache commons 的随机数,我可以生成每一列。这种方法的问题是我得到了几行相同的值。
  • 你的字符串是任意长度的吗?你总是有一个字符串列吗?如果是这样,只需在第一个字符串列的数据末尾附加哈希码(例如)。否则,您可以选择一个或多个数字列(如果您只存储哈希码的一些位,例如其中的 64 位就足够了)。
  • 如果我使用这种方法,验证工具只需要知道开始输入(在本例中为 12345),并且可以轻松验证给定 pk1 和 pk2 值的任何行。但是,问题是这会导致很多重复值。将为 100 个表生成数据,因此如果可以避免的话,我不想单独存储每一行​​的种子。
  • 不.. 不能保证总是有一个字符串列。让我们暂时不用担心字符串长度 - 如果我可以为一行想出一个可预测的种子,我可以轻松解决任何字符串长度的问题。问题只是想出了一个种子,我可以在验证期间轻松计算/检索它
  • 好吧,你总会有一些专栏,不是吗?因此,您可以将种子或哈希码传播到那里的第一列,无论它们的类型如何。只需使用尽可能多的列来存储种子/哈希码。
【解决方案2】:

【讨论】:

  • 谢谢穆斯特。我已经看过这个了。问题在于要使用的“种子”值,因此我可以轻松生成字符串。所以,本质上,这个问题是:给定pk1(1000)和pk2(1);我应该在 Random 生成器中使用什么种子,这样我每次都可以始终如一地为 s1、l1 和 i1 创建相同的值。
  • @walletless 只需将种子存储在其中一列中(类似于我的解决方案中建议的哈希码)。然后,您可以为每一行生成一个随机种子,并从种子中生成该行中的数据。
  • 此方法依赖于用于验证的随机数生成算法与用于生成的随机数生成算法完全相同。这现在听起来很明显,但可能是此类生成器的实现者不保证这一点,并且在将来会稍微改变他们的算法(例如,在库的下一个版本中)。然后你的数据突然就无法验证了。通过使用像任何常见哈希码这样的标准化算法,这个问题就消失了。
  • 不幸的是,修改架构不是一种选择。我认为的一个选择是从一个固定的种子开始作为应用程序的输入,然后对 pk1 和 pk2 进行异或运算。然后将其用作随机种子。所以,假设我使用输入种子作为 12345(它可以是任何东西 - 例如系统滴答声)。所以我的随机函数的种子是 12345 ^ 1000 ^ 1。然后使用 apache commons 的随机数,我可以生成每一列。这种方法的问题是我得到了几行相同的值..
  • 如果我使用这种方法,验证工具只需要知道开始输入(在本例中为 12345),并且可以轻松验证给定 pk1 和 pk2 值的任何行。但是,问题在于这会导致很多重复值。将为 100 个表生成数据,因此如果可以避免的话,我不想单独存储每一行​​的种子
【解决方案3】:

这仅回答了您问题的第二部分 - 如何让 l1 存储所有其他字段的哈希?然后您可以快速验证是否有任何损坏

【讨论】:

  • 如果架构总是有很长的,那将起作用。给定表的列集可能有也可能没有任何长列 - 它也可能有多个长列。修改任何现有架构不是一种选择,因为有些应用程序依赖于特定形式的架构 - 修改它将使在生成的数据之上发生的任何功能测试无效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-25
  • 1970-01-01
  • 1970-01-01
  • 2015-12-06
  • 1970-01-01
  • 2019-10-08
相关资源
最近更新 更多