Re: [Python-es] ¿Propuesta de algoritmo o estructura de datos para conjuntos aleatorios con pocos cambios?
El 28 de noviembre de 2017, 11:29, lasizoilloescribió: > > > El 27 de noviembre de 2017, 23:37, Jesus Cea escribió: > >> >> >> El objetivo es batir esas dos páginas de memoria por "lookup". ¿Ideas?. >> >> > Probablemente diga una barbaridad, pero por si acaso no lo es la digo ;-) > > https://www.kernel.org/doc/Documentation/vm/transhuge.txt > > Si el tema es evitar los accesos a páginas de memoria porque se producen > cache-miss en la tabla que mapea la memoria virtual con la física está la > posibilidad de aumentar los tamaños de las páginas de memoria. No es gratis > y no está exento de problemas, pero bajamdo al nivel que te gusta bajar es > posible que te sirva de ayuda. > > No entro en la parte de la algorítmica porque parece que la tienes atada y > no me ha dado tiempo a profundizar. De lo poco que he tenido tiempo de leer > sobre el cuckoo hashing he visto que hablaban sobre límites de ocupación > del hash ¿Puede ser eso problemático? > > Gracias a los dos por el hilo, está siendo un auténtico placer leeros. > +1 (desde la sombra de la ignorancia) > > Un abrazo, > > Javi > > ___ > Python-es mailing list > Python-es@python.org > https://mail.python.org/mailman/listinfo/python-es > > ___ Python-es mailing list Python-es@python.org https://mail.python.org/mailman/listinfo/python-es
Re: [Python-es] ¿Propuesta de algoritmo o estructura de datos para conjuntos aleatorios con pocos cambios?
El 27 de noviembre de 2017, 23:37, Jesus Ceaescribió: > > > El objetivo es batir esas dos páginas de memoria por "lookup". ¿Ideas?. > > Probablemente diga una barbaridad, pero por si acaso no lo es la digo ;-) https://www.kernel.org/doc/Documentation/vm/transhuge.txt Si el tema es evitar los accesos a páginas de memoria porque se producen cache-miss en la tabla que mapea la memoria virtual con la física está la posibilidad de aumentar los tamaños de las páginas de memoria. No es gratis y no está exento de problemas, pero bajamdo al nivel que te gusta bajar es posible que te sirva de ayuda. No entro en la parte de la algorítmica porque parece que la tienes atada y no me ha dado tiempo a profundizar. De lo poco que he tenido tiempo de leer sobre el cuckoo hashing he visto que hablaban sobre límites de ocupación del hash ¿Puede ser eso problemático? Gracias a los dos por el hilo, está siendo un auténtico placer leeros. Un abrazo, Javi ___ Python-es mailing list Python-es@python.org https://mail.python.org/mailman/listinfo/python-es
Re: [Python-es] ¿Propuesta de algoritmo o estructura de datos para conjuntos aleatorios con pocos cambios?
2017-11-27 23:37 GMT+01:00 Jesus Cea: > On 27/11/17 21:38, Francesc Alted wrote: > > De todas maneras, lo que intentaba era hacer ver > > que una ordenación siempre suele aumentar el ratio de compresión. > > Aquí > > hay un ejemplo mejor de lo que quería decir: > > > > In [40]: b = np.random.randint(2**63, size=1000*1000) > > Estás usando 63 bits, no 64, pero vale :-) > Bueno, la verdad es que confieso que mientras estaba intentando los 64 me encontré con: In [8]: b = np.random.randint(2**64, size=1000*1000) --- ValueErrorTraceback (most recent call last) in () > 1 b = np.random.randint(2**64, size=1000*1000) mtrand.pyx in mtrand.RandomState.randint (numpy/random/mtrand/mtrand.c:16123)() ValueError: high is out of bounds for int64 y me dije "bah, probablemente Jesús me va a perdonar 1 bit" :) > > Ordenar mejora la compresión porque estamos reduciendo la entropía de > los datos. En mi caso, si tengo 256000 valores diferentes, podrían > ordenarse de 256000! maneras, un número de 1.4 millones de dígitos. Si > de todas esas posibilidades me quedo exclusivamente con la versión > ordenada numéricamente, me ahorro (por entropía) unos 4229911 bits > (aproximación de Stirling del factorial). Es decir, un compresor > perfecto comprimiría mis 8192000 bytes perfectamente aleatorios a > 7663261 bytes. Una compresión teórica máxima del 6.45%. Si los datos son > verdaderamente aleatorios y la única estructura que tenemos es que están > ordenados, no podemos comprimir más que un 6.45%. Salvo error matemático > por mi parte. (considerando 256000 valores de 256 bits aleatorios). > > Por tanto, insisto nuevamente, me centraría en buscar una estructura de > datos que acceda al mínimo posible de páginas de RAM, no en comprimir, > porque por la parte de compresión estoy limitado al 6.45% de un > compresor ideal que no existe. > > Usemos la fórmula para analizar tu ejemplo. Un millón de valores son > 1e6! de combinaciones de ordenación. Si me quedo solo con la variedad > ordenada numéricamente, un compresor IDEAL podría ahorrar 18488874 bits. > Tus datos ocupan 63 bits cada uno (no 64), así que en total suman > 6300 bits. Con la compresión IDEAL salen 44511126 o 5563891 bytes. > Como tú partes de 64 bits de mentirijillas y no 63 bits reales (jeje, te > doy ventaja), el nivel de compresión máximo teórico cogiendo esos 64 > bits por elemento sería del 30.5%. > Buena estimación. Para ver que pasa con 64 bits he hecho la prueba fetén: In [25]: b = np.random.randint(2**64, size=1000*1000, dtype=np.uint64) In [26]: b.sort() In [27]: %time len(blosc.compress(b)) CPU times: user 26.3 ms, sys: 0 ns, total: 26.3 ms Wall time: 6.9 ms Out[27]: 6324530 Lo cual nos deja la compresión en un 21% (no 23% de 63 bits). Usando el codec más potente en blosc, el ztsd: In [28]: %time len(blosc.compress(b, cname="zstd")) CPU times: user 1.09 s, sys: 0 ns, total: 1.09 s Wall time: 290 ms Out[28]: 6050011 que representa el 25% de compresión (supongo que muy cerca del límite teórico). > > La compresión que muestra blosc en ese mismo ejemplo es del 23%. > Confieso que es una hazaña reseñable e inesperada y que mientras hacía > las cuentas estaba nervioso por que la "práctica" contradijese la > "teoría" matemática inviolable. A fin de cuentas yo soy ingeniero, no > matemático :-). > Bueno, mientras no se supere el límite teórico no hay ninguna 'hazaña' reseñable ;) > > > Probablemente ya lo habrás estudiado, pero con cosas como Cassandra o > > HBase no podrías atacar estos problemas? Si éstos te parecen demasiado > > 'pesados', a lo mejor un filesystem distribuido como Gluster > > (https://en.wikipedia.org/wiki/Gluster) ayudaría. Y si quieres más bajo > > nivel todavía, qué tal un simple almacén de objetos? Hay un interesante > > artículo sobre esto en: > > https://www.digitalocean.com/community/tutorials/object- > storage-vs-block-storage-services > > (a mí me gusta la aproximación de Ceph en particular). > > La clave del asunto es que los nodos de almacenaje no corren ningún > código especial. Imagina montar un sistema así con nodos tontos, simples > almacenes de datos sin capacidad para ejecutar ningún tipo de código. > Sus únicas operaciones son: escribir un objeto, leer un objeto y listar > los objetos que almacena (de forma muy lenta, por cierto). Supón que tus > nodos de almacenamiento son cosas como Google Drive o Dropbox, con una > latencia estratosférica e incapacidad total para ejecutar ningún código > más alla de GET, PUT, REMOVE o LIST. > > Los almacenes están completamente descoordinados y son TONTOS. Lo que yo > tengo montado es la inteligencia que hay por encima que permite > localizar y operar con los objetos A PESAR de que el almacenaje final no > coopera. También la replicación y la verificación de la integridad de > todo el sistema. > > Este proyecto tiene unos objetivos muy
Re: [Python-es] ¿Propuesta de algoritmo o estructura de datos para conjuntos aleatorios con pocos cambios?
On 27/11/17 21:38, Francesc Alted wrote: > En tu > caso creí entender que ordenabas los valores de alguna manera, pero > viendo los ratios que obtienes, y que son bastante más pobres que mi > prueba, posiblemente no entiendo bien a que te refieres cuando dices > 'ordenados'. Ordeno los hashes de los bloques que tiene cada nodo. Esto tiene la ventaja de que puedo hacer un MMAP de ese fichero y hacer un LOOKUP directo mediante bisección. El problema de eso es que con 2000 páginas por fichero, tengo que hacer 11 accesos a páginas diferentes. Los primeros niveles muy posiblemente estén cacheados en RAM, pero los niveles inferiores son aleatorios y poco cacheables. Muy lejos de los dos accesos a páginas que me da un "cuckoo hash". Otra ventajas de tener una lista ordenada de hashes es que operaciones como la unión, la resta de conjuntos o la intersección son muy sencillos y eficientes. Me basta con revisar un único elemento de cada conjunto y, encima, en streaming secuencial. Eso les encanta a las cachés de la CPU :-). Pasar eso a un "cuckoo hash" supone que, por ejemplo, una intersección, una resta o una unión de conjuntos requieres dos accesos secuenciales y un acceso aleatorio (en vez de dos accesos secuenciales). El acceso aleatorio es costoso pero tolerable, y los "lookups" pasan de requerir once accesos a páginas diferentes a requerir dos como mucho. La complejidad en sí del algoritmo es pequeña. La pregunta es... ¿Se puede hacer mejor? -- Jesús Cea Avión _/_/ _/_/_/_/_/_/ j...@jcea.es - http://www.jcea.es/ _/_/_/_/ _/_/_/_/ _/_/ Twitter: @jcea_/_/_/_/ _/_/_/_/_/ jabber / xmpp:j...@jabber.org _/_/ _/_/_/_/ _/_/ _/_/ "Things are not so easy" _/_/ _/_/_/_/ _/_/_/_/ _/_/ "My name is Dump, Core Dump" _/_/_/_/_/_/ _/_/ _/_/ "El amor es poner tu felicidad en la felicidad de otro" - Leibniz signature.asc Description: OpenPGP digital signature ___ Python-es mailing list Python-es@python.org https://mail.python.org/mailman/listinfo/python-es
Re: [Python-es] ¿Propuesta de algoritmo o estructura de datos para conjuntos aleatorios con pocos cambios?
On 27/11/17 21:38, Francesc Alted wrote: > En tu > caso creí entender que ordenabas los valores de alguna manera, pero > viendo los ratios que obtienes, y que son bastante más pobres que mi > prueba, posiblemente no entiendo bien a que te refieres cuando dices > 'ordenados'. Lo cierto es que puedes comprobarlo tú mismo: >>> hashes = [sha256(b'%d' % i).digest() for i in range(256000)] >>> hashes.sort() # Ordeno los hashes >>> b=blosc.compress(b''.join(hashes), typesize=32) >>> len(b) 8045911 >>> 100*(1-8045911/(256000*32)) 1.7833129882812493 1.78%. Clava a mis resultados con datos reales: > Para quedarnos todos tranquilos, voy a ver mi caso real: [...]> 1.7785873168091881 > > La compresión es del 1.78%. -- Jesús Cea Avión _/_/ _/_/_/_/_/_/ j...@jcea.es - http://www.jcea.es/ _/_/_/_/ _/_/_/_/ _/_/ Twitter: @jcea_/_/_/_/ _/_/_/_/_/ jabber / xmpp:j...@jabber.org _/_/ _/_/_/_/ _/_/ _/_/ "Things are not so easy" _/_/ _/_/_/_/ _/_/_/_/ _/_/ "My name is Dump, Core Dump" _/_/_/_/_/_/ _/_/ _/_/ "El amor es poner tu felicidad en la felicidad de otro" - Leibniz signature.asc Description: OpenPGP digital signature ___ Python-es mailing list Python-es@python.org https://mail.python.org/mailman/listinfo/python-es
Re: [Python-es] ¿Propuesta de algoritmo o estructura de datos para conjuntos aleatorios con pocos cambios?
On 27/11/17 21:38, Francesc Alted wrote: > De todas maneras, lo que intentaba era hacer ver > que una ordenación siempre suele aumentar el ratio de compresión. > Aquí > hay un ejemplo mejor de lo que quería decir: > > In [40]: b = np.random.randint(2**63, size=1000*1000) Estás usando 63 bits, no 64, pero vale :-) Ordenar mejora la compresión porque estamos reduciendo la entropía de los datos. En mi caso, si tengo 256000 valores diferentes, podrían ordenarse de 256000! maneras, un número de 1.4 millones de dígitos. Si de todas esas posibilidades me quedo exclusivamente con la versión ordenada numéricamente, me ahorro (por entropía) unos 4229911 bits (aproximación de Stirling del factorial). Es decir, un compresor perfecto comprimiría mis 8192000 bytes perfectamente aleatorios a 7663261 bytes. Una compresión teórica máxima del 6.45%. Si los datos son verdaderamente aleatorios y la única estructura que tenemos es que están ordenados, no podemos comprimir más que un 6.45%. Salvo error matemático por mi parte. (considerando 256000 valores de 256 bits aleatorios). Por tanto, insisto nuevamente, me centraría en buscar una estructura de datos que acceda al mínimo posible de páginas de RAM, no en comprimir, porque por la parte de compresión estoy limitado al 6.45% de un compresor ideal que no existe. Usemos la fórmula para analizar tu ejemplo. Un millón de valores son 1e6! de combinaciones de ordenación. Si me quedo solo con la variedad ordenada numéricamente, un compresor IDEAL podría ahorrar 18488874 bits. Tus datos ocupan 63 bits cada uno (no 64), así que en total suman 6300 bits. Con la compresión IDEAL salen 44511126 o 5563891 bytes. Como tú partes de 64 bits de mentirijillas y no 63 bits reales (jeje, te doy ventaja), el nivel de compresión máximo teórico cogiendo esos 64 bits por elemento sería del 30.5%. La compresión que muestra blosc en ese mismo ejemplo es del 23%. Confieso que es una hazaña reseñable e inesperada y que mientras hacía las cuentas estaba nervioso por que la "práctica" contradijese la "teoría" matemática inviolable. A fin de cuentas yo soy ingeniero, no matemático :-). > Probablemente ya lo habrás estudiado, pero con cosas como Cassandra o > HBase no podrías atacar estos problemas? Si éstos te parecen demasiado > 'pesados', a lo mejor un filesystem distribuido como Gluster > (https://en.wikipedia.org/wiki/Gluster) ayudaría. Y si quieres más bajo > nivel todavía, qué tal un simple almacén de objetos? Hay un interesante > artículo sobre esto en: > https://www.digitalocean.com/community/tutorials/object-storage-vs-block-storage-services > (a mí me gusta la aproximación de Ceph en particular). La clave del asunto es que los nodos de almacenaje no corren ningún código especial. Imagina montar un sistema así con nodos tontos, simples almacenes de datos sin capacidad para ejecutar ningún tipo de código. Sus únicas operaciones son: escribir un objeto, leer un objeto y listar los objetos que almacena (de forma muy lenta, por cierto). Supón que tus nodos de almacenamiento son cosas como Google Drive o Dropbox, con una latencia estratosférica e incapacidad total para ejecutar ningún código más alla de GET, PUT, REMOVE o LIST. Los almacenes están completamente descoordinados y son TONTOS. Lo que yo tengo montado es la inteligencia que hay por encima que permite localizar y operar con los objetos A PESAR de que el almacenaje final no coopera. También la replicación y la verificación de la integridad de todo el sistema. Este proyecto tiene unos objetivos muy concretos. No pretende competir con sistemas de almacenamiento distribuidos donde tienes el lujo de ejecutar código en la máquina que te da el almacenamiento. En mi caso yo no puedo ni siquiera confiar en que el almacenamiento no me mienta descaradamente, como para entregarle alguna responsabilidad en la gestión del sistema... Mi sistema lleva funcionando años con una excelente trayectoria. A medida que crece el espacio de almacenaje hay que evolucionar los algoritmos. No por un tema específicamente de velocidad, que es buena ahora mismo cuando no paginas, sino porque a medida que los índices crecen y ocupan más, acabas paginando. El cambio a "cuckoo hashes" reduciría mis necesidades de memoria respecto a la versión actual del sistema a un tercio, aproximadamente. Es decir, con los recursos actuales, puedo triplicar mi tamaño hasta volver a tropezarme con el problema que empiezo a rozar ahora: paginar. Ahora mismo estoy empezando a paginar en algunos momentos. Durante esos "eventos", el rendimiento del sistema se va al garete y el problema persiste durante dos o tres minutos por "evento". Reduciendo mis necesidades de memoria a un tercio, puedo triplicar mi tamaño hasta que vuelva a encontrarme en el mismo punto que estoy ahora, donde la paginación "está empezando a molestar" (pero aún no es grave y supone solo molestias esporádicas). Con mi ritmo de crecimiento de los últimos años, esto me da unos dos o tres años de vida,
Re: [Python-es] ¿Propuesta de algoritmo o estructura de datos para conjuntos aleatorios con pocos cambios?
2017-11-27 20:12 GMT+01:00 Jesus Cea: > On 27/11/17 19:01, Francesc Alted wrote: > > Sin embargo, antes de decidir si tu > > conjunto comprime bien o no, nunca está de más hacer una prueba. Lo que > > me hacía pensar en que tus datos podrían ser comprimibles es > > precisamente lo que decías de que los valores te llegaban ordenados, y > > sé que eso puede afectar mucho al ratio de compresión. Por ejemplo, > > usando un conjunto de números aleatorios de 1 millón de enteros de 64 > > bits (en total 8 MB) se tiene: > > Estás siendo un poco tramposo, Francesc :-). En tu ejemplo, tus datos no > ocupan 64 bits cada uno, ocupan 20 bits escasos. Además, como generas un > millón de valores en el rango 0-99, la diferencia entre un valor y > el siguiente es muy pequeño, incluso cero :-). > Así no vale :-). > > Bueno, más que tramposo me faltaba información sobre la distribución de tus datos; viendo que estás tratando con valores SHA256, ya veo de que estamos hablando :) De todas maneras, lo que intentaba era hacer ver que una ordenación siempre suele aumentar el ratio de compresión. Aquí hay un ejemplo mejor de lo que quería decir: In [40]: b = np.random.randint(2**63, size=1000*1000) In [41]: %time len(blosc.compress(b)) CPU times: user 74.8 ms, sys: 2.2 ms, total: 77 ms Wall time: 23 ms Out[41]: 816 # sin compresion In [42]: b.sort() In [43]: %time len(blosc.compress(b)) CPU times: user 51.1 ms, sys: 1.93 ms, total: 53 ms Wall time: 15.6 ms Out[43]: 6165702 # hay compression En los dos casos los datos son aleatorios, pero en el segundo caso están ordenados, y por tanto comprimen (un 23% de reducción en este caso, bastante notable para datos pseudo-aleatorios como éste). En tu caso creí entender que ordenabas los valores de alguna manera, pero viendo los ratios que obtienes, y que son bastante más pobres que mi prueba, posiblemente no entiendo bien a que te refieres cuando dices 'ordenados'. > Para quedarnos todos tranquilos, voy a ver mi caso real: > > >>> import blosc > >>> # Eliminamos el número de versión y el hash final de integridad > >>> data=open("", "rb").read()[1:-32] > >>> len(data) > 8041888 > >>> len(blosc.compress(data, typesize=32)) > 7898856 > >>> 100 * (1 - 7898856 / 8041888) > 1.7785873168091881 > > La compresión es del 1.78%. Es inferior al 3.3% de simplemente dividir > la tabla en 256 tablas y eliminar el primer byte de cada valor en cada > subtabla. Posiblemente se pueda llegar con facilidad al 3% con blosc > usando prefiltros. > Blosc usa el filtro de SHUFFLE por defecto, así que tus datos son claramente *dificilmente comprimibles*. > Mis datos son verdaderamente aleatorios en sus 256 bits. Son el SHA256 > de bloques de datos cifrados con claves a azar. Más (pseudo)aleatorio > imposible :-). > > Aplicar blosc a un filtro cuckoo donde los fingerprints son más pequeños > (digamos, 32 bits) parece más prometedor, pero en ese caso los > fingerprints no están ordenados, tendrán un orden aleatorio y tampoco > los vas a poder comprimir. Por ejemplo: > > >>> b=np.random.randint(2**32, size=1000*1000) > # NO HAGO EL 'SORT()' PORQUE EN UN FILTRO CUCKOO LOS FINGERPRINTS > # ESTAN DESORDENADOS. > >>> len(blosc.compress(b)) > 4018965 > > Dado que los datos ocupan realmente 400 bytes, blocs los expande un > 0.5%. > > Que conste que blosc me parece un proyecto espectacular. Sencillamente > no parece aplicable en este caso. > > Dicho lo cual, las discusiones sobre algoritmos me encantan. Sigamos :-). > > De momento sigo pensando que lo mejor que puedo hacer es usar "hash > cuckoo" con un posible "filtro cucko" con una pequeña tasa de falsos > positivos para una parte concreta del proceso. > > Por si alguien se pregunta sobre el uso de todo esto, se trata de un > sistema de localización de bloques de datos en un sistema de > almacenamiento distribuido donde no puedes controlar dónde se almacena > cada bloque, pero debes saber dónde está a la hora de buscarlo, o > declarar taxativametne que ese bloque no existe en el sistema. No se > controla dónde se guardan las cosas, no hay rebalanceo a posteriori ni > tampoco puedes contar con meter inteligencia en los nodos de > almacenamiento más allá de un WEBDAV para listar, leer y escribir > bloques (inmutables). > > A la hora de localizar bloques podría tolerarse una pequeña tasa de > falsos positivos, que te obligaría a buscar en dos servidores en vez de > solo en uno. Molesto, pero tolerable. Pero hay otras tareas donde no > puedo permitir falsos positivos, como es el caso de la replicación > (salvo que los falsos positivos se aleatoricen y sean diferentes cada > vez, aceptando que pueden ser necesario hacer varias replicaciones para > asegurarnos de que realmente está todo replicado) o el control de > integridad (verificar que no sobra ni falta ningún bloque en el sistema). > Probablemente ya lo habrás estudiado, pero con cosas como Cassandra o HBase no podrías atacar estos problemas?
Re: [Python-es] ¿Propuesta de algoritmo o estructura de datos para conjuntos aleatorios con pocos cambios?
On 27/11/17 19:01, Francesc Alted wrote: > Sin embargo, antes de decidir si tu > conjunto comprime bien o no, nunca está de más hacer una prueba. Lo que > me hacía pensar en que tus datos podrían ser comprimibles es > precisamente lo que decías de que los valores te llegaban ordenados, y > sé que eso puede afectar mucho al ratio de compresión. Por ejemplo, > usando un conjunto de números aleatorios de 1 millón de enteros de 64 > bits (en total 8 MB) se tiene: Estás siendo un poco tramposo, Francesc :-). En tu ejemplo, tus datos no ocupan 64 bits cada uno, ocupan 20 bits escasos. Además, como generas un millón de valores en el rango 0-99, la diferencia entre un valor y el siguiente es muy pequeño, incluso cero :-). Así no vale :-). Para quedarnos todos tranquilos, voy a ver mi caso real: >>> import blosc >>> # Eliminamos el número de versión y el hash final de integridad >>> data=open("", "rb").read()[1:-32] >>> len(data) 8041888 >>> len(blosc.compress(data, typesize=32)) 7898856 >>> 100 * (1 - 7898856 / 8041888) 1.7785873168091881 La compresión es del 1.78%. Es inferior al 3.3% de simplemente dividir la tabla en 256 tablas y eliminar el primer byte de cada valor en cada subtabla. Posiblemente se pueda llegar con facilidad al 3% con blosc usando prefiltros. Mis datos son verdaderamente aleatorios en sus 256 bits. Son el SHA256 de bloques de datos cifrados con claves a azar. Más (pseudo)aleatorio imposible :-). Aplicar blosc a un filtro cuckoo donde los fingerprints son más pequeños (digamos, 32 bits) parece más prometedor, pero en ese caso los fingerprints no están ordenados, tendrán un orden aleatorio y tampoco los vas a poder comprimir. Por ejemplo: >>> b=np.random.randint(2**32, size=1000*1000) # NO HAGO EL 'SORT()' PORQUE EN UN FILTRO CUCKOO LOS FINGERPRINTS # ESTAN DESORDENADOS. >>> len(blosc.compress(b)) 4018965 Dado que los datos ocupan realmente 400 bytes, blocs los expande un 0.5%. Que conste que blosc me parece un proyecto espectacular. Sencillamente no parece aplicable en este caso. Dicho lo cual, las discusiones sobre algoritmos me encantan. Sigamos :-). De momento sigo pensando que lo mejor que puedo hacer es usar "hash cuckoo" con un posible "filtro cucko" con una pequeña tasa de falsos positivos para una parte concreta del proceso. Por si alguien se pregunta sobre el uso de todo esto, se trata de un sistema de localización de bloques de datos en un sistema de almacenamiento distribuido donde no puedes controlar dónde se almacena cada bloque, pero debes saber dónde está a la hora de buscarlo, o declarar taxativametne que ese bloque no existe en el sistema. No se controla dónde se guardan las cosas, no hay rebalanceo a posteriori ni tampoco puedes contar con meter inteligencia en los nodos de almacenamiento más allá de un WEBDAV para listar, leer y escribir bloques (inmutables). A la hora de localizar bloques podría tolerarse una pequeña tasa de falsos positivos, que te obligaría a buscar en dos servidores en vez de solo en uno. Molesto, pero tolerable. Pero hay otras tareas donde no puedo permitir falsos positivos, como es el caso de la replicación (salvo que los falsos positivos se aleatoricen y sean diferentes cada vez, aceptando que pueden ser necesario hacer varias replicaciones para asegurarnos de que realmente está todo replicado) o el control de integridad (verificar que no sobra ni falta ningún bloque en el sistema). -- Jesús Cea Avión _/_/ _/_/_/_/_/_/ j...@jcea.es - http://www.jcea.es/ _/_/_/_/ _/_/_/_/ _/_/ Twitter: @jcea_/_/_/_/ _/_/_/_/_/ jabber / xmpp:j...@jabber.org _/_/ _/_/_/_/ _/_/ _/_/ "Things are not so easy" _/_/ _/_/_/_/ _/_/_/_/ _/_/ "My name is Dump, Core Dump" _/_/_/_/_/_/ _/_/ _/_/ "El amor es poner tu felicidad en la felicidad de otro" - Leibniz signature.asc Description: OpenPGP digital signature ___ Python-es mailing list Python-es@python.org https://mail.python.org/mailman/listinfo/python-es
Re: [Python-es] ¿Propuesta de algoritmo o estructura de datos para conjuntos aleatorios con pocos cambios?
On 27/11/17 10:29, Francesc Alted wrote: > Lo único que se me ocurre es que, para minimizar el uso de memoria uses > compresión para tus bloques binarios (dices que te llegan ordenados > numéricamente, así que seguro que se pueden obtener buenos ratios de > compresión). En realidad la compresión es mínima y no compensa. Son valores aleatorios de 256 bits. Aunque estén ordenados de forma numérica, la ganancia es mínima. Por ejemplo, un grupo típico tiene 256000 valores. Como cada valor tiene 256 bits, eso supone que cada fragmento de 1000 valores consecutivos empieza con el mismo byte. Dividiendo esa tabla de 256000 valores en 256 tablas de 1000 valores cada una, ocupando cada entrada 31 bytes en vez de 32 (porque el primer byte es implícito), la ganancia es de 32->31 bytes, es decir, apenas un 3%. Algo es algo, es verdad. Pero no sé si me compensa picar código para ganar un 3%. Además, si uso algo tipo "cuckoo hashing", no puedo aplicar esa compresión en memoria, que es donde la necesitaría (para paginar lo mínimo posible). > Para las búsquedas puedes continuar usando hashes cuckoo, > pero sólo guardando las claves, no los valores Es cierto, no lo he explicado: Estoy usando esto para "conjuntos", no para "diccionarios". Es decir, solo hay claves, no hay valores :). Pero buen apunte para otra ocasión. > clase de acceso de manera muy eficiente a través de la llamada > `blosc_getitem()` Valoré Blosc brevemente, pero considero que mis datos son "incompresibles" en RAM. Estoy más interesado en la parte de la estructura de datos a utilizar para que las búsquedas sean eficientes considerando que tengo poca RAM, no hay localidad de acceso en las búsquedas (los datos que se buscan son aleatorios y no hay correlación entre ellos) y puedo necesitar paginar al SWAP. Por eso estoy tan interesado en reducir al mínimo los accesos a páginas diferentes de 4096 bytes (La unidad de paginación). Los haskes cuckoo me garantizan un máximo de dos accesos por búsqueda en el peor de los casos. Posiblemente no sea mejorable y, básicamente me interesa que alguien me diga "pues estás equivocado, Jesús, mírate el algoritmo XXX, que te garantiza un único acceso a página". De hecho en este caso existe una posibilidad más: Como los datos son aleatorios y "bien repartidos", podría hacer una búsqueda "estimativa" en plan: "me da en la nariz que el valor, si existe, está en esta zona" y buscar directamente allí. Las búsquedas dentro de una página de 4096 bytes las considero "gratis". Lo que duele es la paginación. 4096 bytes me dan para 128 entradas. Mirarlas una a una es "gratis" comparado con tocar el disco duro. Esto ya lo había pensado, pero lo cierto es que por necesidades del sistema no puedo basarme en que los datos estén "bien repartidos". Ahora mismo lo están, pero no es un requerimiento de diseño y puede no cumplirse en el futuro. Necesito algo capaz de sobrevivir a "sesgos". Otra posibilidad sería tener una tabla con el primer primer registro de cada página de 4096 bytes. Es decir, 32 bytes por cada 128 registros (4kbytes). Si mi conjunto tiene 256 entradas, son 2000 páginas de 4096 bytes. Puedo tener un índice de 2000 entradas (64000 bytes, 16 páginas de 4096 bytes). La búsqueda en el índice es binaria y podría tocar 4 páginas, pero es razonable pensar que un índice de 64Kbytes sí lo puedo mantener en RAM, incluso con un "MAP_LOCKED" o "mlock()". Claro que el problema es que mis datos no miden 256000 entradas. Son docenas de conjuntos, cada uno con 256000 entradas. No estamos hablando de 64 kbytes en RAM para el índice, sino 64*número de conjuntos, y ese numero de conjuntos va por los cientos y subiendo. En fin, el asunto es engañosamente sencillo. De momento va ganando el cuckoo hashing. Es una estructura sencilla y me garantiza un máximo de dos accesos a página, por muy grandes o muy raros que sean mis datos. Mi esperanza es que alguien me sugiera algo mejor :-). Para uno de los modos de uso del sistema, el que más me importa, estoy valorando usar "filtros cuckoo", tolerando un pequeño nivel de falsos positivos, del orden del UNO por millón. Sigo teniendo dos accesos por búsqueda, pero como ahora la estructura es más pequeña es más factible que el número de accesos al SWAP se reduzca (recordemos que lo que me penaliza es la paginación, las búsquedas en memoria las considero gratis). Esto complicaría ese caso de uso porque ahora podría tener falsos positivos, lo que supone que una vez por millón de accesos voy a ir a buscar el dato a un servidor, me va decir que no está ahí y luego tengo que hacer un acceso al servidor "por defecto". Ese "error" es muy costoso en recursos y tiempo, pero si solo ocurre una vez por millón de accesos, el coste amortizado es bajo. Decisiones, decisiones... Gracias por responder, Francesc. Buen aporte. -- Jesús Cea Avión _/_/ _/_/_/_/_/_/ j...@jcea.es - http://www.jcea.es/ _/_/_/_/ _/_/_/_/ _/_/ Twitter: @jcea
Re: [Python-es] ¿Propuesta de algoritmo o estructura de datos para conjuntos aleatorios con pocos cambios?
Lo único que se me ocurre es que, para minimizar el uso de memoria uses compresión para tus bloques binarios (dices que te llegan ordenados numéricamente, así que seguro que se pueden obtener buenos ratios de compresión). Para las búsquedas puedes continuar usando hashes cuckoo, pero sólo guardando las claves, no los valores, y así maximizas la localidad de los accesos a memoria (durante la búsqueda no te sirve de nada traer los valores a las lineas de cache). Una vez localizado el lugar donde está el valor puedes acceder al bloque comprimido que toque, descomprimir, y extraerlo. Blosc te permite esta clase de acceso de manera muy eficiente a través de la llamada `blosc_getitem()` ( https://github.com/Blosc/c-blosc/blob/master/blosc/blosc.h#L290). Si eliges el tamaño de bloque lo suficientemente pequeño (digamos 4/8/16/32 KB), la descompresión normalmente sucede en la cache L1, así que es muy rápido. Francesc 2017-11-27 5:13 GMT+01:00 Jesus Cea: > Requisitos: > > Tengo millones de bloques binarios de 256 bits. Estos millones de > bloques están divididos aleatoriamente en grupos, digamos de un millón > de elementos. > > Las operaciones básicas que debo soportar son: > > 1. Creación de un grupo. Una vez creado un grupo, no necesita ser > actualizado. Ni para añadir ni para eliminar. > > 2. Comprobar si un elemento pertenece a un grupo concreto. > > 3. Generar un grupo nuevo como unión de dos o más grupos. > > 4. Generación de un grupo nuevo como intersección de dos o más grupos. > > 5. Iterar sobre un grupo. El orden no es importante. > > A nivel de limitaciones, la más importante es que la sobrecarga en > memoria debe ser lo mínimo posible. Cada elemento ocupa 32 bytes (256 > bits). La segunda más importante es que el algoritmo debe ser "cache > friendly", sobre todo en la parte de búsqueda de pertenencia. En > realidad solo necesito que el número de bloques de memoria de 4096 bytes > que se revisan para buscar un elemento sea lo más bajo posible, porque > el entorno de trabajo tiene muy poca memoria RAM pero se puede tirar de > SWAP. > > No puedo tolerar falsos positivos, así que no puedo usar filtros bloom o > filtros cuckoo. De momento la estructura de datos que va ganando son los > hashes cuckoo: La ocupación de memoria es prácticamente óptima y solo > requiere acceder a dos bloques de 4096 bytes. > > En cuanto a los datos en sí, son valores de 256 bits aleatorios. Ahora > mismo los recibo en orden numérico, pero podría generar cualqueir otra > estructura. Por ejemplo, podrían almacenarse directamente como un hash > cuckoo para no tener que regenerarlos en tiempo de ejecución cada vez. > > Buscando en PYPI veo un par de proyectos que implementan filtros cuckoo. > En principio no me sirven porque están escritos en Python nativo sin > prestar atención al uso de memoria y porque no tolero falsos positivos. > > Dado que tengo los datos ya ordenados en la entrada, una opción evidente > sería usar MMAP para verlos en memoria y hacer búsquedas mediante > bisección. Esto sería óptimo en consumo de memoria, pero teniendo grupos > de 8 megabytes, estaría tocando unos 11 bloques de 4096 bytes por cada > comprobación de pertenencia. Aún suponiendo que los bloques más > "calientes" estén cacheados en RAM, es preferible que el almacenamiento > nativo sea un chuckoo hash, que nos garantiza un máximo de acceso a dos > bloques de 4096 bytes. > > Usar un "set()" nativo de Python me garantiza un acceso típico de uno o > dos bloques de 4096 bytes (bien) pero la ocupación en memoria es > importante: entre dos y tres veces el tamaño de los datos originales. > > ¿Alguna sugerencia?. > > Gracias por vuestras neuronas :-). > > Cuckoo hashing: https://en.wikipedia.org/wiki/Cuckoo_hashing > > Cuento con programar el algoritmo en C o en Cython, si no encuentro nada > hecho. > > -- > Jesús Cea Avión _/_/ _/_/_/_/_/_/ > j...@jcea.es - http://www.jcea.es/ _/_/_/_/ _/_/_/_/ _/_/ > Twitter: @jcea_/_/_/_/ _/_/_/_/_/ > jabber / xmpp:j...@jabber.org _/_/ _/_/_/_/ _/_/ _/_/ > "Things are not so easy" _/_/ _/_/_/_/ _/_/_/_/ _/_/ > "My name is Dump, Core Dump" _/_/_/_/_/_/ _/_/ _/_/ > "El amor es poner tu felicidad en la felicidad de otro" - Leibniz > > > ___ > Python-es mailing list > Python-es@python.org > https://mail.python.org/mailman/listinfo/python-es > > -- Francesc Alted ___ Python-es mailing list Python-es@python.org https://mail.python.org/mailman/listinfo/python-es
[Python-es] ¿Propuesta de algoritmo o estructura de datos para conjuntos aleatorios con pocos cambios?
Requisitos: Tengo millones de bloques binarios de 256 bits. Estos millones de bloques están divididos aleatoriamente en grupos, digamos de un millón de elementos. Las operaciones básicas que debo soportar son: 1. Creación de un grupo. Una vez creado un grupo, no necesita ser actualizado. Ni para añadir ni para eliminar. 2. Comprobar si un elemento pertenece a un grupo concreto. 3. Generar un grupo nuevo como unión de dos o más grupos. 4. Generación de un grupo nuevo como intersección de dos o más grupos. 5. Iterar sobre un grupo. El orden no es importante. A nivel de limitaciones, la más importante es que la sobrecarga en memoria debe ser lo mínimo posible. Cada elemento ocupa 32 bytes (256 bits). La segunda más importante es que el algoritmo debe ser "cache friendly", sobre todo en la parte de búsqueda de pertenencia. En realidad solo necesito que el número de bloques de memoria de 4096 bytes que se revisan para buscar un elemento sea lo más bajo posible, porque el entorno de trabajo tiene muy poca memoria RAM pero se puede tirar de SWAP. No puedo tolerar falsos positivos, así que no puedo usar filtros bloom o filtros cuckoo. De momento la estructura de datos que va ganando son los hashes cuckoo: La ocupación de memoria es prácticamente óptima y solo requiere acceder a dos bloques de 4096 bytes. En cuanto a los datos en sí, son valores de 256 bits aleatorios. Ahora mismo los recibo en orden numérico, pero podría generar cualqueir otra estructura. Por ejemplo, podrían almacenarse directamente como un hash cuckoo para no tener que regenerarlos en tiempo de ejecución cada vez. Buscando en PYPI veo un par de proyectos que implementan filtros cuckoo. En principio no me sirven porque están escritos en Python nativo sin prestar atención al uso de memoria y porque no tolero falsos positivos. Dado que tengo los datos ya ordenados en la entrada, una opción evidente sería usar MMAP para verlos en memoria y hacer búsquedas mediante bisección. Esto sería óptimo en consumo de memoria, pero teniendo grupos de 8 megabytes, estaría tocando unos 11 bloques de 4096 bytes por cada comprobación de pertenencia. Aún suponiendo que los bloques más "calientes" estén cacheados en RAM, es preferible que el almacenamiento nativo sea un chuckoo hash, que nos garantiza un máximo de acceso a dos bloques de 4096 bytes. Usar un "set()" nativo de Python me garantiza un acceso típico de uno o dos bloques de 4096 bytes (bien) pero la ocupación en memoria es importante: entre dos y tres veces el tamaño de los datos originales. ¿Alguna sugerencia?. Gracias por vuestras neuronas :-). Cuckoo hashing: https://en.wikipedia.org/wiki/Cuckoo_hashing Cuento con programar el algoritmo en C o en Cython, si no encuentro nada hecho. -- Jesús Cea Avión _/_/ _/_/_/_/_/_/ j...@jcea.es - http://www.jcea.es/ _/_/_/_/ _/_/_/_/ _/_/ Twitter: @jcea_/_/_/_/ _/_/_/_/_/ jabber / xmpp:j...@jabber.org _/_/ _/_/_/_/ _/_/ _/_/ "Things are not so easy" _/_/ _/_/_/_/ _/_/_/_/ _/_/ "My name is Dump, Core Dump" _/_/_/_/_/_/ _/_/ _/_/ "El amor es poner tu felicidad en la felicidad de otro" - Leibniz signature.asc Description: OpenPGP digital signature ___ Python-es mailing list Python-es@python.org https://mail.python.org/mailman/listinfo/python-es