Python中的数据库压缩

Python中的数据库压缩,python,Python,我有像这样的小时日志 user1:joined user2:log out user1:added pic user1:added comment user3:joined 我想把所有的平面文件压缩成一个文件。日志中有大约3000万用户,我只想要所有日志的最新用户日志 我的最终结果是我想要一个像 user1:added comment user2:log out user3:joined 现在我的第一次小规模尝试就是做一个像dict一样的dict log['user1'] = "added

我有像这样的小时日志

user1:joined
user2:log out
user1:added pic
user1:added comment
user3:joined
我想把所有的平面文件压缩成一个文件。日志中有大约3000万用户,我只想要所有日志的最新用户日志

我的最终结果是我想要一个像

user1:added comment
user2:log out
user3:joined
现在我的第一次小规模尝试就是做一个像dict一样的dict

log['user1'] = "added comment"
执行3000万个键/值对的dict是否会占用大量内存。。或者我应该使用类似sqllite的东西来存储它们。。然后,只需将sqllite表的内容放回一个文件中?

如果您选择了每个日志条目,那么无论它显示多少次,对于每个类似的日志条目,您将只使用一个字符串,从而大大降低内存使用率

>>> a = 'foo'
>>> b = 'foo'
>>> a is b
True
>>> b = 'f' + ('oo',)[0]
>>> a is b
False
>>> a = intern('foo')
>>> b = intern('f' + ('oo',)[0])
>>> a is b
True
如果对每个日志条目都进行了修改,那么无论它显示多少次,对于每个类似的日志条目都只使用一个字符串,从而大大降低了内存使用率

>>> a = 'foo'
>>> b = 'foo'
>>> a is b
True
>>> b = 'f' + ('oo',)[0]
>>> a is b
False
>>> a = intern('foo')
>>> b = intern('f' + ('oo',)[0])
>>> a is b
True

对于Map/Reduce解决方案来说,这似乎是一个完美的问题。见:


例如。

对于Map/Reduce解决方案来说,这似乎是一个完美的问题。见:


例如。

您也可以反向处理日志行,然后使用一个集合跟踪您看到的用户:

s = set()

# note, this piece is inefficient in that I'm reading all the lines
# into memory in order to reverse them...  There are recipes out there
# for reading a file in reverse.
lines = open('log').readlines()
lines.reverse()

for line in lines:
    line = line.strip()
    user, op = line.split(':')
    if not user in s:
         print line
         s.add(user)

您还可以反向处理日志行,然后使用一个集合跟踪您看到的用户:

s = set()

# note, this piece is inefficient in that I'm reading all the lines
# into memory in order to reverse them...  There are recipes out there
# for reading a file in reverse.
lines = open('log').readlines()
lines.reverse()

for line in lines:
    line = line.strip()
    user, op = line.split(':')
    if not user in s:
         print line
         s.add(user)

模拟数据结构以查看需要多少内存非常容易

类似于此,您可以更改gen_字符串以生成与消息近似的数据

import random
from commands import getstatusoutput as gso

def gen_string():
     return str(random.random())

 d = {}
 for z in range(10**6):
     d[gen_string()] = gen_string()

print gso('ps -eo %mem,cmd |grep test.py')[1]
在单gig上网本上:

  0.4 vim test.py
  0.1 /bin/bash -c time python test.py
 11.7 /usr/bin/python2.6 test.py
  0.1 sh -c { ps -eo %mem,cmd |grep test.py; } 2>&1
  0.0 grep test.py

   real    0m26.325s
   user    0m25.945s
   sys     0m0.377s
。。。因此,它在100000条记录中使用了大约10%的1G


但这也取决于您有多少数据冗余…

模拟数据结构以查看需要多少内存非常容易

类似于此,您可以更改gen_字符串以生成与消息近似的数据

import random
from commands import getstatusoutput as gso

def gen_string():
     return str(random.random())

 d = {}
 for z in range(10**6):
     d[gen_string()] = gen_string()

print gso('ps -eo %mem,cmd |grep test.py')[1]
在单gig上网本上:

  0.4 vim test.py
  0.1 /bin/bash -c time python test.py
 11.7 /usr/bin/python2.6 test.py
  0.1 sh -c { ps -eo %mem,cmd |grep test.py; } 2>&1
  0.0 grep test.py

   real    0m26.325s
   user    0m25.945s
   sys     0m0.377s
。。。因此,它在100000条记录中使用了大约10%的1G


但这也取决于您有多少数据冗余…

各种dbm模块(Python3中的dbm,或Python2中的anydbm、gdbm、dbhash等)允许您创建键到值映射的简单数据库。它们存储在磁盘上,因此不会对内存造成巨大影响。如果愿意,您可以将它们存储为日志。

各种dbm模块(Python3中的dbm,或Python2中的anydbm、gdbm、dbhash等)允许您创建键到值映射的简单数据库。它们存储在磁盘上,因此不会对内存造成巨大影响。如果愿意,您可以将它们存储为日志。

感谢@Ignacio for intern()-

那么,问题是这将消耗多少内存

def makeUserName():
    ch = random.choice
    syl = ['ba','ma','ta','pre','re','cu','pro','do','tru','ho','cre','su','si','du','so','tri','be','hy','cy','ny','quo','po']
    # 22**5 is about 5.1 million potential names
    return ch(syl).title() + ch(syl) + ch(syl) + ch(syl) + ch(syl)

ch = random.choice
states = ['joined', 'added pic', 'added article', 'added comment', 'voted', 'logged out']
d = {}
t = []
for i in xrange(1000):
    for j in xrange(8000):
        d[makeUserName()] = ch(states)
    t.append( (len(d), sys.getsizeof(d)) )
导致

(横轴=用户名数,纵轴=内存使用量(以字节为单位),这是。。。有点奇怪。它看起来像是一本字典预先分配了相当多的内存,然后每次太满时都会加倍


不管怎么说,400万用户占用的内存不到100MB,但实际上它重新分配了大约300万用户,50MB,因此如果双倍增长保持不变,您将需要大约800MB的内存来处理2400万到4800万用户。

多亏了@Ignacio for intern()-

那么,问题是这将消耗多少内存

def makeUserName():
    ch = random.choice
    syl = ['ba','ma','ta','pre','re','cu','pro','do','tru','ho','cre','su','si','du','so','tri','be','hy','cy','ny','quo','po']
    # 22**5 is about 5.1 million potential names
    return ch(syl).title() + ch(syl) + ch(syl) + ch(syl) + ch(syl)

ch = random.choice
states = ['joined', 'added pic', 'added article', 'added comment', 'voted', 'logged out']
d = {}
t = []
for i in xrange(1000):
    for j in xrange(8000):
        d[makeUserName()] = ch(states)
    t.append( (len(d), sys.getsizeof(d)) )
导致

(横轴=用户名数,纵轴=内存使用量(以字节为单位),这是。。。有点奇怪。它看起来像是一本字典预先分配了相当多的内存,然后每次太满时都会加倍


无论如何,400万用户占用的内存不到100MB,但实际上它重新分配了大约300万用户,50MB,因此如果双倍增长保持不变,您将需要大约800MB的内存来处理2400万到4800万用户。

当然,但字典的密钥将自动唯一。当然,但是对于字典,该键将自动是唯一的。您是否对已记录的日志执行一次此操作,如果不执行,您希望日志在某个时间段内为id存储一个结果,还是永久存储?您是否对已记录的日志执行一次此操作,如果不执行,您希望日志在某个时间段内为id存储一个结果,还是永远?