2009-03-11 13 views
51

Próbuję zoptymalizować oprogramowanie, które generuje miliony testów. Testy te są generowane w taki sposób, że mogą występować pewne powtórzenia. Oczywiście nie chcę tracić czasu na przeprowadzanie testów, które już uruchomiłem, jeśli mogę skutecznie tego uniknąć.Naprzeciwko filtra Blooma?

Zastanawiam się, czy użyć filtru Bloom do przechowywania testów, które już zostały uruchomione. Jednak filtr Bloom'a błądzi mnie po niebezpiecznej stronie. Daje fałszywe alarmy. Oznacza to, że może on zgłosić, że przeprowadziłem test, którego nie zrobiłem. Chociaż może to być dopuszczalne w scenariuszu, nad którym pracuję, zastanawiałem się, czy istnieje odpowiednik filtru Blooma, ale błądzę po przeciwnej stronie, to znaczy podaję tylko fałszywe negatywy.

Przeszukałem literaturę bez powodzenia.

+2

http://cstheory.stackexchange.com/questions/6596/a-probabilistic-set-with-no-false-positives –

+0

Dla kompletności, może to być interesujące: https://github.com/ jmhodges/opposite_of_a_bloom_filter – Dave

+1

Jest jedna taka rzecz z zabawną nazwą "Opposite of a Bloom Filter". Kod: https://github.com/jmhodges/opposite_of_a_bloom_filter blog: http://www.somethingsimilar.com/2012/05/21/the-opposite-of-a-bloom-filter/ – ib84

Odpowiedz

-1

Nie, a jeśli się nad tym zastanowić, nie byłoby to zbyt przydatne. W twoim przypadku nie możesz być pewien, że twój test kiedykolwiek się zatrzyma, ponieważ jeśli zawsze będą "fałszywe negatywy" zawsze będą testy, które trzeba uruchomić ...

Powiedziałbym, że musisz po prostu użyj skrótu.

+0

Dziękuję za odpowiedź. Myślę, że nadal jest przydatny, ponieważ zawsze mogę się zatrzymać po ustalonym czasie. W rzeczywistości mogę ciągle generować testy. Ale taka struktura danych pomoże mi zapewnić, że większość testów jest w rzeczywistości nowymi, bez szybkiego wyczerpywania pamięci. –

6

Czy można przechować testy, które wykonałeś , a nie uruchomić? Powinno to odwrócić zachowanie filtra.

+0

Nie można tego zrobić, ponieważ nie można pobrać elementów z filtru Bloom. – RarrRarrRarr

+6

Filtr kwitnących liczników może działać tutaj –

+0

lub filtr kukułka https://www.cs.cmu.edu/~dga/papers/cuckoo-conext2014.pdf https://bdupras.github.io/filter-tutorial/ –

0

Co powiesz na LRUCache?

0

Przykro mi, nie jestem zbyt pomocny - nie sądzę, że to możliwe. Jeśli nie można zamówić wykonania testu, może użyć formatu spakowanego (8 testów na bajt!) Lub dobrej biblioteki z rzadką biblioteką do przechowywania wyników w pamięci.

0

Myślę, że pomijasz część rozwiązania; Aby całkowicie uniknąć fałszywych alarmów, nadal będziesz musiał śledzić, które zostały uruchomione, i zasadniczo używaj filtru Blooma jako skrótu, aby stwierdzić, że test nie został wykonany.

To powiedziawszy, ponieważ znasz liczbę testów z wyprzedzeniem, możesz ustawić filtr w taki sposób, aby zapewnić akceptowalny poziom błędu za pomocą dobrze znanych formuł; dla 1% prawdopodobieństwa zwrotu fałszywego wyniku pozytywnego potrzebujesz ~ 9,5 bitów/wpis, więc dla miliona pozycji wystarczające jest 1,2 megabajta. Jeśli zmniejszysz dopuszczalny poziom błędu do 0,1%, to tylko zwiększy się do 1,8 MB.

Artykuł Wikipedii Bloom Filters zawiera świetną analizę i interesujący przegląd matematyki.

20

Tak, stratna tablica skrótów lub LRUCache to struktura danych z szybkim wyszukiwaniem O (1), która daje tylko fałszywe negatywy - jeśli zapytasz "Czy uruchomiłem test X", powie Ci to albo " Tak, zdecydowanie masz "lub" Nie pamiętam ".

