2014-01-04 7 views
1

У меня есть 2 файла json размером data_large(150.1mb) и data_small(7.5kb). Содержимое внутри каждого файла имеет тип [{"score": 68},{"score": 78}]. Мне нужно найти список уникальных баллов из каждого файла.Как найти уникальные значения в большом файле JSON?

Имея дело с data_small, я сделал следующее, и мне удалось просмотреть его содержимое с помощью 0.1 secs.

with open('data_small') as f: 
    content = json.load(f) 

print content # I'll be applying the logic to find the unique values later. 

Но при работе с data_large, я сделал следующее, и моя система получила повешен, медленно и пришлось заставить запорно-вниз, чтобы привести его в его нормальной скорости. Для печати его содержимого потребовалось около 2 mins.

with open('data_large') as f: 
    content = json.load(f) 

print content # I'll be applying the logic to find the unique values later. 

Как я могу увеличить эффективность программы при работе с большими наборами данных?

+0

Для больших JSon файлов см: http://stackoverflow.com/questions/10382253/reading-rather-large-json-files-in-python/10382359#10382359 Этот ответ предлагает ijson – vinod

+0

@vinod - Cant Я использую встроенные библиотеки python? –

+0

'json' builtin lib загружает весь файл за один раз. Если вам нужно перебрать его, вам нужно будет вручную разобрать json-файл или просто установить lib как 'ijson'. – miki725

ответ

3

Поскольку файл JSON не такой большой, и вы можете себе позволить, чтобы открыть его в барана все сразу, вы можете получить все уникальные значения, такие как:

with open('data_large') as f: 
    content = json.load(f) 

# do not print content since it prints it to stdout which will be pretty slow 

# get the unique values 
values = set() 
for item in content: 
    values.add(item['score']) 

# the above uses less memory compared to this 
# since this has to create another array with all values 
# and then filter it for unique values 
values = set([i['score'] for i in content]) 

# its faster to save the results to a file rather than print them 
with open('results.json', 'wb') as fid: 
    # json cant serialize sets hence conversion to list 
    json.dump(list(values), fid) 

Если вам нужно будет обрабатывать даже большие файлы , затем найдите другие библиотеки, которые могут анализировать json-файл итеративно.

+1

Использование выражения [_generator expression_] (http://docs.python.org/2/reference/expressions.html?highlight=generator%20expression#generator-expressions) во втором методе позволит избежать создания временного массива - 'list 'фактически - со всеми значениями в нем. Просто используйте 'values ​​= set (i ['score'] для i в содержимом)'. – martineau

+0

thanx. не знал этого. – miki725

+0

Для печати уникальных значений потребовалось '201secs'. Хотя 'content = ijson.items (f, 'item')' загружается быстро, но 'print set (i ['score'] для i в содержимом)' на самом деле занимает много времени. Может ли это быть более эффективным? –

0

Если вы хотите перебрать JSON-файл в меньшие куски, чтобы сохранить RAM, я предлагаю подход ниже, основываясь на ваших комментариях, которые вы не хотели использовать ijson для этого. Это работает только потому, что ваши входные данные образца настолько просты и состоят из массива словарей с одним ключом и одним значением. Это усложнилось бы с более сложными данными, и я бы пошел с реальной потоковой библиотекой JSON в этот момент.

import json 

bytes_to_read = 10000 
unique_scores = set() 

with open('tmp.txt') as f: 
chunk = f.read(bytes_to_read) 
while chunk: 
    # Find indices of dictionaries in chunk 
    if '{' not in chunk: 
     break 
    opening = chunk.index('{') 
    ending = chunk.rindex('}') 

    # Load JSON and set scores. 
    score_dicts = json.loads('[' + chunk[opening:ending+1] + ']') 
    for s in score_dicts: 
     unique_scores.add(s.values()[0]) 

    # Read next chunk from last processed dict. 
    f.seek(-(len(chunk) - ending) + 1, 1) 
    chunk = f.read(bytes_to_read) 
print unique_scores 
+0

Ну, я попробовал это, и его еще долго печатают уникальные значения. 'f = open ('data_large') content = ijson.items (f, 'item') print set (i ['score'] для i в содержимом)' –

+0

Для печати уникальных значений потребовалось '201secs'. Хотя 'content = ijson.items (f, 'item')' загружается быстро, но 'print set (i ['score'] для i в содержимом)' на самом деле занимает много времени. Может ли это быть более эффективным? –

Смежные вопросы