有效跟踪唯一条目的内存有效方法

时间:2019-04-12 20:21:12

标签: python

我大约有一个50GB的文件夹,里面装有文件。每个文件由一行一行的JSON数据组成,并且在此JSON结构中是user_id的字段。

我需要计算所有文件中唯一用户ID的数量(并且只需要总数)。什么是最有效的内存和相对快速的计数方式?

当然,将所有内容加载到庞大的列表中可能不是最佳选择。我试过熊猫,但是花了好长时间。然后,我尝试将ID简单地写入文本文件,但我想我会发现是否可能缺少更简单的东西。

4 个答案:

答案 0 :(得分:1)

由于只需要user_id,因此,加载.json(作为数据结构),提取任何id,然后销毁对该结构及其任何部分的所有引用,因此它是垃圾收集。

要加快该过程,您可以并行执行几个过程,请查看answer

答案 1 :(得分:1)

Since it was stated that the JSON context of user_id does not matter,我们只是将JSON文件视为纯文本文件。

GNU工具解决方案

我完全不会使用Python,而是依靠GNU提供的工具和管道:

cat *.json | sed -nE 's/\s*\"user_id\"\s*\:\s*\"([0-9]+)\"\s*/\1/p' | sort -un --parallel=4 | wc -l
  • cat *.json:将所有文件的内容输出到stdout
  • sed -nE 's/\s*\"user_id\"\s*\:\s*\"([0-9]+)\"\s*/\1/p':查找包含"user_id": "{number}"的行,仅将数字打印到标准输出
  • sort -un --parallel=4:使用多个(4)作业,对输出进行数字排序,忽略重复项(即仅输出唯一值),并输出到stdout
  • wc -l:计算行数,并输出到stdout

要确定值是否唯一,我们只需对它们进行排序。您可以通过指定更多的并行作业来加快排序速度,具体取决于您的核心数量。

Python解决方案

如果您仍然想使用Python,建议您使用setre(正则表达式)

import fileinput
import re

r = re.compile(r'\s*\"user_id\"\s*\:\s*\"([0-9]+)\"\s*')

s = set()
for line in fileinput.input():
    m = r.match(line)
    if m:
        s.add(m.groups()[0])

print(len(s))

使用python3 <scriptname>.py *.json运行它。

答案 2 :(得分:1)

首先尝试最简单的方法。

编写一个函数get_user_ids(filepath),该函数在JSON文件中返回user_id的列表。

然后做:

from pathlib import Path
the_folder = Path("path/to/the/folder")
user_ids = set()
for jsonpath in the_folder.glob('*.json'):
    user_ids.update(get_user_ids(jsonpath))
print(len(user_ids))

答案 3 :(得分:0)

如果用户ID列表太大,以致于无法合理地放入内存中,则一种简单且节省内存的重复数据删除方法是在空目录中简单创建以用户ID命名的文件,然后计算目录中的文件数。之所以可行,是因为大多数文件系统都能高效地索引目录中的文件名。

import os
os.chdir('/')
os.mkdir('/count_unique')
os.chdir('/count_unique')
# change the following demo tuple to a generator that reads your JSON files and yields user IDs
for user_id in 'b', 'c', 'b', 'a', 'c':
    open(user_id, 'w').close()
print(sum(1 for _ in os.scandir('/count_unique')))

这将输出:3