1

我有一个 Perl DBM 哈希,其中包含我想随机选择的 URL 列表,以对爬虫站点进行负载平衡。结果我想随机选择一个键,或者选择第 n 个元素(所以我可以随机化 n)。

我知道这违背了哈希的概念,但这可能吗?

注意:错过了一个有价值的点,即散列大小将太大而无法加载所有密钥以随机选择。

4

4 回答 4

3

我认为任何 DBM 包都没有用于检索随机密钥或通过索引号检索密钥的 API。您可以查找特定的键,或者您可以按照数据库选择返回它们的任何顺序读取所有键(如果数据库被修改,这可能会发生变化,并且对于您想要的任何内容可能足够“随机”,也可能不够“随机”去做)。

您可以通读所有键并选择一个,但这需要每次都读取整个数据库(或至少读取相当大的一部分),这可能太慢了。

我认为您需要重新排列数据结构。

  1. 您可以使用真正的 SQL 数据库(如SQLite),因此您可以通过连续的行号和 URL 来查找行。这将是最灵活的。

  2. 您可以使用连续整数作为 DBM 文件的键。这将使随机选择一个变得容易,但您无法再通过 URL 查找条目。

  3. 您可以使用两个 DBM 文件:一个是您现在拥有的,另一个是由连续整数键入的,以 URL 作为值。(实际上,由于 URL 看起来不像整数,您可以将两组记录存储在同一个 DBM 文件中,但这会使任何使用 . 的代码变得复杂each。)这将使用两倍的磁盘空间,并且会插入/删除条目有点复杂。使用方法#1 可能会更好,除非由于某种原因无法安装 SQLite。

于 2010-01-27T23:17:56.267 回答
2

从数组中选择一个随机元素更简单,因此您可以使用它keys(%foo)来获取键数组并从中随机选择。

$x我相信这将从数组中返回一个随机元素:

$x = $array[rand @array];

如果你想洗牌一个数组,考虑 List::Util::shuffle。见http://search.cpan.org/perldoc/List::Util#shuffle_LIST

于 2010-01-27T22:14:50.390 回答
1

当然,这是可能的。首先,获取密钥列表。然后,使用 List::Util 随机shuffle列表

然后,循环遍历这些键。

如果键太多(因此无法将它们全部保存在列表中并且无法改组),请记住您使用的是绑定哈希。只需用于each迭代键值对。

顺序将是确定性的,但 AFAIK,它不会按字母顺序或插入顺序。就其本身而言,它可能能够为您提供您想要的东西。

于 2010-01-27T22:10:25.950 回答
1

您可以使用DBM::Deep而不是传统的 DB 文件来保存您的数据。

tie %hash, "DBM::Deep", {
    file => "foo.db",
    locking => 1,
    autoflush => 1
};

# $hash{keys} = [ ... ]
# $hash{urls} = { ... } <- same as your current DB file.

my $like_old = $hash{urls}; # a ref to a hash you can use like your old hashref.
my $count = @{$hash{keys}};

有了它,您可以根据需要提取随机值。

于 2010-01-28T02:14:49.507 回答