如何分析 ~13GB 的数据?

2022-09-03 02:40:06

我有大约300个文本文件,其中包含有关跟踪器,种子和对等体的数据。每个文件的组织方式如下:

跟踪器.txt

time torrent
    time peer
    time peer
    ...
time torrent
...

我每个跟踪器都有几个文件,并且大部分信息都是重复的(相同的信息,不同的时间)。

我希望能够分析我所拥有的内容并报告有关以下内容的统计信息

  • 每个跟踪器有多少种子
  • 有多少跟踪器是种子列在
  • 种子有多少个同行
  • 对等节点有多少种子

庞大的数据量使我很难做到这一点。这是我尝试过的。

我的SQL

我把所有东西都放进了一个数据库;每个实体类型和一个表来保存关系的表(例如,此种子在此跟踪器上)。

将信息添加到数据库很慢(当我尝试这样做时,我没有13GB的信息),但是事后分析关系是不行的。每个稍微复杂的查询需要 24 小时以上才能完成(如果有的话)。

示例查询如下:

SELECT COUNT(DISTINCT torrent) 
    FROM TorrentAtPeer, Peer 
    WHERE TorrentAtPeer.peer = Peer.id 
    GROUP BY Peer.ip;

我尝试增加文件中的内存分配,但似乎没有帮助。我使用了设置文件。my.cnfmy-innodb-heavy-4G.cnf

编辑:添加表详细信息

以下是我使用的内容:

Peer         Torrent                  Tracker        
-----------  -----------------------  ------------------  
id (bigint)  id (bigint)              id (bigint)
ip* (int)    infohash* (varchar(40))  url (varchar(255))
port (int)

TorrentAtPeer      TorrentAtTracker
-----------------  ----------------
id (bigint)        id (bigint)
torrent* (bigint)  torrent* (bigint)
peer* (bigint)     tracker* (bigint)
time (int)         time (int)

*indexed field. Navicat reports them as being of normal type and Btree method.
id - Always the primary key

没有外键。我对自己只能使用与现有实体相对应的ID的能力充满信心,添加外键检查似乎是不必要的延迟。这是天真的吗?

Matlab

这似乎是一个为繁重的工作而设计的应用程序,但我无法分配足够的内存来一次性保存所有数据。

我没有数字数据,所以我使用细胞阵列,我从这些移动到尝试以减少占用空间。我无法让它工作。

爪哇岛

我迄今为止最成功的尝试。我发现了Limewire的人提供的Patricia Tries的实现。使用此功能,我能够读取数据并计算我有多少个唯一实体:

  • 13 个跟踪器
  • 170万种子
  • 3200万同行

我仍然发现很难计算出对等节点的洪流数量的频率。我试图通过构建这样的尝试来做到这一点:

Trie<String, Trie<String, Object>> peers = new Trie<String, Trie<String, Object>>(...);
for (String line : file) {
    if (containsTorrent(line)) {
        infohash = getInfohash(line);
    }
    else if (containsPeer(line)) {
        Trie<String, Object> torrents = peers.get(getPeer(line));
        torrents.put(infohash, null);
    }
}

从我到目前为止所能做的,如果我能构建这个trie,那么我就可以很容易地找出每个对等节点上有多少个种子。我昨天运行了所有内容,当我回来时,我注意到日志文件没有被写入,我该应用程序并报告了以下内容:peers^Ztime

real 565m41.479s
user 0m0.001s
sys  0m0.019s

这对我来说看起来不对,用户和系统应该这么低吗?我应该提到,我还将JVM的堆大小增加到7GB(最大值和启动),没有这一点,我很快就会得到内存不足的错误。

我不介意等待几个小时/几天,但看起来这个东西在大约10个小时后就停止了。

我想我的问题是,我该如何分析这些数据?我尝试过的东西是正确的吗?我错过了什么吗?Java解决方案似乎是迄今为止最好的,我能做些什么来让它工作吗?


答案 1

您声明 MySQL 查询花费的时间太长。您是否确保适当的索引到位以支持您提交的请求类型?在您的示例中,这将是 的索引(甚至是嵌套索引)和 的索引。Peer.ip(Peer.ip,Peer.id)TorrentAtPeer.peer

据我所知,Java结果,您有很多数据,但没有那么多不同的字符串。因此,您可以通过为每个跟踪器,种子和对等器分配一个唯一的编号来节省一些时间。每个表使用一个表,其中一些索引值保存字符串,并将数字主键作为 id。这样,与这些实体相关的所有表只需处理这些数字,这可以节省大量空间并使您的操作速度更快。


答案 2

我会再给MySQL一次尝试,但使用不同的模式:

  • 此处不使用 id 列
  • 在这里使用自然主键:

    Peer: ip, port
    Torrent: infohash
    Tracker: url
    TorrentPeer: peer_ip, torrent_infohash, peer_port, time
    TorrentTracker: tracker_url, torrent_infohash, time

  • 对所有表使用 innoDB 引擎

这有几个优点:

  • InnoDB使用聚集索引作为主键。这意味着,当您仅从主键列请求数据时,可以直接从索引中检索所有数据,而无需进行额外的查找。因此,InnoDB表在某种程度上是索引组织的表。
  • 较小的大小,因为您不必存储代理项密钥。->速度,因为相同的结果 IO 较小。
  • 您现在可以在不使用(昂贵的)联接的情况下执行某些查询,因为您使用的是自然主键和外键。例如,链接表直接包含对等表的 as 外键。如果需要查询子网中对等方使用的种子,现在可以在不使用连接的情况下执行此操作,因为所有相关数据都在链接表中。TorrentAtPeerpeer ip

如果你想要每个对等体的洪流计数,并且你也希望对等体的ip在结果中,那么我们在这里使用自然主键/外键时再次具有优势。

使用您的架构,您必须加入才能检索ip:

SELECT Peer.ip, COUNT(DISTINCT torrent) 
    FROM TorrentAtPeer, Peer 
    WHERE TorrentAtPeer.peer = Peer.id 
    GROUP BY Peer.ip;

使用自然主键/外键:

SELECT peer_ip, COUNT(DISTINCT torrent) 
    FROM TorrentAtPeer 
    GROUP BY peer_ip;

编辑好吧,原始发布的架构不是真正的架构。现在,该表有一个字段。我建议在这里使用主键(ip,端口),并且仍然删除id列。这也意味着链接表需要具有多列外键。调整了答案...Peerport


推荐