Wybacz bardzo surowy Pseudokod:

setup_test_table(): 
    create test_table(some large number of entries) 
    clear each entry(test_table, NEVER) 
    return test_table 

has_test_been_run_before(new_test_details, test_table): 
    index = hash(test_details , test_table.length) 
    old_details = test_table[index].detail 
    // unconditionally overwrite old details with new details, LRU fashion. 
    // perhaps some other collision resolution technique might be better. 
    test_table[index].details = new_test_details 
    if (old_details === test_details) return YES 
    else if (old_details === NEVER) return NEVER 
    else return PERHAPS  

main() 
    test_table = setup_test_table(); 
    loop 
     test_details = generate_random_test() 
     status = has_test_been_run_before(test_details, test_table) 
     case status of 
      YES: do nothing; 
      NEVER: run test (test_details); 
      PERHAPS: if(rand()&1) run test (test_details); 
    next loop 
end. 
+0

Chciałbym dodać, że każda odpowiedź, która łączy model pamięci ze strategią eksmisji, taką jak MRU, LFU lub ARC, jest prawidłową odpowiedzią na to pytanie. –

+0

, podczas gdy każdy zestaw stratny z dyskretnym członkostwem można powiedzieć, że jest rodziną struktur danych uważanych za "przeciwne" zestawom z prawdopodobieństwem członkostwa, heurystyka LRU jest całkowicie odrębnym problemem i nie ma bezpośredniego związku z pytaniem. wprawdzie, tak samo jest z moją własną odpowiedzią (zakłada ona asocjatywność 1), jeśli mamy uogólniać. wystarczy powiedzieć, że istnieje transformacja 'f (set, item) -> set'' zdefiniowana tak, że biorąc pod uwagę' set' i 'item', tworzony jest nowy' set'', który może zawierać 'item'' jako członek, z zastrzeżeniem ograniczeń liczności. wybór 'f' jest nieistotny. –

9

Dokładna struktura danych, który realizuje to zadanie jest Direct-mapped cache i jest powszechnie stosowane w procesorach.

function set_member(set, item) 
    set[hash(item) % set.length] = item 

function is_member(set, item) 
    return set[hash(item) % set.length] == item 
+2

Również na zamówienie milionów można użyć prostej tablicy bitowej. :) –

-1

Struktura danych, której oczekujesz, nie istnieje. Ponieważ taka struktura danych musi być mapowaniem wielu do jednego, lub, powiedzmy, zestawem stanów ograniczonych. Musi istnieć co najmniej dwa różne wejścia mapujące do tego samego stanu wewnętrznego. Nie można więc stwierdzić, czy oba (lub więcej) z nich są w zestawie, tylko wiedząc, że przynajmniej jedno z takich danych wejściowych istnieje.

EDYCJA To stwierdzenie jest prawdziwe tylko wtedy, gdy szukasz pamięci wydajnej struktury danych. Jeśli pamięć jest nieograniczona, zawsze możesz uzyskać strukturę danych, aby uzyskać 100% dokładne wyniki, przechowując każdy element członkowski.

+5

To jest niezgodne z rzeczywistością –

+0

@ MartinKällman Masz rację, jeśli wydajność pamięci nie jest wymagana, ponieważ wszystkie rozwiązania proponowane powyżej wymagają przechowywania oryginalnych elementów (set_member w twoim przypadku). Po osiągnięciu limitu pamięci wyniki będą fałszywie ujemne i fałszywie dodatnie. Filtr Bloom nigdy nie daje wyników fałszywie ujemnych, nawet jeśli poziom fałszywych alarmów jest raczej wysoki ze względu na zbyt dużą liczbę wejść. – roam

+0

Tak, jest to wymagane dla dowolnej tablicy asocjacyjnej –

0
  1. Użyj zestawu bitów, jak wspomniano powyżej. Jeśli znasz nie. testów, które zamierzasz uruchomić wcześniej, zawsze uzyskasz poprawne wyniki (obecne, nieobecne) ze struktury danych.
  2. Czy wiesz, jakie klucze będziesz mieszać? Jeśli tak, powinieneś uruchomić eksperyment, aby zobaczyć rozmieszczenie kluczy w BloomFilter, abyś mógł go dostroić, aby odtworzyć fałszywe alarmy lub co ty.
  3. Możesz również chcieć sprawdzić HyperLogLog.