2009-03-11 12 views
51

Estoy tratando de optimizar un software que básicamente ejecuta millones de pruebas. Estas pruebas se generan de tal manera que puede haber algunas repeticiones. Por supuesto, no quiero perder tiempo ejecutando pruebas que ya realicé si puedo evitarlo de manera eficiente.¿Frente al filtro Bloom?

Por lo tanto, estoy pensando en utilizar un filtro Bloom para almacenar las pruebas que ya se han ejecutado. Sin embargo, el filtro Bloom se equivoca en el lado inseguro para mí. Da falsos positivos. Es decir, puede informar que realicé una prueba que no hice. Aunque esto podría ser aceptable en el escenario en el que estoy trabajando, me preguntaba si existe un equivalente a un filtro Bloom, pero se equivoca en el lado opuesto, es decir, solo se dan falsos negativos.

He hojeado la literatura sin ningún tipo de suerte.

+2

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

+0

Para completar, esto puede ser de su interés: https://github.com/ jmhodges/opposite_of_a_bloom_filter – Dave

+1

Hay una cosa así con el nombre divertido "Opuesto a un filtro Bloom". Código: https://github.com/jmhodges/opposite_of_a_bloom_filter blog: http://www.somethingsimilar.com/2012/05/21/the-opposite-of-a-bloom-filter/ – ib84

Respuesta

-1

No, y si lo piensas bien, no sería muy útil. En su caso, no puede estar seguro de que su prueba se detenga alguna vez, porque si siempre hay "falsos negativos" siempre habrá pruebas que deben ejecutarse ...

Yo diría que solo tiene que usa un hash

+0

Gracias por su respuesta. Creo que sigue siendo útil, ya que siempre puedo parar después de un período de tiempo fijo. De hecho, puedo seguir generando pruebas para siempre. Pero esa estructura de datos me ayudará a garantizar que la mayoría de las pruebas sean nuevas sin agotar la memoria rápidamente. –

6

¿Es posible almacenar las pruebas que hizo no ejecutar? Esto debería invertir el comportamiento del filtro.

+0

No puede hacer eso porque es imposible quitar elementos de un filtro Bloom. – RarrRarrRarr

+6

Un filtro de recuento de floración podría funcionar aquí –

+0

o un filtro de cuco https://www.cs.cmu.edu/~dga/papers/cuckoo-conext2014.pdf https://bdupras.github.io/filter-tutorial/ –

0

¿Qué tal un LRUCache?

0

Lo siento, no soy de mucha ayuda, no creo que sea posible. Si no se puede ordenar la ejecución de la prueba, quizás use un formato empaquetado (¡8 pruebas por byte!) O una buena biblioteca de matriz dispersa para almacenar los resultados en la memoria.

0

Creo que está dejando de lado parte de la solución; para evitar falsos positivos por completo, aún tendrá que rastrear los que se han ejecutado, y esencialmente utilizar el filtro de floración como un atajo para determinar que la prueba definitivamente no se ha ejecutado.

Dicho esto, ya que conoce el número de pruebas por adelantado, puede ajustar el tamaño del filtro de forma que proporcione una tasa de error aceptable utilizando algunas fórmulas bien conocidas; para una probabilidad del 1% de devolver un falso positivo necesitas ~ 9.5 bits/entrada, por lo que para un millón de entradas son suficientes 1.2 megabytes. Si reduce la tasa de error aceptable al 0.1%, esto solo aumenta a 1.8 MB.

El artículo de Wikipedia Bloom Filters ofrece un excelente análisis y una visión general interesante de las matemáticas involucradas.

20

Sí, una tabla hash con pérdida o una LRUCache es una estructura de datos con una búsqueda O (1) rápida que solo arrojará resultados negativos falsos. Si pregunta "¿He ejecutado la prueba X?", Le dirá " Sí, definitivamente tienes ", o" No puedo recordar ".

perdonar al pseudocódigo muy crudo:

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

Agregaría que cualquier respuesta que combine un modelo de memoria con una estrategia de desalojo, como MRU, LFU o ARC, es una respuesta válida a esta pregunta. –

+0

mientras que cualquier conjunto con pérdida de membresía discreta podría decirse que pertenece a la familia de estructuras de datos consideradas "opuestas" de conjuntos con membresía probabilística, la heurística LRU es una preocupación completamente separada y no tiene relevancia directa para la pregunta. ciertamente, también lo hace mi propia respuesta (supone la asociatividad 1), si tuviéramos que generalizar. es suficiente decir que hay una transformación 'f (set, item) -> set'' definida de tal manera que dado un' set' y un 'item', se produce un nuevo' set'' que puede incluir 'item' como miembro, sujeto a restricciones de cardinalidad. la elección de 'f' es irrelevante –

9

La estructura de datos exacta que lleva a cabo esta tarea es un Direct-mapped cache, y se utiliza comúnmente en las CPU.

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

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

También en el orden de millones, podría usar una matriz de bits simple. :) –

-1

La estructura de datos que espera no existe. Debido a que dicha estructura de datos debe ser un mapeo de varios a uno, o por ejemplo, un conjunto de estados limitados. Debe haber al menos dos entradas diferentes asignadas al mismo estado interno. Por lo tanto, no puede decir si ambos (o más) de ellos están en el conjunto, solo sabiendo que al menos uno de dichos datos existe.

EDITAR Esta afirmación es verdadera solo cuando se busca una estructura de datos con memoria eficiente. Si la memoria es ilimitada, siempre puede obtener una estructura de datos para obtener resultados 100% precisos, almacenando cada elemento miembro.

+5

Esto es objetivamente incorrecto –

+0

@ MartinKällman Tiene razón si la eficiencia de la memoria no es un requisito porque todas las soluciones propuestas anteriormente requieren el almacenamiento de los artículos originales (set_member en su caso). Después de que se alcanza el límite de memoria, daría resultados falsos negativos y falsos positivos. Bloom Filter nunca da resultados falsos negativos incluso cuando la tasa de falsos positivos es bastante alta debido a demasiadas entradas. – roam

+0

Sí, es un requisito para cualquier matriz asociativa –

0
  1. Utilice un conjunto de bits, como se mencionó anteriormente. Si sabes el no. de las pruebas que va a ejecutar de antemano, siempre obtendrá los resultados correctos (presente, no presente) de la estructura de datos.
  2. ¿Sabes qué teclas vas a utilizar hashing? Si es así, debe ejecutar un experimento para ver la distribución de las claves en BloomFilter para que pueda ajustarlo y reproducir falsos positivos, o lo que sea.
  3. Es posible que desee comprobar HyperLogLog también.