MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Duże przepływy danych przy użyciu pand

Rutynowo używam dziesiątek gigabajtów danych właśnie w ten sposób. Mam na dysku tabele, które czytam za pomocą zapytań, tworzę dane i dołączam z powrotem.

Warto przeczytać dokumentację i pod koniec tego wątku, aby uzyskać kilka sugestii dotyczących przechowywania danych.

Szczegóły, które wpłyną na sposób przechowywania danych, takie jak:
Podaj jak najwięcej szczegółów; i pomogę Ci opracować strukturę.

  1. Rozmiar danych, liczba wierszy, kolumn, typy kolumn; dołączasz wiersze, czy tylko kolumny?
  2. Jak będą wyglądać typowe operacje. Np. wykonaj zapytanie na kolumnach, aby wybrać kilka wierszy i określonych kolumn, a następnie wykonaj operację (w pamięci), utwórz nowe kolumny i zapisz je.
    (Podanie przykładu zabawki może umożliwić nam zaoferowanie bardziej szczegółowych zaleceń. )
  3. Co robisz po tym przetworzeniu? Czy krok 2 jest doraźny czy powtarzalny?
  4. Płaskie pliki wejściowe:ile, przybliżony całkowity rozmiar w GB. Jak są one zorganizowane m.in. przez rekordy? Czy każdy z nich zawiera inne pola, czy też mają jakieś rekordy na plik ze wszystkimi polami w każdym pliku?
  5. Czy kiedykolwiek wybierasz podzbiory wierszy (rekordów) na podstawie kryteriów (np. wybierasz wiersze z polem A> 5)? i potem coś zrób, czy po prostu zaznaczasz pola A, B, C ze wszystkimi rekordami (a potem coś robisz)?
  6. Czy „pracujesz” nad wszystkimi swoimi kolumnami (w grupach), czy też istnieje odpowiednia część, której możesz użyć tylko w raportach (np. chcesz zachować dane, ale nie musisz ich pobierać kolumna jawnie do czasu ostatecznych wyników)?

Rozwiązanie

Upewnij się, że masz pandy co najmniej 0.10.1 zainstalowany.

Czytaj iterowane pliki kawałek po kawałku i zapytania dotyczące wielu tabel.

Ponieważ pytables jest zoptymalizowane pod kątem operowania wierszami (czyli o co pytasz), utworzymy tabelę dla każdej grupy pól. W ten sposób łatwo jest wybrać małą grupę pól (która będzie działać z dużą tabelą, ale w ten sposób wydajniej jest to zrobić... Myślę, że być może uda mi się naprawić to ograniczenie w przyszłości... to jest w każdym razie bardziej intuicyjny):
(Poniższy to pseudokod.)

import numpy as np
import pandas as pd

# create a store
store = pd.HDFStore('mystore.h5')

# this is the key to your storage:
#    this maps your fields to a specific group, and defines 
#    what you want to have as data_columns.
#    you might want to create a nice class wrapping this
#    (as you will want to have this map and its inversion)  
group_map = dict(
    A = dict(fields = ['field_1','field_2',.....], dc = ['field_1',....,'field_5']),
    B = dict(fields = ['field_10',......        ], dc = ['field_10']),
    .....
    REPORTING_ONLY = dict(fields = ['field_1000','field_1001',...], dc = []),

)

group_map_inverted = dict()
for g, v in group_map.items():
    group_map_inverted.update(dict([ (f,g) for f in v['fields'] ]))

Wczytywanie plików i tworzenie magazynu (zasadniczo robienie tego, co append_to_multiple robi):

for f in files:
   # read in the file, additional options may be necessary here
   # the chunksize is not strictly necessary, you may be able to slurp each 
   # file into memory in which case just eliminate this part of the loop 
   # (you can also change chunksize if necessary)
   for chunk in pd.read_table(f, chunksize=50000):
       # we are going to append to each table by group
       # we are not going to create indexes at this time
       # but we *ARE* going to create (some) data_columns

       # figure out the field groupings
       for g, v in group_map.items():
             # create the frame for this group
             frame = chunk.reindex(columns = v['fields'], copy = False)    

             # append it
             store.append(g, frame, index=False, data_columns = v['dc'])

Teraz masz wszystkie tabele w pliku (właściwie możesz przechowywać je w oddzielnych plikach, jeśli chcesz, prawdopodobnie musiałbyś dodać nazwę pliku do group_map, ale prawdopodobnie nie jest to konieczne).

W ten sposób otrzymujesz kolumny i tworzysz nowe:

frame = store.select(group_that_I_want)
# you can optionally specify:
# columns = a list of the columns IN THAT GROUP (if you wanted to
#     select only say 3 out of the 20 columns in this sub-table)
# and a where clause if you want a subset of the rows

# do calculations on this frame
new_frame = cool_function_on_frame(frame)

# to 'add columns', create a new group (you probably want to
# limit the columns in this new_group to be only NEW ones
# (e.g. so you don't overlap from the other tables)
# add this info to the group_map
store.append(new_group, new_frame.reindex(columns = new_columns_created, copy = False), data_columns = new_columns_created)

Gdy będziesz gotowy do przetwarzania końcowego:

# This may be a bit tricky; and depends what you are actually doing.
# I may need to modify this function to be a bit more general:
report_data = store.select_as_multiple([groups_1,groups_2,.....], where =['field_1>0', 'field_1000=foo'], selector = group_1)

Jeśli chodzi o kolumny danych, tak naprawdę nie musisz definiować DOWOLNYCH kolumny_danych; pozwalają na podrzędny wybór wierszy na podstawie kolumny. Np. coś takiego:

store.select(group, where = ['field_1000=foo', 'field_1001>0'])

Mogą być dla Ciebie najbardziej interesujące na etapie generowania raportu końcowego (zasadniczo kolumna danych jest oddzielona od innych kolumn, co może w pewnym stopniu wpłynąć na wydajność, jeśli zdefiniujesz dużo).

Możesz również chcieć:

  • utwórz funkcję, która pobiera listę pól, wyszukuje grupy w groups_map, następnie wybiera je i łączy wyniki, aby otrzymać wynikową ramkę (to jest zasadniczo to, co robi select_as_multiple). W ten sposób struktura byłaby dla Ciebie całkiem przejrzysta.
  • indeksy w określonych kolumnach danych (sprawia, że ​​tworzenie podzbiorów wierszy jest znacznie szybsze).
  • włącz kompresję.

Daj mi znać, jeśli masz pytania!



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Myśli MongoDB i PostgreSQL

  2. Jak wyodrębnić datę utworzenia z Mongo ObjectID?

  3. Poważny spadek wydajności dzięki strumieniom zmian MongoDB

  4. mongoexport bez pola _id

  5. za dużo otwartych plików na serwerze mgo go