2010-12-14 24 views
7

mam wokół 6,00,000 entries in MongoDB w następującym formacie:Python: budowanie cache LRU

feature:category:count 

gdzie

  • cecha może być dowolne słowo,
  • kategorii jest dodatnia lub ujemna i
  • liczba mówi, ile razy wystąpiła funkcja w dokumencie dla tej kategorii.

Chcę buforować 1000 najlepszych krotek, powiedzmy, aby nie kwerendy bazy danych za każdym razem.

W jaki sposób można zbudować pamięć podręczną LRU w Pythonie? Czy są jakieś znane rozwiązania tego problemu?

Odpowiedz

3

Python 3.2 functools zawiera LRU cache. Możesz łatwo wyskoczyć z repo, sprawdzić, czy musisz dostosować to do pracy z Pythonem 2 (nie powinno być zbyt trudne - może używając itertools zamiast pewnych wbudowanych - zapytaj, czy potrzebujesz pomocy) i gotowe. Musisz zawinąć zapytanie do wywołania i upewnić się, że zależy to od argumentów funkcji (hashable) funkcji.

+0

Wydaje się to interesujące, ale jak uzyskać je od repo ??? Nie wiem jak to zrobić \ – daydreamer

+0

@learner: Najprostszym sposobem byłoby skopiowanie go z pliku, do którego linkowałem. – delnan

+0

Próbowałem, ale gdy próbuję zaimportować functools rzuca functools błąd >>> import Traceback (most recent call last): Plik "", wiersz 1, w pliku "functools.py", linia 151 nielokalne trafienia, pomyłki ^ Błąd składni: nieprawidłowa składnia Błąd w sys.excepthook: – daydreamer

5

Poza wersją zawartą w Pythonie 3.2, istnieją receptury pamięci podręcznej LRU w Python Cookbook, w tym these autorstwa głównego programisty Pythona, Raymonda Hettingera.

17

Obiekt LRU cache w Python3.3 ma O (1) wstawienia, usunięcia i wyszukiwania.

W projekcie zastosowano okrągłą podwójnie połączoną listę wpisów (ułożonych najstarszych do najnowszych) i tabelę mieszania w celu zlokalizowania poszczególnych łączy. Wyniki pamięci podręcznej używają tablicy mieszającej, aby znaleźć odpowiednie łącze i przenieść go do nagłówka listy. Pamięć podręczna pomija usunięcie najstarszego łącza i tworzy nowy link na początku połączonej listy.

Oto uproszczona (ale szybka) wersja w 33 liniach bardzo podstawowego Pythona (przy użyciu tylko prostych operacji słownika i listy). To działa na Python2.0 i później (lub pypy lub Jython lub Python3.x):

class LRU_Cache: 

    def __init__(self, original_function, maxsize=1024): 
     # Link structure: [PREV, NEXT, KEY, VALUE] 
     self.root = [None, None, None, None] 
     self.root[0] = self.root[1] = self.root 
     self.original_function = original_function 
     self.maxsize = maxsize 
     self.mapping = {} 

    def __call__(self, *key): 
     mapping = self.mapping 
     root = self.root 
     link = mapping.get(key) 
     if link is not None: 
      link_prev, link_next, link_key, value = link 
      link_prev[1] = link_next 
      link_next[0] = link_prev 
      last = root[0] 
      last[1] = root[0] = link 
      link[0] = last 
      link[1] = root 
      return value 
     value = self.original_function(*key) 
     if len(mapping) >= self.maxsize: 
      oldest = root[1] 
      next_oldest = oldest[1] 
      root[1] = next_oldest 
      next_oldest[0] = root 
      del mapping[oldest[2]] 
     last = root[0] 
     last[1] = root[0] = mapping[key] = [last, root, key, value] 
     return value 


if __name__ == '__main__': 
    p = LRU_Cache(ord, maxsize=3) 
    for c in 'abcdecaeaa': 
     print(c, p(c)) 
1

Istnieją również backporty wersji Pythona 3.3 lru_cache takich jak this który działa na Python 2.7. Jeśli interesują Cię dwie warstwy pamięci podręcznej (jeśli nie jest buforowana w instancji, sprawdzi współużytkowaną pamięć podręczną) Stworzyłem lru2cache w oparciu o protokół lru_cache.