0

我正在尝试用 perl 做一件简单的事情,但我很难做到。我必须从mysql读取数据对数据做一些事情,然后打印一些东西。问题是我的数据库文件大小只有 90MB,而我的系统有 4GB 内存。谁能帮我解决这个问题?我的意思是为什么会这样?

这是我的代码:

#!/usr/bin/env perl
use common::sense;
use File::Slurp;
use Text::SpeedyFx;
use DBI;
use DBD::mysql;
my $dbh = DBI->connect('dbi:mysql:enron','x','y') or die "Connection Error:     $DBI::errstr\n";

# Create cascades
my $sql = "select uniqueid,mid,sender,receiver,unixdate,body,seen from     filteredmessage";
my $sth = $dbh->prepare($sql);
$sth->execute or die "SQL Error: $DBI::errstr\n";

# Variables
my $row; 
my $uniqueId;
my $msg1;
my $sender;
my $receiver;
my $unixdate;

my $uniqueId2;
my $msg2;
my $sender2;
my $receiver2;
my $unixdate2;
my $dif;
my $row2;
my $sql2;
my $sth2;
my $j;

my $i=1;
while ($row = $sth->fetchrow_hashref) {
    my $flagSingleRow = 0;
    $uniqueId = $row->{'uniqueid'};
    $msg1 = $row->{'body'};
    $sender = $row->{'sender'};
    $receiver = $row->{'receiver'};
    $unixdate = $row->{'unixdate'};

    $sql2 = "select uniqueid,mid,sender,receiver,unixdate,body,seen from filteredmessage";
    $sth2 = $dbh->prepare($sql2);
    $sth2->execute or die "SQL Error: $DBI::errstr\n";

    $j=1;
    while ($row2 = $sth2->fetchrow_hashref) {
        $uniqueId2 = $row2->{'uniqueid'};
        $msg2 = $row2->{'body'};
        $sender2 = $row2->{'sender'};
        $receiver2 = $row2->{'receiver'};
        $unixdate2 = $row2->{'unixdate'};

        $dif = cosine_similarity($sfx->hash_fv($msg1, 8192),$sfx->hash_fv($msg2, 8192));
        #if($dif>0.5){
            print $i." ".$j." ". $dif."\n";
        #}
        $j++;
    }
    $i++;
} 

sub cosine_similarity {
    my ($a, $b) = @_;

    my $nbits_a = unpack(q(%32b*) => $a);
    my $nbits_b = unpack(q(%32b*) => $b);

    return $nbits_a * $nbits_b
        ? unpack(q(%32b*) => $a & $b) / sqrt $nbits_a * $nbits_b
        : 0;
}
4

4 回答 4

2

Text::SpeedyFx 严重泄漏内存。这是一个简单的演示如何散列相同的事物导致内存增长。

#! /usr/bin/perl

use v5.12;
use strict;
use warnings;

use Text::SpeedyFx;

my $sfx = Text::SpeedyFx->new;

for(1..1_000) {
    $sfx->hash_fv("12345", 8192);
}

say `ps auwx $$`;

for(1..10_000) {
    $sfx->hash_fv("12345", 8192);
}

say `ps auwx $$`;

for(1..100_000) {
    $sfx->hash_fv("12345", 8192);
}

say `ps auwx $$`;

for(1..1_000_000) {
    $sfx->hash_fv("12345", 8192);
}

say `ps auwx $$`;

$ perl ~/tmp/test.plx
USER      PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
schwern 81574  29.1  0.1  2463756   8412 s000  S+    1:58AM   0:00.21 perl /Users/schwern/tmp/test.plx

USER      PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
schwern 81574  54.4  0.2  2463756  18000 s000  S+    1:58AM   0:00.22 perl /Users/schwern/tmp/test.plx

USER      PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
schwern 81574  70.2  1.4  2553868 118384 s000  S+    1:58AM   0:00.35 perl /Users/schwern/tmp/test.plx

USER      PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
schwern 81574  98.5 13.4  3561496 1122320 s000  S+    1:58AM   0:01.49 perl /Users/schwern/tmp/test.plx

每次调用 hash_v 大约需要 1K。由于 1K 是位向量大小,这表明 SpeedyFx 正在单独存储对 hash_v 的每个调用,而不是为相同的八位字节重复使用相同的插槽。

我已将此报告为错误。同时,为了缓解这个问题,您可以在外循环内初始化 Text::SpeedyFx 对象。

于 2014-12-28T07:03:16.917 回答
1

在重用新查询$sth2->finish之前尝试调用。$sth2(例如,

    }
    $sth2->finish;
    $i++;
}

)

我的第二条评论是你的函数cosine_similarity是对称的(即cosine_similarity(x,y) = cosine_similarity(y,x))。因此,如果添加ORDER BY uniqueidto$sql并进行适当更改$sql2以仅获取 where 行,您可以减少近 50% 的时间uniqueid >= $uniqueId

于 2013-09-29T06:37:30.647 回答
0

看来我的程序的主要问题是使用 $sfx->hash_fv。我必须想出一些想法来改进这个功能。这不是我自己的函数,它来自 SpeedyFx 包。无论如何,谢谢你们。

于 2013-09-29T22:08:53.580 回答
0

是否可以在两个语句句柄上使用“fetchrow_arrayref”而不是“fetchrow_hashref”?然后,您将不得不使用特定的数组索引而不是哈希键来获取您的值。

while ($row = $sth->fetchrow_arrayref) {
    my $flagSingleRow = 0;
    $uniqueId = $row->[0];
    $msg1 = $row->[1];
    $sender = $row->[2];
    $receiver = $row->[3];
    $unixdate = $row->[4];
...
# and similarly for $sth2

数组中每个字段的实际位置取决于 select 语句中列的顺序。试一试,让我们知道结果。

于 2013-09-29T07:09:10.040 回答