73
UNIVERSIDAD DE CHILE FACULTAD DE CIENCIAS FÍSICAS Y MATEMÁTICAS DEPARTAMENTO DE CIENCIAS DE LA COMPUTACIÓN PARALELIZACIÓN DE UN ALGORITMO PARA LA DETECCIÓN DE CÚMULOS DE GALAXIAS MEMORIA PARA OPTAR AL TÍTULO DE INGENIERO CIVIL EN COMPUTACIÓN MARCEL ANDRE AUGSBURGER BECERRA PROFESOR GUIA: NANCY HITSCHFELD KAHLER MIEMBROS DE LA COMISION: LUIS CAMPUSANO BROWN JORGE PÉREZ ROJAS SANTIAGO DE CHILE ENERO 2012

Paralelización de un Algoritmo para la Detección de Clusters de

  • Upload
    buibao

  • View
    217

  • Download
    2

Embed Size (px)

Citation preview

Page 1: Paralelización de un Algoritmo para la Detección de Clusters de

UNIVERSIDAD DE CHILE FACULTAD DE CIENCIAS FÍSICAS Y MATEMÁTICAS DEPARTAMENTO DE CIENCIAS DE LA COMPUTACIÓN

PARALELIZACIÓN DE UN ALGORITMO PARA LA DETECCIÓN DE CÚMULOS DE GALAXIAS

MEMORIA PARA OPTAR AL TÍTULO DE INGENIERO CIVIL EN COMPUTACIÓN

MARCEL ANDRE AUGSBURGER BECERRA

PROFESOR GUIA:

NANCY HITSCHFELD KAHLER

MIEMBROS DE LA COMISION: LUIS CAMPUSANO BROWN

JORGE PÉREZ ROJAS

SANTIAGO DE CHILE ENERO 2012

Page 2: Paralelización de un Algoritmo para la Detección de Clusters de

2

Tabla de contenido

Resumen ......................................................................................................................................................... 4

1. Introducción ........................................................................................................................................... 5

1.1. La nueva astronomía ...................................................................................................................... 5

1.2. La computación paralela ................................................................................................................ 6

1.3. Motivación ..................................................................................................................................... 7

1.3.1. Importancia del análisis de cúmulos de galaxias ................................................................... 7

1.3.2. Importancia del análisis paralelo ........................................................................................... 7

1.3.3. Otras aplicaciones del software ............................................................................................. 8

1.4. Objetivos ........................................................................................................................................ 8

1.5. Contenido de la memoria ............................................................................................................... 9

2. Antecedentes .......................................................................................................................................10

2.1. Tipos de paralelismo ....................................................................................................................10

2.2. Herramientas ................................................................................................................................12

2.3. Algoritmo secuencial de detección de cúmulos de galaxias ........................................................14

3. Análisis ..................................................................................................................................................17

Arquitectura de ................................................................................................................................17

3.1. Hadoop .........................................................................................................................................17

3.1.1. Distribución de datos ...........................................................................................................18

3.1.2. Procesamiento de datos .......................................................................................................19

3.1.3. Escalabilidad .........................................................................................................................21

3.1.4. HDFS .....................................................................................................................................21

3.1.5. MapReduce ..........................................................................................................................24

3.2. Arquitectura de Vocludet .............................................................................................................26

3.3. Versión disponible de Vocludet ...................................................................................................29

3.4. Alternativas de implementación ..................................................................................................32

Page 3: Paralelización de un Algoritmo para la Detección de Clusters de

3

3.4.1. MapReduce de Hadoop ........................................................................................................32

3.4.2. Pig .........................................................................................................................................32

3.4.3. Streaming .............................................................................................................................33

3.5. Alternativa escogida .....................................................................................................................34

4. Diseño e Implementación ....................................................................................................................35

4.1. Diseño de la solución ....................................................................................................................35

4.1.1. División de los datos .............................................................................................................36

4.1.2. Procesamiento de los datos .................................................................................................39

4.1.3. Re ensamblaje de los resultados ..........................................................................................40

4.1.4. Diseño final ...........................................................................................................................41

4.2. Código Implementado ..................................................................................................................43

5. Evaluación ............................................................................................................................................52

5.1. Datos de prueba ...........................................................................................................................52

5.2. Pruebas .........................................................................................................................................54

5.2.1. Particiones ............................................................................................................................54

5.2.2. Ensamblaje ...........................................................................................................................54

5.2.3. Verificación de datos y procedimientos ...............................................................................57

5.3. Desempeño ..................................................................................................................................60

5.3.1. Uso de recursos ....................................................................................................................60

5.3.2. Desempeño comparativo .....................................................................................................61

6. Conclusiones.........................................................................................................................................65

7. Anexos ..................................................................................................................................................66

Tabla 3: Distribución de cúmulos por tamaño .........................................................................................66

Mapper Function 2 celdas 10% de overlap ..............................................................................................67

Re Assembly Function ..............................................................................................................................70

8. Bibliografía ...........................................................................................................................................72

Page 4: Paralelización de un Algoritmo para la Detección de Clusters de

4

Resumen

Dados los avances en la tecnología, la astronomía es capaz de recolectar del orden de terabytes de datos

por noche. El análisis manual de ésta es prácticamente imposible, por lo que es constante la necesidad

de nuevos y mejores algoritmos para realizar análisis automático. Por otro lado, la computación paralela

provee herramientas para realizar análisis de datos masivos, las que incrementan la capacidad total de

procesamiento y disminuyen el tiempo requerido.

Existe un software para la búsqueda de cúmulos de galaxias, el cual funciona de forma secuencial. Hacer

que este software funcione en forma paralela sería de gran utilidad, dada la cantidad de datos que

existen y existirán para analizar. El objetivo de esta memoria es diseñar e implementar una solución

computacional que permita efectuar la detección de cúmulos de galaxias en forma paralela.

La paralelización del algoritmo se hizo sobre el framework Hadoop, utilizando la herramienta Streaming

con el lenguaje Python para el desarrollo del software. Se construyó una aplicación que divide los datos

de entrada de forma inteligente, ejecuta el algoritmo de detección de cúmulos de galaxias en varias

máquinas de forma paralela, y re ensambla los resultados parciales obtenidos. Se estudiaron estrategias

para el particionamiento de los datos, utilizando celdas con distintas geometrías. También se estudiaron

e implementaron estrategias para el re ensamblado de los resultados. En base a conocimientos

astronómicos y experimentación se determinó la utilidad, dado el contexto, de cada estrategia, y los

valores límites para sus parámetros.

Los resultados son los siguientes: (1) un software paralelo para la detección de cúmulos de galaxias; (2) al

correr el programa paralelo con dos particiones, el tiempo de ejecución se reduce a la mitad; (3) el

software secuencial de detección de cúmulos se observa altamente dependiente de las particiones

utilizadas, encontrándose para una partición de 2 celdas sólo un 11% de los cúmulos que se detectaban

en la versión secuencial.

Como trabajo futuro se propone: (1) modificar el software secuencial de búsqueda de cúmulos de

galaxias para que detecte cúmulos sin miembros repetidos; (2) ejecutar este software en un clúster de

computadores o con cloud computing, para medir las mejoras en tiempo; (3) la ejecución de este

software con sets de datos más grandes, para medir la escalabilidad de éste; (4) crear una partición ad-

hoc al set de datos.

Page 5: Paralelización de un Algoritmo para la Detección de Clusters de

5

1. Introducción

Desde la antigüedad, diferentes culturas y personas han creado catálogos de estrellas. Al principio se

hacían observaciones a ojo desnudo, hasta que en 1610 Galileo Galilei apuntó su telescopio al cielo. Al

irse mejorando las capacidades de los telescopios, la cantidad de información astronómica y por ende los

catálogos estelares fueron creciendo en gran escala. Hoy en día las herramientas de observación

permiten escanear el cielo y guardar los datos de manera automática, generando terabytes de

información sólo de pequeñas áreas del cielo.

Al haber tanta información, el análisis manual de ésta es prácticamente imposible, por lo que es

constante la necesidad de nuevos y mejores algoritmos computacionales para realizar análisis

automático. A pesar de ser mucho más eficiente, la gran cantidad de datos hace que el análisis

computacional requiera de mucho tiempo de procesamiento. La computación paralela puede disminuir

los costos en tiempo, ya que permite aumentar los recursos asignados a cada tarea.

La computación paralela divide un problema en varios sub problemas, los que son resueltos de manera

concurrente. De tal manera se puede resolver cada sub problema con distintos recursos, pudiendo

distribuir la carga en equipos que pueden estar separados físicamente. Sin embargo, los programas

paralelos agregan dificultad en los procesos de división del problema, en la concurrencia, y en el re

ensamblado de la solución completa a partir de las soluciones parciales.

Existe un software desarrollado por Daniel Pizarro et al, el cual aplica un algoritmo basado en el Voronoi

Tessellation Technique (1) para la detección de cúmulos de galaxias. Este software lleva por nombre

Vocludet. Uno de los componentes del Vocludet es el Voronoi Tessellation Maximum Likelihood

Estimator, en adelante VTMLE, el cual lleva a cabo el proceso de búsqueda de cúmulos (2). Este software

funciona de manera secuencial.

1.1. La nueva astronomía

Gracias a los avances en la tecnología de los telescopios, algoritmos de detección, y hardware

computacional, la recolección de datos astronómicos es actualmente del orden de terabytes por noche

(4). Este incremento en la obtención de datos ha ocurrido en muchas áreas de la ciencia, cambiando la

forma en que se hace la investigación y transformándola en análisis de datos sobre bases de datos con

mucha información. En el área de la astronomía se habla del Observatorio Virtual, donde se puede

acceder a la información de distintos centros de datos de manera relativamente fácil y transparente. Se

Page 6: Paralelización de un Algoritmo para la Detección de Clusters de

6

están aportando datos y relacionándolos entre sí a tasas cada vez mayores, lo cual ha tornado la

obtención de datos por este medio en algo tan importante como la obtención de datos a través de

telescopios.

En los últimos años se han puesto a disposición resultados de numerosos estudios con distintos tipos de

información astronómica. En particular existen datos e interés en la estructura a gran escala del

universo, donde han jugado un rol importante las observaciones de cúmulos de galaxias, al servir para

contrastarlas con las predicciones de diferentes modelos teóricos.

Los cúmulos de galaxias, mencionados previamente, son sistemas que contienen desde 50 a 1000

galaxias unidas por atracción gravitacional mutua; las galaxias son sistemas de estrellas, las cuales

poseen típicamente cientos de miles de millones de estrellas. Estos cúmulos han sido detectados

históricamente en forma visual, y recientemente se han aplicado algoritmos para la detección

automática de éstos.

El sondeo 2dF Galaxy Redshift Survey (2dFGRS), llevado a cabo por el Observatorio Anglo-Australiano

entre 1997 y 2002, generó variados tipos de información respecto a galaxias, incluyendo su distribución

al determinar su posición en tres dimensiones (5). La estimación de distancias es posible gracias a la

información del corrimiento al rojo, que es el aumento de la longitud de onda equivalente al Efecto

Doppler en las ondas físicas.

1.2. La computación paralela

La computación paralela es la utilización simultánea de múltiples recursos de computación para resolver

problemas computacionales.

Tradicionalmente, el software ha sido escrito para ser ejecutado en forma secuencial. Esto significa que

para resolver un problema, el algoritmo que se implementa debe ser escrito como una secuencia de

instrucciones. Como restricción se tiene que estas instrucciones deben ser ejecutadas una a la vez, y

solamente en el orden especificado por el algoritmo. Cada una de estas instrucciones es ejecutada por

una CPU (Central Processing Unit). El tiempo que demora la resolución del problema depende de la

eficiencia del algoritmo y de la rapidez con la que la CPU realiza los cálculos, haciendo que este último

factor haya sido y siga siendo sujeto de estudio.

Page 7: Paralelización de un Algoritmo para la Detección de Clusters de

7

Por décadas, la velocidad de procesamiento de los computadores ha ido incrementando según la Ley de

Moore, esto es, duplicándose cada aproximadamente dos años (6). Este incremento se ha debido en

gran medida al aumento de la frecuencia de reloj de los procesadores, sin embargo se está llegando a un

límite conocido como power wall, debido al consumo exponencial de energía con el aumento en la

frecuencia de operaciones, y el consiguiente aumento de temperatura. Existen también cuellos de

botella como la rapidez de acceso a la memoria, por lo que el desarrollo de procesadores más rápidos

no necesariamente va a significar un incremento en la eficiencia final de los computadores.

En la búsqueda de cómo continuar incrementando la capacidad de procesamiento, y tomando en cuenta

otros factores limitantes, se ha considerado el paralelismo como buena solución. La computación

paralela se ha usado históricamente, mostrando buenos resultados en distintas áreas, como en

computación de alto rendimiento, servidores, aceleración gráfica, y muchos sistemas embebidos (7). Así

podemos encontrar actualmente diseños de procesadores con múltiples núcleos, los cuales permiten

realizar varios cálculos por ciclo, para computadores multipropósito.

1.3. Motivación

Existe un software para la búsqueda de cúmulos de galaxias, el cual funciona de forma secuencial. Hacer

que este software funcione en forma paralela es de gran utilidad, dada la cantidad de datos que existen y

existirán a futuro para analizar.

1.3.1. Importancia del análisis de cúmulos de galaxias

Los cúmulos de galaxias son de gran interés para la astronomía. En las últimas décadas han tenido un

importante rol en el estudio cosmológico: sirven para reconocer las estructuras en gran escala del

universo, su densidad numérica se puede contrastar con predicciones de distintos modelos, y además

sirven para monitorear la formación y evolución de las galaxias (9).

1.3.2. Importancia del análisis paralelo

Como se mencionó, hoy se cuenta con un observatorio virtual con grandes cantidades de datos. Futuros

sondeos prometen aumentar el volumen de datos en órdenes de magnitud, produciendo una llamada

“avalancha de datos astronómicos”.

Page 8: Paralelización de un Algoritmo para la Detección de Clusters de

8

La ciencia en general ha logrado producir más datos de los que se pueden analizar, y dada esta

problemática, es de gran importancia primero lograr el análisis automático de los datos, e

inmediatamente lograr paralelizarlo para aminorar los tiempos de procesamiento. Lo relevante de esta

tarea para la astronomía, la aplicabilidad en otras ramas de la ciencia, y la conocida dificultad de

paralelizar procesos, hacen de éste un tema interesante como memoria.

1.3.3. Otras aplicaciones del software

El análisis de cúmulos es un problema recurrente en varias áreas, entre éstas el aprendizaje automático,

reconocimiento de patrones, análisis de imágenes, recuperación de la información y bioinformática.

Dado que el software desarrollado se creó de manera flexible, éste puede ser usado no sólo en el análisis

de datos astronómicos, sino que también en cualquiera de las áreas recién mencionadas. Si bien la

aplicación secuencial ya lo permitía, el desarrollo de este análisis en paralelo abre las puertas al

procesamiento de órdenes de magnitud mayor de datos, pudiéndose atacar problemas que de otra

manera hubiese sido imposible.

1.4. Objetivos

El objetivo general es diseñar e implementar una solución computacional que permita detectar cúmulos

de galaxias en forma paralela, utilizando un framework que permita distribuir la carga de procesamiento.

Los objetivos específicos son:

Construir una aplicación utilizando el framework Hadoop para llevar a cabo el análisis de datos

en forma paralela. Lo anterior considera el diseño e implementación de un programa que realice

una buena partición de los datos, resuelva el problema sobre cada partición, y calcule la solución

completa re ensamblando los resultados parciales.

Evaluar si se efectúa una mejora a la solución existente, lo que implica comparar la aplicación

secuencial y la aplicación paralela en término de tiempos y consumo de recursos.

Determinar las diferencias y similitudes entre los resultados obtenidos por el programa

secuencial y el paralelo .

Page 9: Paralelización de un Algoritmo para la Detección de Clusters de

9

1.5. Contenido de la memoria

En la sección 2 se presentan las tecnologías disponibles y el algoritmo que se quiere paralelizar. En la

sección 3 se analizan las herramientas con las que se cuenta para el desarrollo del software, se comparan

las diferentes alternativas y su estado, y se decide cuáles se van a utilizar y de qué forma. En la sección 4

se presentan las decisiones que se consideraron para el diseño del software, se propone un diseño final,

y se muestra y explica el código implementado. En la sección 5 se presentan los experimentos realizados

para probar el software y determinar su eficacia y eficiencia. Se incluye una descripción de los datos de

prueba, las pruebas mismas, y el desempeño del software. Finalmente, en la sección 6 se presentan las

conclusiones a las que se llegó con este trabajo, según los objetivos que se habían planteado, y se

proponen acciones para continuarlo a futuro.

Page 10: Paralelización de un Algoritmo para la Detección de Clusters de

10

2. Antecedentes

En este capítulo se presentan los antecedentes del problema, tales como las tecnologías disponibles y el

algoritmo que se quiere paralelizar.

2.1. Tipos de paralelismo

La computación paralela se puede llevar a cabo en varios niveles, desde la cantidad de bits que se

pueden procesar por ciclo, la cantidad de instrucciones que se pueden procesar en forma paralela, la

paralelización en procesamiento de datos, hasta la paralelización de tareas. De todos modos, sólo se

pueden realizar ciertos cálculos en paralelo: algunos deben ser secuenciales pues dependen de

resultados obtenidos por cálculos previos. Se puede hacer una clasificación de los computadores que

trabajan en forma paralela según el nivel al cual el hardware provee el paralelismo. Para el paralelismo a

nivel de núcleos de procesamiento, esta clasificación es a grandes rasgos análoga a la distancia entre los

nodos básicos de computación, y no son mutuamente excluyentes.

Computación Multinúcleo: Un procesador multinúcleo es aquel que posee múltiples unidades de

ejecución (núcleos) en el mismo chip. Estos procesadores tienen la capacidad de ejecutar

múltiples instrucciones por ciclo, provenientes de múltiples flujos de instrucciones.

Multiprocesamiento Simétrico: Un multiprocesador simétrico es un computador que posee

múltiples procesadores idénticos, los cuales comparten el acceso a la memoria a través de un

único bus de datos. Esto permite asignar más de un procesador a una o varias tareas. Dado el

diseño del acceso a datos, los multiprocesadores simétricos suelen no tener más de 32

procesadores.

Computación Distribuida: La computación distribuida es un modelo de computación donde se

usan múltiples computadores para la resolución de un problema. Estos se coordinan entre sí a

través de un sistema distribuido, definido como: una colección de computadores separados

físicamente y conectados entre sí por una red de comunicaciones distribuida, donde cada

máquina posee sus componentes de hardware y software que el usuario percibe como un solo

sistema. Se define como nodo a una unidad individual, típicamente una máquina, dentro de un

sistema distribuido.

El framework utilizado en el presente trabajo se construyó para que pudiese ser utilizado por cualquiera

de las tres clases de computación paralela, abstrayéndose de este nivel y funcionando indiferente a la

Page 11: Paralelización de un Algoritmo para la Detección de Clusters de

11

clase de paralelismo y cantidad de núcleos utilizados. Sin embargo, presta su verdadera contribución al

ser aplicada con computación distribuida, al crecer la capacidad de procesamiento de datos en paralelo

en órdenes de magnitud. Para la cantidad de datos que genera la ciencia, y la astronomía en particular,

se hace necesario que el procesamiento de información se haga con computación distribuida.

La computación a gran escala presenta un gran número de dificultades. La mayoría de éstas derivan de la

coordinación entre múltiples máquinas para la solución de un problema, y las consiguientes fallas que se

pueden presentar, tanto de comunicación, como de los nodos en sí. En un ambiente distribuido, las fallas

parciales son esperadas e incluso comunes: las redes pueden experimentar variados tipos de problemas

derivados de fallas físicas o de congestión, los cuales impiden que los datos lleguen a destino en el

momento que debían; los nodos pueden dejar de funcionar debido a problemas de hardware, software,

o de capacidad; los datos pueden estar corrompidos por causas en la generación, transmisión o por

ataques maliciosos; puede haber diferencias en el protocolo de transmisión de diferentes versiones del

software; los relojes pueden desincronizarse; pueden ocurrir problemas de sincronización en el acceso a

datos; etc. El resto del sistema distribuido debiese ser capaz de recuperarse en forma independiente del

elemento fallido, para cada uno de los casos posibles de falla (8).

Además de los problemas asociados con fallas en la red o en los nodos, también existe el problema de

que los nodos poseen hardware con capacidad finita. Los elementos más importantes para estos efectos

son el tiempo de procesador, la memoria, el espacio en disco y el ancho de banda de la red. Cada nodo

tiene por lo general algunos gigabytes de memoria, lo que implica que si el set de datos es de algunos

terabytes, se necesitarían del orden de miles de nodos para guardar la información en RAM. Los discos

duros proveen un espacio de almacenamiento mucho mayor, que pueden ser del orden de terabytes. Sin

embargo, los sets de datos que se generan al procesar la información pueden llegar a ocupar mucho más

espacio que el input original, lo que podría llevar a sobrepasar la capacidad de almacenamiento de un

nodo y recurrir a la de otro. El ancho de banda es un recurso escaso incluso en una red interna, y mucho

más si los nodos están separados por medianas o grandes distancias. Es fácil que se saturen las redes al

haber grandes cantidades de datos siendo transferidos, y que por ello se pierdan datos o no lleguen en el

momento requerido.

Un sistema distribuido de gran escala debe poder manejar los recursos previamente mencionados en

forma eficiente, buscando un equilibrio entre el funcionamiento del sistema en forma íntegra y el

procesamiento de datos.

Page 12: Paralelización de un Algoritmo para la Detección de Clusters de

12

El desafío más grande en el diseño de sistemas distribuidos es la sincronización entre los nodos. Si éstos

tienen la capacidad de comunicarse entre sí de manera explícita, se enfrentan riesgos como producir

más llamados a procedimientos remotos de los que soporta el sistema, bloqueos mutuos sobre los datos

y otras condiciones de carrera. Además está la complejidad de diseñar un sistema que sea capaz de

recuperarse ante el fallo de un nodo, con poca pérdida de recursos y redistribuyendo la carga de manera

eficiente en el resto del sistema.

2.2. Herramientas

La programación funcional utiliza frecuentemente las funciones map y reduce, las que sirvieron como

base para que Google creara el framework MapReduce (10). Este modelo de programación tiene la

ventaja de proveer automáticamente paralelización y distribución, además de ser tolerante a fallas. Éste

fue utilizado por el framework Apache Hadoop, el cual permite crear programas paralelos.

Map-reduce trabaja con pares de key/values (llave/valores): la función map recibe uno de estos pares, lo

procesa y genera un set de pares intermedios; la función reduce procesa los pares intermedios para

generar uno o varios valores finales. Esto se ve ilustrado en el siguiente ejemplo, donde se cuentan las

palabras de un texto:

int resultado=0

La función map recibe un texto, valorEntrada, y emite un par por cada palabra, donde el key es la

palabra y el value es 1. En este programa en particular no se utiliza el primer parámetro recibido,

llaveEntrada. La función reduce recibe entonces un key, llaveIntermedia, y una lista con el valor 1

repetido tantas veces como apariciones del key haya habido en el texto original, valoresIntermedios, y

emite la suma de los valores de la lista.

Page 13: Paralelización de un Algoritmo para la Detección de Clusters de

13

Tanto la función map como reduce se pueden ejecutar en forma paralela. Los datos de entrada se

pueden distribuir en tantos map como se estime conveniente, usualmente la misma cantidad que el

número de procesadores disponibles. Luego se crean tantas funciones reduce como keys hayan, las

cuales son procesadas en forma paralela por los procesadores que se asignen.

El software se instaló y configuró en varios modos para evaluar la ejecución. También se investigaron

herramientas disponibles y se escribieron programas básicos para evaluar la complejidad de desarrollar

con este framework. También se buscó información para determinar si el framework es capaz de

manejar la gran cantidad de datos que se requiere en la búsqueda de cúmulos de galaxias. Según los

creadores, éste es capaz de manejar del orden de petabytes, lo cual es más que suficiente considerando

que la cantidad de datos astronómicos que se quieren procesar es de alrededor de 6 terabytes. Además,

ya se ha utilizado en el procesamiento de imágenes astronómicas en universidades como la Washington

University (11).

Respecto a dónde y cómo se debería ejecutar el software desarrollado para procesar la información: el

framework está pensado para ser usado con cualquier cantidad de recursos, pero en particular funciona

bien con cloud computing. El modelo de programación map-reduce tiene la ventaja de que la

escalabilidad es directa, por lo que no es necesario esfuerzo alguno para ejecutarlo en una cantidad

mayor de máquinas. Al utilizar cloud computing se pueden arrendar un número variable de recursos, por

lo que se puede reducir el tiempo de procesamiento de forma proporcional a la cantidad de

procesadores que se arrienden. En caso de aumentar la cantidad de datos a procesar, se pueden

arrendar más recursos, pudiendo mantenerse el tiempo de procesamiento relativamente independiente

de la cantidad de datos de entrada. Además existen proyectos de grandes compañías como The New

York Times y famosas universidades como Stanford, que se han llevado a cabo con Apache Hadoop sobre

la plataforma Amazon Elastic Compute Cloud (12).

Haciendo una breve comparación con otros sistemas de computación paralela sobre grandes volúmenes

de datos, existen otras alternativas como Condor, pero ésta no distribuye los datos automáticamente

como Apache Hadoop. Esto significa que el control de datos se debe realizar de forma manual, y que la

colaboración entre nodos se debe programar con sistemas de comunicación como MPI, lo cual conlleva

un gran esfuerzo y aumenta la probabilidad de errores. Esto no es necesario en Apache Hadoop, pues

son tareas automatizadas que constituyen parte del framework, y de las cuales el programador se puede

abstraer. Si bien la eficiencia puede ser menor que al computarlo con otros sistemas, la ganancia en

Page 14: Paralelización de un Algoritmo para la Detección de Clusters de

14

facilidad para el programador, la escalabilidad directa, y los bajos costos de cloud computing hacen de

este framework una buena opción para el proyecto.

2.3. Algoritmo secuencial de detección de cúmulos de galaxias

Daniel Pizarro desarrolló un software llamado Vocludet para la detección de cúmulos de galaxias (2). Éste

consta de dos partes, el algoritmo VTMLE y el DePropris, siendo el primero utilizado para la detección de

cúmulos de galaxias.

El algoritmo VTMLE recibe como entrada un set de puntos en un espacio de tres dimensiones, donde

cada punto representa las coordenadas de una galaxia que hay en el espacio que se quiere analizar. Con

esta información se calcula el diagrama de Voronoi que se construye a partir de los puntos, el cual

entrega una estimación de la densidad local de galaxias para cada punto del set. Se itera sobre los datos

de entrada para encontrar posibles cúmulos de galaxias, lo que consta de las siguientes fases:

Detección de semilla: Para esto se busca el área de mayor densidad de galaxias, lo que equivale a

buscar la celda de menor volumen en el diagrama. Se debe verificar que la semilla encontrada no

sea parte de un cúmulo encontrado en una iteración previa.

Detección de miembros del cúmulo (Algoritmo 1): Partiendo con la semilla como cúmulo base, se

trata de aumentar el valor resultante de una función de probabilidad, el Estimador de Máxima

Verosimilitud (EMV), agregando los puntos vecinos al cúmulo. Este proceso se lleva a cabo hasta

que una de las siguientes dos condiciones deja de cumplirse:

o No se puede incrementar el EMV del conjunto al agregar alguno de sus vecinos. En este

caso se encontró un cúmulo y se guardan los datos.

o El elemento agregado forma parte de otro cúmulo. En este caso se descarta la semilla

que originó este cúmulo.

El algoritmo recibe el diagrama de Voronoi previamente calculado con la herramienta Qhull. Este

software es capaz de generar el diagramas de Voronoi en varias dimensiones. En particular sirve para

generar el diagrama de Voronoi en tres dimensiones.

A continuación, se presenta el pseudocódigo del algoritmo para el caso de la búsqueda de un cúmulo:

Page 15: Paralelización de un Algoritmo para la Detección de Clusters de

15

Algoritmo 1: Algoritmo VTMLE

Este pseudocódigo debe enmarcarse dentro del algoritmo general, que busca todos los cúmulos de

galaxias en una zona del espacio. En éste se deben hacer la búsqueda de la semilla y el conteo de las

celdas usadas y cúmulos de galaxias encontrados, e invocar al algoritmo de búsqueda individual para

encontrar posibles cúmulos de galaxias a partir de cada semilla.

Se presenta el pseudocódigo del algoritmo general a continuación:

Page 16: Paralelización de un Algoritmo para la Detección de Clusters de

16

Algoritmo 2: Algoritmo de detección de cúmulos

Page 17: Paralelización de un Algoritmo para la Detección de Clusters de

17

3. Análisis

En este capítulo se analizan las herramientas con las que se cuenta para el desarrollo del software, se

comparan las diferentes alternativas y su estado, y se decide cuáles se van a utilizar de qué forma.

3.1. Arquitectura de Hadoop

Hadoop es un framework que permite procesar datos usando el modelo de programación map-reduce.

Está diseñado para procesar grandes volúmenes de información de manera eficiente a través de

computación distribuida, conectando computadores y coordinándolos para trabajar juntos en paralelo.

Permite trabajar con diferentes cantidades de nodos, permitiendo escalabilidad desde un servidor hasta

miles de máquinas, cada una con capacidad de computación y almacenamiento locales. El sistema está

diseñado para detectar y manejar fallas en el nivel de aplicación. Esto permite despreocuparse de contar

con hardware de alta disponibilidad, ya que el sistema es capaz de soportar y manejar fallas en

cualquiera de los nodos del cluster.

Si bien existen otros sistemas que realizan procesamiento de grandes volúmenes de datos en sistemas

distribuidos, Hadoop tiene la ventaja de proveer un modelo de programación simple, el cual permite

escribir y testear sistemas distribuidos de forma rápida. Además provee un sistema eficiente de

distribución automática de datos y trabajo en el conjunto de nodos, y también dentro de cada nodo con

sus respectivos núcleos.

El framework está constituido por las siguientes componentes, que en su totalidad permiten la creación

y ejecución de programas distribuidos y en forma paralela:

Hadoop Common: Un set de herramientas que sirven de base para otros componentes y

proyectos de Hadoop. Esto incluye el sistema de archivos básico, manejo de llamadas a

procedimientos remotos, y bibliotecas de serialización.

Hadoop Distributed File System (HDFS): Un sistema de archivos distribuido, que provee un rápido

acceso y alto flujo de datos. Es el sistema primario de almacenamiento de datos usado por las

aplicaciones de Hadoop, el cual replica los bloques de datos y los distribuye en nodos del cluster.

Es esta distribución y redundancia la que permite el acceso rápido y la tolerancia a fallos en los

nodos del cluster.

Page 18: Paralelización de un Algoritmo para la Detección de Clusters de

18

Hadoop MapReduce: Un framework de software para el procesamiento distribuido de grandes

cantidades de datos en clusters de computadores. Éste provee un modelo de programación que

permite crear aplicaciones que procesan datos en forma paralela.

Existen también proyectos que extienden las capacidades de Hadoop, agregando funcionalidades o

usándolo como base para realizar tareas de más alto nivel. Entre éstos destacan lenguajes de alto nivel

que facilitan el acceso y procesamiento de datos.

3.1.1. Distribución de datos

En un cluster de Hadoop, los datos se distribuyen a todos los nodos a medida que éstos se van cargando

en el sistema, como muestra la Figura 1. El HDFS se encarga de particionar los datos y distribuirlos en

forma redundante, de tal manera que cada conjunto de datos se encuentre replicado en más de un

nodo. Esto evita pérdida o inaccesibilidad a cualquier conjunto de datos, en caso de presentarse fallas en

algún nodo o en las redes. Un sistema de monitoreo activo se encarga de replicar los datos en respuesta

a fallas en el sistema. A pesar de su distribución en varios nodos, los conjuntos de datos forman parte del

mismo espacio de nombres, por lo que son fácil y completamente accesibles.

Al cargar la información al sistema, cada archivo se divide en líneas, o en algún otro formato específico

para la lógica del programa en particular. A esto se le llama orientación a registros, donde cada registro

es una línea o su símil. Cada proceso que esté corriendo en cada nodo procesa un subconjunto de estos

registros, siendo el framework quien organiza los datos que se procesan, según la proximidad que éstos

tengan a los datos. De esta forma, la mayoría de los datos son leídos directamente desde el disco duro

local, aliviando la carga en las redes y evitando transferencias innecesarias. La estrategia utilizada para la

organización tareas consiste en mover la capacidad de computación hacia los datos, en vez de mover los

datos. Esto se traduce en una alta localización de los datos, que a su vez resulta en un alto desempeño.

Page 19: Paralelización de un Algoritmo para la Detección de Clusters de

19

Figura 1: Distribución de datos en Hadoop

3.1.2. Procesamiento de datos

Hadoop limita la cantidad de comunicación que puede ocurrir entre los procesos, ya que cada registro es

procesado por una tarea aislada del resto. Aunque esto suena como una gran limitación en un principio,

hace que el framework sea mucho más confiable. Hadoop no está diseñado para ejecutar cualquier

programa y distribuirlo en un cluster, sino que los programas deben estar escritos en acuerdo a un

modelo de programación en particular, llamado MapReduce.

En MapReduce, los registros son procesados de forma aislada por tareas llamadas mappers, las que

suelen utilizarse para clasificar datos. En caso de ser necesario, un proceso llamado shuffle toma los

resultados obtenidos por todos los mappers, y los agrupa según estas clasificaciones. Finalmente los

datos son procesados por tareas llamadas reducers, donde cada una recibe datos pertenecientes a una o

más clasificaciones, y las procesa. La Figura 2 muestra el proceso recién descrito.

Page 20: Paralelización de un Algoritmo para la Detección de Clusters de

20

Figura 2: Procesos de map y reduce en Hadoop

Los nodos de un cluster de Hadoop se comunican entre sí, pero a diferencia de otros sistemas

distribuidos, donde los desarrolladores de la aplicación ordenan explícitamente los flujos de datos de

nodo a nodo a través de buffers MPI, la comunicación en Hadoop se lleva a cabo de forma implícita. Los

subconjuntos de datos pueden ser etiquetados, lo que es utilizado por Hadoop para saber cómo enviar la

información a un nodo destinatario común. Hadoop maneja internamente todas las transferencias de

datos y los asuntos referentes a la topología del cluster.

Al restringir la comunicación entre los nodos, Hadoop hace que el sistema distribuido sea mucho más

confiable. Las fallas individuales en los nodos pueden solucionarse reiniciando las tareas en otras

máquinas. Dado que las tareas a nivel de usuario no se comunican explícitamente entre sí, no es

necesario un intercambio de mensajes en los programas de usuario, ni tampoco definir puntos de

retorno para retomar la ejecución en caso de fallas. Ante la falla en un nodo, el resto de los nodos

continúan operando como si nada hubiese pasado, dejando las complicaciones del reinicio parcial del

programa a la capa subyacente de Hadoop.

Page 21: Paralelización de un Algoritmo para la Detección de Clusters de

21

3.1.3. Escalabilidad

Una de los grandes beneficios de Hadoop en comparación a otros sistemas distribuidos, es su curva

plana de escalabilidad. El rendimiento de Hadoop puede no ser espectacular si es que se ejecuta con

pocos datos bajo un pequeño número de nodos, ya que el sobrecosto asociado a iniciar programas de

Hadoop es relativamente alto. Otros paradigmas de programación paralelos o distribuidos como MPI

(Message Passing Interface) pueden presentar un mejor desempeño al ejecutarse con menos de diez

máquinas. Aunque el esfuerzo de coordinación entre un pequeño número de máquinas puede ser mejor

llevado por tales tipos de sistemas, el costo que se paga en rendimiento y esfuerzo por parte de los

ingenieros al añadir más hardware como resultado del incremento en el volumen de datos, crece de

forma no lineal.

Un programa escrito en otros frameworks distribuidos, pueden requerir grandes cantidades de

refactorización al escalar de diez a cien o a mil máquinas. Esto puede requerir que el programa se

reescriba varias veces; elementos fundamentales de su diseño pueden también poner un tope a la escala

de crecimiento de la aplicación.

Hadoop, en contraste, está específicamente diseñado para tener una curva de escalabilidad muy plana.

Luego de que un programa en Hadoop está escrito y funcionando en diez nodos, muy poco o nulo

trabajo es requerido para correr el mismo programa sobre una cantidad mucho mayor de hardware. Se

requiere muy poco trabajo extra sobre una aplicación para poder crecer en órdenes de magnitud. La

plataforma de Hadoop subyacente maneja los recursos de datos y hardware, y provee un crecimiento en

el rendimiento dependiente, proporcional al número de máquinas disponibles.

3.1.4. HDFS

El sistema de archivos distribuidos de Hadoop, HDFS, es un sistema de archivos diseñado para guardar

grandes cantidades de datos (terabytes e incluso petabytes), y proveer acceso de alto flujo de datos a

esta información. Los archivos son almacenados de manera redundante a través de múltiples máquinas,

para asegurar su resistencia a fallas y su alta disponibilidad a aplicaciones altamente paralelas, tal como

se muestra en la Figura 3.

Page 22: Paralelización de un Algoritmo para la Detección de Clusters de

22

Figura 3: HDFS de Hadoop

Un sistema de archivos distribuido está diseñado para almacenar grandes cantidades de datos y proveer

acceso a estos datos a la mayor cantidad de clientes distribuidos a través de la red. Existen varios

sistemas de archivos distribuidos que resuelven este problema de diferentes maneras, como el NFS

(Network File System) de Linux.

HDFS está diseñado para ser robusto frente a un gran número de problemas a los que otros sistemas de

archivos distribuidos, como NFS son vulnerables. En particular:

El HDFS está diseñado para almacenar una gran cantidad de información (terabytes o petabytes).

Esto requiere distribuir los datos en un gran número de máquinas. También es capaz de manejar

tamaños de archivo mucho mayores a los que puede manejar NFS.

El HDFS almacena los datos de manera confiable. Si falla alguna máquina del cluster, los datos

deberían seguir estando disponibles.

El HDFS provee acceso rápido y escalable a esta información. Debiese ser posible proveer

servicios a un número mayor de clientes sólo agregando más máquinas al cluster.

El HDFS se integra bien con el Hadoop MapReduce, permitiendo que los datos sean leídos y

computados localmente cuando sea posible.

Page 23: Paralelización de un Algoritmo para la Detección de Clusters de

23

El HDFS, sin embargo, no es de propósito general, por lo que hay decisiones de diseño que lo hacen

óptimo para trabajar con Hadoop, pero no para otros fines. En particular:

Se asume que el diseño de las aplicaciones que usan HDFS realiza lecturas a los archivos de

forma secuencial y larga. El HDFS está optimizado para proveer lectura con altos flujos de datos.

Si bien esto es bueno para la mayoría de los casos de uso, tiene un sobrecosto al intentar

acceder a posiciones arbitrarias de un archivo, ya que se realiza una búsqueda secuencial que

toma un tiempo no determinado.

Dados los grandes tamaños de los archivos, y la naturaleza secuencial de las lecturas, el sistema

no provee un mecanismo para almacenamiento en caché de forma local. El sobrecosto del

almacenamiento en caché es suficientemente grande como para preferir que los datos

simplemente sean releídos desde la fuente HDFS.

Se asume que máquinas individuales van a fallar a una tasa relativamente frecuente, tanto de

manera intermitente como permanente. El clúster debe ser capaz de soportar la falla completa

de varias máquinas, posiblemente todas ocurriendo al mismo tiempo (por ejemplo si falla un

rack por completo). Aunque el rendimiento puede degradarse proporcionalmente al número de

máquinas que se hayan perdido, el sistema completo no debería ponerse demasiado lento, ni se

debería perder información. Las estrategias de replicación de datos combaten este problema.

El diseño del HDFS está basado en el diseño de GFS, el sistema de archivos de Google. Su diseño fue

descrito en un paper publicado por Google (14).

El HDFS es un sistema de archivos con estructura de bloques: cada archivo es dividido en bloques de un

tamaño determinado. Estos bloques son almacenados en el clúster en una o más máquinas con

capacidad de almacenamiento de datos. A estas máquinas se les llama DataNodes. Un archivo puede

estar compuesto por varios bloques, y éstos no están almacenados necesariamente en la misma

máquina. Así el acceso a un archivo puede requerir la cooperación de múltiples máquinas, pero es capaz

de manejar tamaños de archivo mucho más grandes; cada archivo puede requerir más espacio de lo que

es capaz de almacenar un solo disco duro.

Si varias máquinas deben estar involucradas para proveer acceso a un archivo, entonces un archivo

puede no estar disponible si se pierde acceso a alguna de estas máquinas. El HDFS resuelve este

problema replicando cada bloque en varias máquinas, 3 por defecto.

Page 24: Paralelización de un Algoritmo para la Detección de Clusters de

24

La mayoría de los sistemas de archivos con estructura de bloques usan un tamaño de bloque del orden

de 4 a 8 KB. En HDFS, el tamaño de bloque por defecto es de 64 MB, órdenes de magnitud más grande.

Esto permite que el HDFS disminuya la cantidad espacio requerido para almacenar metadatos por cada

archivo (las listas de bloques por archivo son menores a medida que el tamaño de los bloques

incrementa). La consecuencia de esta decisión es que el HDFS espera manejar archivos grandes, y espera

que ellos sean leídos de manera secuencial. Los metadatos son manejados por una única máquina,

llamada NameNode.

3.1.5. MapReduce

Hadoop implementa un paradigma computacional llamado map-reduce, el cual divide la aplicación en

fragmentos de trabajo. Cada uno de los fragmentos puede ser ejecutado o re ejecutado en cualquier

nodo del cluster. Un trabajo MapReduce divide el set de datos de entrada en trozos independientes, los

cuales son procesados por las tareas map en forma paralela. El framework clasifica el output de los

maps, los cuales son entonces entregados como input de las tareas “reduce”, que también son

ejecutadas de forma paralela. Típicamente, ambos el input y el output de cada trabajo son almacenados

en el sistema de archivos HDFS. El framework se hace cargo de la organización temporal, monitoreo y re

ejecución, en caso de fallo, de las tareas. Por lo general, los nodos de computación y de almacenamiento

son los mismos, es decir, el framework MapReduce y el HDFS son ejecutados en el mismos set de nodos.

El framework MapReduce consiste de un único JobTracker maestro, encargado de manejar el trabajo en

su totalidad, y un TaskTracker esclavo por nodo del cluster, encargados del manejo de las tareas

específicas asignadas a cada nodo del cluster. El maestro es responsable de la distribución espacial y

temporal de las tareas que componen un trabajo, asignando y luego monitoreando el estado de las

tareas en los esclavos. También se encarga de la re ejecución de las tareas fallidas.

Para ejecutar una tarea, se debe especificar la ubicación del input/output y proveer las funciones map y

reduce. Para que estas funciones sean válidas y puedan ejecutarse, deben implementar interfaces

apropiadas y/o clases abstractas. La ubicación del input/output, las funciones map y reduce, y otros

parámetros de los trabajos comprenden la configuración del trabajo. El JobClient de Hadoop entrega el

trabajo (jar, ejecutable u otros) y la configuaración al JobTracker. Éste asume la responsabilidad de

distribuir ambos a los esclavos, organizándolos temporalmente y monitoreándolos, además de

constantemente proveer la información de estado y diagnóstico al JobClient.

Page 25: Paralelización de un Algoritmo para la Detección de Clusters de

25

El framework MapReduce opera exclusivamente con pares key/values, es decir, el framework ve el input

del trabajo como un set de pares key/values y produce sets de pares key/values como output del

trabajo, posiblemente de tipos distintos. Las clases key y values deben ser serializables por el framework,

y por ende necesitan implementar la interfaz Writable.

Page 26: Paralelización de un Algoritmo para la Detección de Clusters de

26

3.2. Arquitectura de Vocludet

Vocludet (Voronoic based Cluster Detector) es un software desarrollado para el análisis de datos

astronómicos, en particular para la detección de cúmulos de galaxias. Éste fue desarrollado por Daniel

Pizarro para su tesis de magister en ciencias, mención computación (2). Está escrito principalmente en

Java, sin embargo hace llamados a programas en C y utiliza shell scripting para uno de sus módulos.

El input para la aplicación son datos provenientes de diferentes sets de datos, no necesariamente en el

mismo formato, y no necesariamente completos. Se necesita que el proceso sea igual sin importar qué

tipo de datos sean ingresados al sistema. El output de la aplicación debe ser uniforme, sin importar el

tipo de datos ingresados, y puede ser necesario adaptar datos para ser leídos por muchas aplicaciones

distintas.

Figura 4: Modelo pipe-and-filter de Vocludet

El problema de los distintos formatos de input es solucionado por Pizarro et al con la implementación de

un modelo pipe-and-filter presentado en la Figura 4. Existen tres funciones principales, a partir de las

cuales se crean tres grupos de filtros. El primer grupo de filtros, llamado Formatted Data Readers (FDR)

Page 27: Paralelización de un Algoritmo para la Detección de Clusters de

27

está compuesto por módulos que leen información de diversas fuentes y los escriben en un formato

común. El segundo grupo de filtros, llamados Internal Data Processing (IDP) tiene módulos que procesan

la información escrita en el formato común, escribiendo también sus resultados en formato común. El

tercer grupo de filtros, llamados Formatted Data Writers (FDW) leen datos escritos en el formato común

y escriben la información en diferentes formatos, según lo especificado por el usuario final.

Una gran ventaja es que diferentes niveles de complejidad están encapsulados en diferentes grupos de

filtros. Es claro que la complejidad relacionada con la heterogeneidad de los formatos de entrada está

encapsulada en el primer grupo de filtros (FDR), donde cada módulo es básicamente un parser. La

complejidad relacionada con el procesamiento de datos está encapsulada en el segundo grupo de filtros

(IDP), los que siempre funcionan con tipos de dato homogéneo para sus inputs, mejorando la eficiencia.

Finalmente, el tercer grupo de filtros (FDW) encapsulan la complejidad relacionada a los formatos de

output, entregando facilidad en la personalización y creación de nuevos formatos de output. El plan de

ejecución de estos módulos se encuentra en otro módulo: el módulo de Script, el cual encapsula la

especificación del plan de ejecución en la aplicación.

Esta arquitectura es muy flexible, ya que no está restringida a una secuencia input-procesamiento-

output, sino que puede tener múltiples ejecuciones de procesos externos que incorporan nueva

información al proceso.

La secuencia de ejecución es la especificación del orden temporal en que los módulos son ejecutados en

la aplicación.

Page 28: Paralelización de un Algoritmo para la Detección de Clusters de

28

Figura 5: Ejecución simple de Vocludet

La ejecución más simple de Vocludet es presentada en el diagrama de secuencia de la Figura 5. La

secuencia es la siguiente:

El módulo Script es invocado, y va a ser quien esté a cargo de invocar a todos los otros módulos.

Un módulo Reader es invocado: Lee datos desde una Formatted Data Source (fuente de datos

inicial en algún formato muy probablemente distinto al formato común interno), y escribe la

información al componente Interna Data (datos internos escritos en el formato común). Esto

corresponde a la primera capa.

Un módulo de Data Processing (procesamiento de datos) es ejecutado, el cual lee los datos y

escribe los resultados en el componente Internal Data. Esto corresponde a la segunda capa.

Un módulo Writer (escritor) es invocado, el cual lee información desde el componente Internal

Data y la escribe como Formatted Data Output (datos en algún formato especificado por el

usuario final). Esto corresponde a la tercera capa.

Page 29: Paralelización de un Algoritmo para la Detección de Clusters de

29

Los componentes básicos de la arquitectura son:

Script: Un Script es un shell script que define la sucesión de líneas de comando de los módulos que

deben ejecutarse para realizar un proceso de detección de clusters.

Módulos: Un Módulo es cualquier programa ejecutable mediante la línea de comandos sin intervención

del usuario (no interactiva).

Según esta definición, el “proceso de detección de cúmulos” es especificado en el Script, y define una

ejecución secuencial de uno o más Módulos.

3.3. Versión disponible de Vocludet

Se realizaron varios experimentos para ver el estado del software con que se trabajó. En primer lugar se

determinó que la versión disponible de Vocludet encuentra cúmulos con galaxias repetidas en más de un

cúmulo. Esto es contrario a lo que se describe en el algoritmo en (2), y en el algoritmo descrito en la

sección 2.3.

Cabe hacer notar que el algoritmo presentado en la sección 2.3 no está completo, pues a pesar de

mencionar el conjunto de semillas descartadas, conjunto B, no las incluye allí. El algoritmo corregido es

el siguiente:

Page 30: Paralelización de un Algoritmo para la Detección de Clusters de

30

Algoritmo 3: Algoritmo VTMLE corregido

Page 31: Paralelización de un Algoritmo para la Detección de Clusters de

31

Algoritmo 4: Algoritmo de detección de cúmulos corregido

Page 32: Paralelización de un Algoritmo para la Detección de Clusters de

32

3.4. Alternativas de implementación

En esta sección se analizan las distintas herramientas disponibles para la implementación del software.

Para la mayoría de las decisiones de diseño, se escribió código para comparar y determinar cuál era el

mejor camino a tomar. Se desarrollaron programas con inputs y procesamiento similar al que se debía

implementar, utilizando MapReduce de Hadoop, Pig y Streaming. También se intentó escribir un reducer

que fuese una versión modificada del Vocludet, adaptando el código existente y agregándole secciones

para que siguiese el modelo de programación. Se implementó también una versión donde el mapper

entregaba los rangos que se debían procesar, en vez de los datos mismos.

3.4.1. MapReduce de Hadoop

MapReduce es un modelo de programación diseñado para procesar grandes volúmenes de datos en

forma paralela, dividiendo el trabajo en un set de tareas independientes. Los programas se escriben de

una manera particular, influenciada por el estilo de programación funcional, en el cual se procesan listas

de datos.

Conceptualmente, un programa escrito en MapReduce transforma listas de elementos entregados como

input, en listas de datos de salida. Esto se lleva a cabo dos veces, usando dos procesos de modificación

de datos: map y reduce.

El modelo de programación se explica en las secciones 2.2 y 3.1. Éste usa Java como lenguaje de

programación, existiendo restricciones en las clases que se deben extender y las interfaces que se deben

implementar. Este es nivel más bajo de programación para Hadoop, al existir lenguajes de programación

más simples que usan éste como base, tales como Pig y Streaming.

3.4.2. Pig

Apache Pig es una plataforma para analizar sets de datos de gran tamaño. Consiste de un lenguaje de

alto nivel para escribir programas de análisis de datos, junto con una infraestructura para evaluar estos

programas. Estos programas poseen una estructura que permite paralelización, lo que les da la

capacidad para manejar sets de datos muy grandes.

La capa de infraestructura de Pig consiste de un compilador que produce secuencias de programas

MapReduce, para los cuales ya existe una implementación paralela general. La capa de lenguaje consiste

Page 33: Paralelización de un Algoritmo para la Detección de Clusters de

33

en un lenguaje llamado Pig Latin, el cual posee propiedades positivas interesantes: la programación es

relativamente fácil, al tener una sintaxis parecida a consultas en SQL; simplifica los análisis de datos

simples, al escribirse éstos en pocas líneas y obtener una ejecución en paralelo de forma automática; las

tareas complejas, compuestas por múltiples transformaciones de datos interrelacionados, son

codificadas explícitamente como secuencias de flujo de datos, lo que facilita su lectura; la forma en que

se codifican las tareas permite que el sistema pueda optimizar su ejecución automáticamente,

permitiendo al usuario enfocarse en semántica en vez de eficiencia; y los usuarios pueden crear sus

propias funciones para hacer procesamiento de datos para sus propios propósitos.

3.4.3. Streaming

Hadoop Streaming es una herramienta que viene con la distribución de Hadoop. Ésta permite crear y

ejecutar tareas MapReduce usando cualquier ejecutable o script como mapper o reducer. Esto entrega

una gran flexibilidad, al poder utilizar diferentes lenguajes de programación con herramientas y

bibliotecas específicas para crear los scripts o ejecutables. Streaming inserta estos programas en la línea

de procesos MapReduce, envolviéndolos con mappers y reducers que los alimentan por el stdin y

recuperan sus resultados por el stdout.

Cuando se define el ejecutable que va a ser utilizado en los mappers, cada una de las tareas map lanza el

ejecutable como un proceso separado al momento que se inicializa. Mientras se ejecuta, convierte sus

inputs en líneas y alimenta con estas lineas al stdin del proceso. Mientras tanto, el mapper recolecta los

outputs provenientes del stdout del proceso y los convierte en un par key/values, lo que se transforma

en el output del mapper. Para esto, se usa la convención de que cada línea escrita por el proceso en el

stdout debe corresponder a un key seguido por sus values. Por defecto, el prefijo de una línea hasta el

primer tab se considera el key, y el resto de la línea va a corresponder a los values. Para los reducers

ocurre un proceso similar al de los mappers, pero recibiendo como un par key/values como entrada.

Esta es una alternativa que puede ser muy útil para trabajos en que se quiera reutilizar código, ya que

permite el desarrollo en cualquier lenguaje. Además hace fácil la invocación a código externo al proveer

la capa “envolvente” descrita más arriba.

Page 34: Paralelización de un Algoritmo para la Detección de Clusters de

34

3.5. Alternativa escogida

La alternativa que mostraba la mayor flexibilidad y potencialmente mejores resultados en rendimiento

era MapReduce, pero ésta era también la herramienta de más bajo nivel. Esto significaba escribir más

código el cual probablemente sería más difícil de entender, además de realizar trabajos que otras

utilidades ejecutaban de manera automática.

Pig parecía ser una buena opción, dado el manejo de archivos y la facilidad para particionarlos. Se

intentó hacer un programa en Pig Latin que hiciera el particionamiento de los datos, sin embargo la

ejecución de programas externos no era algo propio de la plataforma, por lo que se debía migrar todo el

Vocludet desde su código en Java a funciones personalizadas de Pig. Si bien esto era posible, se evaluó

negativamente por temas de retro compatibilidad y por la necesidad de conocer Pig, un lenguaje poco

conocido, para desarrollos futuros.

Se decidió utilizar Streaming con Python. Streaming permite futuros desarrollos con cualquier lenguaje

de scripting o que genere ejecutables, ya que se abstrae a un simple procesamiento de datos que se leen

por el stdin y se escriben al stdout. Además su diseño no sólo permite, sino que funciona con llamadas a

código externo. Python provee un fácil manejo de strings, además de permitir ejecutar llamadas a código

externo de una manera relativamente sencilla, en particular a bash, con el que están escritos los scripts

del Vocludet. También permite trabajar con listas y tablas de hash de manera muy simple, facilitando el

trabajo en la partición y re ensamblaje de datos. Para este trabajo el input ya estaba organizado en líneas

y columnas separadas por tabs, por lo que no era necesario un pre procesamiento de la información

antes de ser usada para Streaming. Todo lo anterior se traduce en un código más simple, corto y legible,

facilitando su modificación y la comprensión de terceros para desarrollos futuros

Page 35: Paralelización de un Algoritmo para la Detección de Clusters de

35

4. Diseño e Implementación

En este capítulo se presentan las decisiones que se consideraron para el diseño del software, se propone

un diseño final, y se muestra y explica el código implementado.

4.1. Diseño de la solución

Dado que se decidió trabajar con Hadoop, en particular con streaming, el diseño de la solución

contempla el uso de mappers y reducers para procesar los datos en forma paralela.

Al funcionar con tres capas, de lectura, procesamiento y escritura de datos, el software Vocludet permite

hacer múltiples tipos de procesamiento de datos. Dado que el fin de este proyecto no es la ejecución

misma de los procesos, sino la implementación de una solución que permita efectuar estos procesos en

forma paralela, para el diseño y testeo se consideró sólo la ejecución del VTMLE. A pesar de no llevarse a

cabo el resto de los procesos, los resultados se pueden extrapolar, de esta forma evitando los altos

costos en tiempo y recursos asociados. De todos modos se pueden llevar a cabo otros procesos

simplemente agregándolos a los scripts de ejecución.

Para ejecutar el VTMLE se requiere sólo la información de posición de las galaxias, obtenidas desde el

sondeo 2dFGRS. Sin embargo, Vocludet utiliza información adicional, correspondiente a los datos

fotométricos de las galaxias. Esta información no sirve de input para el VTMLE, pero se incluyó pues es

utilizada por el software secuencial para ejecutar otros procesos. Si bien este trabajo no contempla

realizar aquellos procesos, por lo que la información fotométrica no es de interés, de todos modos se

entregarán ambos sets de datos como entrada. Esto permite trabajar con el programa Vocludet sin

modificarlo, lo que facilita la re ejecución de trabajos anteriores y el desarrollo de futuros trabajos donde

sí se quieran hacer comparaciones, con la ventaja del paralelismo otorgado por el presente trabajo. La

versión sobre la que se trabajó recibe entonces dos archivos de entrada, correspondientes a los datos de

posición y a datos fotométricos de las galaxias.

Los archivos constan de 8 y 12 columnas de datos separados por tabs. Ambos archivos describen puntos

en tres dimensiones, con dos coordenadas angulares y una de profundidad (ra, dec y z), además de otros

datos descriptivos.

Se contemplaron varios diseños para llevar a cabo el procesamiento de los datos, descritos a

continuación. Lo que se mantuvo constante para todos los diseños es que el mapper debía establecer

Page 36: Paralelización de un Algoritmo para la Detección de Clusters de

36

una división de los datos, y el reducer debía hacer el procesamiento equivalente al VTMLE en forma

paralela.

4.1.1. División de los datos

La primera decisión de diseño fue la división de los datos en un set de celdas, sin que se perdiesen datos

en el proceso. Al hacer una división disjunta, se tenía el problema de que un cúmulo fuese separado en

dos o más de estas divisiones. Para ello habían dos soluciones posibles: encargarse del problema

después, viendo cuáles eran los cúmulos que habían quedado como caso de borde y analizándolos en

una segunda pasada, o crear las particiones de tal manera que no hubiesen estos problemas. Se optó por

la segunda opción, dado que la primera implicaría la creación de tres nuevas etapas: un análisis de los

cúmulos para encontrar los que se encontraran posiblemente divididos, una ejecución del detector de

cúmulos sobre las áreas en conflicto, y una posterior reconstrucción de los datos. Además, si no se hacía

bien, se podrían generar nuevos conflictos en la segunda pasada, lo que requeriría de nuevos

mecanismos de re ensamblaje.

Las particiones se podían crear de tal manera que no dividiesen los cúmulos, pero esto implicaba un gran

costo en el análisis previo de los datos. La solución por la que se optó fue crear divisiones no disjuntas,

donde los bordes de cada elemento de la partición se solaparan en una cierta distancia. Esto implica un

sobrecosto al procesar datos de ciertas áreas del cielo más de una vez, pero se evita el procesamiento

asociado al análisis de cúmulos que se encuentren divididos en varias celdas. Algunos cúmulos se pueden

detectar en más de una celda, por lo que en una etapa posterior se deben identificar y eliminar los que

se encuentren repetidos.

Una tarea esencial es encontrar los parámetros para lograr una buena partición. Estos incluyen: la

cantidad mínima de galaxias que debe tener una celda, de tal manera que la cantidad de cúmulos que se

puedan detectar por completo sea mayor a los cúmulos que se encuentren en los bordes; el tamaño

mínimo del solapamiento entre las celdas (en adelante overlap), para que todo cúmulo de galaxias se

pueda encontrar íntegramente en al menos una división; la geometría de las celdas, para evitar que un

cúmulo sea más grande que una celda en alguna de sus dimensiones, maximizar la cantidad de cúmulos

íntegros y a su vez minimizar los cúmulos en los bordes; la forma en que se dividen los datos, dado que

se usan coordenadas esféricas para la descripción de posición, lo que conlleva un aumento en el

volumen de las particiones (a coordenadas angulares constantes) al alejarse la coordenada radial del

centro en intervalos constantes; etc.

Page 37: Paralelización de un Algoritmo para la Detección de Clusters de

37

Los parámetros escogidos deben encontrar un equilibrio entre maximizar la paralelización, y minimizar la

cantidad de procesamiento duplicado debido a cúmulos que se encuentran en zonas de overlap. Lo

primero tiende a aumentar el número de celdas y por ende reducir su tamaño, mientras que lo segundo

tiende a lo contrario.

Se habló con astrónomos que trabajaron directa o indirectamente con el trabajo en que se basa el

presente, de los que se obtuvo la siguiente información:

Para determinar si se está en presencia de un cúmulo de galaxias, se debe primero obtener una

densidad local promedio de galaxias. Para esto se toma un punto y un radio, calculándose la

densidad dentro de la esfera que se construye a partir de éstos. El radio mínimo que se podría

considerar es de 15 Mega parsecs (Mpc).

Por construcción, un cúmulo de galaxias debe tener menos de 1,5 Mpc de radio. De lo contrario

se tendrían cúmulos de tamaños muy distintos, al poder seguirse agregando muchas galaxias a

un cúmulo según otros criterios de agregación.

Con el primer dato se puede establecer que en toda celda debe poder caber una esfera inscrita de 15

Mpc de radio, para que en el caso general se logre una densidad local promedio adecuada. Con el

segundo dato se puede establecer que independiente del tamaño y la geometría de las celdas, el tamaño

del overlap debe ser mayor a 3 Mpc. De esta manera se garantiza que todo cúmulo va a poder ser

encontrado íntegramente en al menos una celda.

Respecto a la geometría, es intuitivo pensar que celdas con formas y volúmenes similares van a tender a

equiparar el tiempo de procesamiento de los datos. Por lo demás, la geometría de las celdas va a

depender necesariamente de la geometría del espacio que se esté analizando. Al graficar los puntos en

tres dimensiones se ve que la forma del espacio analizado es la de un cono aplanado, con

aproximadamente 1,3 radianes de ascensión recta y 0,15 radianes de declinación. No se trata

exactamente de un cono, sino más bien una pirámide con base redondeada similar a un pedazo de pizza.

En adelante se referirá a ésta como slice.

Para particiones con pocas celdas, y por ende para una cantidad limitada de paralelismo, se pueden

hacer divisiones en la ascensión recta del slice, y si se desestima el volumen resultante en virtud del

paralelismo, se pueden hacer divisiones según el radio. El resultado de la primera estrategia es una

división del slice original en varios slices alargados sobrepuestos, presentados en la Figura 6. El de la

Page 38: Paralelización de un Algoritmo para la Detección de Clusters de

38

segunda estrategia es similar, agregándose cortes redondeados definidos por radios fijos y la

superposición de éstos, presentados en la Figura 7.

Figura 6: Partición angular Figura 7: Partición angular y radial

Si bien la primera estrategia genera celdas similares en forma y volumen, su forma alargada genera

amplias zonas de overlap cuando se divide en muchas celdas. Se buscó otra forma de particionar los

datos que permitiese obtener celdas con volúmenes similares, pero además con una geometría más

equilátera. Las celdas con forma de cubo minimizan las áreas de overlap, disminuyendo los datos que se

procesan múltiples veces. Si bien la forma del espacio y el sistema de coordenadas utilizado hacen sub

óptima la división del slice en cubos, se encontró una partición que mientras más divisiones tiene, más se

parece a un cubo. Ésta consiste en definirse una arista mínima del cubo ideal, y en base a ésta hacer

divisiones lo más equiláteras posibles, con lados mayores a la arista. Primero se divide el slice en

cascarones múltiplos del mismo radio, donde el radio es el menor valor mayor o igual a la arista, que

divida el radio total en partes iguales. Luego se particiona cada uno de los cascarones en partes iguales,

tanto en el ángulo de ascensión recta como en el de declinación. Para esto se toma el arco menor del

cascarón y se divide en partes iguales, al igual que con el radio, en el menor valor que sea mayor a la

arista mínima. Las celdas resultantes dividen al slice en trozos de volumen similar, y tienen una

geometría que disminuye la proporción total de overlap. Además, mientras más pequeña es la arista

mínima, más divisiones se hacen y las celdas se parecen más a un cubo. Esta estrategia está graficada en

la Figura 8.

Page 39: Paralelización de un Algoritmo para la Detección de Clusters de

39

Figura 8: Partición en celdas similares a cubos

4.1.2. Procesamiento de los datos

La siguiente decisión de diseño fue determinar la forma en que el reducer llevaría a cabo el proceso

VTMLE. La primera opción, que se escogió en un principio al ser la más natural, consistía en crear un

reducer que fuese una versión del Vocludet modificado, manteniendo las funcionalidades y adaptando

los procesos para hacerlos compatibles con el framework Hadoop. Se abría una gama de opciones para la

implementación de este código, incluyendo el lenguaje y la capa de abstracción de Hadoop a la que iba a

pertenecer. Independiente de esta decisión, crear un reducer con estas características implicaba no sólo

cambiar el código del Vocludet, sino dejarlo inutilizable fuera del contexto del framework. También

significaba que para la utilización de algunas funcionalidades existentes y de desarrollos futuros se debía

contar con conocimientos específicos de Hadoop, yendo en contra de la idea original del Vocludet que

proponía independencia del lenguaje en la creación de filtros para el procesamiento de datos. Uno de los

aspectos básicos que se debía cambiar en la implementación de esta solución, era la forma en que se

entregaran los datos. Se debía cambiar el sistema de lectura de archivos por uno donde se leyesen líneas

desde el stdin.

Esta problemática dio origen a una segunda opción para el diseño del reducer, que contemplaba no

modificar el código del Vocludet, sino crear un reducer que se encargara de proporcionarle los datos en

el formato original. Se eligió la segunda opción ya que facilitaba la reutilización de utilidades ya creadas,

Page 40: Paralelización de un Algoritmo para la Detección de Clusters de

40

y permitía el desarrollo de otras nuevas con las mismas herramientas y metodologías utilizadas en el

proyecto original. Dada esta opción, se debía decidir de qué forma se entregarían los datos. El mapper

debía determinar la partición, luego de lo cual los datos se podían entregar uno por uno al reducer

correspondiente, o simplemente entregar el rango de datos a cada reducer.

La solución que consistía en la entrega de los rangos de datos era posible ya que uno de los parámetros

con los que trabaja el Vocludet es el rango sobre el que se quiere trabajar, dentro de un conjunto de

datos. La implementación de esta modalidad contemplaba la creación de múltiples archivos de scripting,

con los parámetros configurados para que cada uno se hiciera cargo de una celda del cielo derivado de la

partición, para luego ejecutar estos scripts en forma paralela. Si bien este modo era directo y su

implementación relativamente simple, no se usaba el framework Hadoop de manera estándar, en

particular el modelo de entrada/salida del “reduce” y el sistema de archivos. Tampoco se tenía la certeza

de que la selección dentro del conjunto de datos se hiciese en forma eficiente.

Se optó entonces por otro mecanismo que realiza tareas redundantes de lectura y escritura de archivos,

pero utiliza Hadoop de una manera convencional. Ésto permite obtener las optimizaciones implícitas de

Hadoop, optar a posibles mejoras en versiones futuras del framework, y facilitar desarrollos futuros de la

aplicación. Para esto se utilizó el modo estándar de Streaming, en que luego de determinar los criterios

de partición, el mapper le entrega a cada reducer el set de datos que le corresponde. El reducer luego se

encarga de crear los archivos de entrada, crear los scripts correspondientes, y ejecutar el Vocludet.

4.1.3. Re ensamblaje de los resultados

El proceso VTMLE crea dos archivos resultantes: uno con la extensión “.ID”, el cual en cada línea tiene el

identificador único de un cúmulo de galaxias; el otro con la extensión “.GID”, el cual por cada línea tiene

datos separados por tabs, donde cada dato corresponde al identificador de una galaxia, y cada línea

corresponde a un cúmulo de galaxias. El archivo más relevante, y por ende el que interesa re ensamblar,

es el que contiene las galaxias integrantes de cada cúmulo; el otro simplemente sirve como referencia

para otros procesos que se pueden llevar a cabo. Al dividir los datos y ejecutar el VTMLE sobre cada

partición, se crean tantos archivos de salida como conjuntos.

Uno de los problemas es que los identificadores de las galaxias son únicos para un set de datos, pero van

a estar repetidos y usados para identificar a más de una galaxia si se trabaja con más de un set. Esto se

debe a que la identificación es una simple enumeración de las galaxias contenidas en el set de datos.

Para trabajar con varios archivos se necesita tener el mismo identificador para las galaxias

Page 41: Paralelización de un Algoritmo para la Detección de Clusters de

41

independientemente del archivo en que se encuentren, pudiendo usarse la posición absoluta o un

derivado de ésta. Una primera solución consistía en modificar el Vocludet para que generara

identificadores absolutos independientemente del archivo. Ésta se descartó por razones ya descritas en

otras secciones de este documento, donde se explica por qué se evitar modificar el Vocludet. Otra

opción era generar un nuevo archivo, reemplazando los identificadores de galaxias por su posición

absoluta en el espacio. Uno de los archivos intermedios que genera el Vocludet contiene, entre otras

cosas, el identificador de cada galaxia y su posición absoluta, por lo que se utilizó para la generación del

nuevo archivo.

Ya trabajando con un sistema de identificación única, el siguiente paso fue eliminar los cúmulos

repetidos. Primero está la pregunta de cómo se define un cúmulo repetido, si es cuando los centroides

se encuentran a una corta distancia, cuando se utiliza la misma semilla para su generación, o si

simplemente tienen algún miembro en común. Dada la forma en que funciona el algoritmo de Daniel

Pizarro, descartando la construcción de cúmulos que contengan una o más galaxias pertenecientes a un

cúmulo ya aceptado, se optó por definir como repetidos aquellos que tenían cualquier miembro en

común. La siguiente decisión fue determinar cuál de los cúmulos se guarda y cuáles se desechan,

pudiendo haber hasta 8 cúmulos con un mismo miembro, siendo 8 el número máximo de celdas que

pueden estar sobrepuestas en un mismo sector al dividir el espacio en 3 dimensiones. Suponiendo una

partición de datos con un overlap suficientemente grande, como las descritas en este documento, se

puede asumir que cualquier cúmulo de galaxias va a estar completo en alguno de los archivos. Por ende,

se puede eliminar el que tenga menor cantidad de galaxias, sin tener que tomar en consideración otros

elementos astronómicos como la semilla de menor volumen, la densidad promedio del cúmulo, u otros.

4.1.4. Diseño final

Los datos de entrada, tanto de posición como fotométricos, son ingresados al sistema de

almacenamiento de Hadoop. Luego el sistema de streaming lee ambos archivos, entregando a cada

mapper un set de datos, una línea a la vez. Cada mapper recibe las líneas por el stdin y determina a qué

celda del cielo corresponde cada una. Luego agrega la información de la celda a la línea con datos y la

escribe como salida en el stdout. De esta forma, los sets de datos que corresponden a la misma celda se

agrupan y se redirigen a un mismo reducer.

El reducer recibe líneas por el stdin, las que provienen de ambos archivos de entrada originales. Cada

reducer recibe las líneas correspondientes a una o más celdas del cielo. Por ende, el reducer debe

Page 42: Paralelización de un Algoritmo para la Detección de Clusters de

42

clasificar las líneas según archivo del que provengan, y según la celda a la que correspondan. Luego crea

archivos según éstas clasificaciones, los que escribe en el sistema de archivos local. Para cada celda de

las que recibe datos, crea un script que ejecuta el Vocludet, entregándole como parámetros los dos

archivos de entrada correspondientes. Luego ejecuta cada uno de los scripts creados, los que escriben

sus resultados en el sistema de archivos local. Con los archivos resultantes se construye uno nuevo, en

que cada línea corresponde a un cúmulo de galaxias, con cada elemento de la línea siendo la posición

absoluta de una galaxia perteneciente a tal cúmulo. Por último lee los archivos de resultado, y escribe

cada línea resultante en el stdout, para así completar el proceso de Streaming. Cada uno de los reducers

se ejecuta en paralelo, por lo que la rapidez de ejecución depende del número de celdas, reducers, y

procesadores disponibles. Además del aumento en eficiencia evidente al ejecutarse los procesos en

paralelo, Hadoop tiene optimizaciones internas que agilizan estos procesos.

Para el re ensamblado de los resultados, se utilizan los archivos que describen los cúmulos de galaxias

con la posición absoluta de las galaxias que los componen. Se ejecuta un script de python que toma dos

de estos archivos, busca las galaxias que se repitan en dos cúmulos, y de estos dos cúmulos elimina el

que tenga menor cantidad de galaxias. Se puede asumir que una galaxia va a encontrarse en un solo

cúmulo por archivo, dado el proceso de construcción de los cúmulos, por lo que la intersección de

elementos sólo va a darse entre dos cúmulos de galaxias. Este proceso de unión de archivos se lleva a

cabo recursivamente, hasta finalmente unirse en un archivo que contiene todos los cúmulos de galaxias.

Page 43: Paralelización de un Algoritmo para la Detección de Clusters de

43

4.2. Código Implementado

Ya que Hadoop y sus herramientas asociadas no son de uso masivo, la documentación que se puede

encontrar es escasa. Además, al estar en desarrollo, la información que se encuentra puede no ser útil

para la versión del software que se esté ocupando. Dado lo anterior y que quien escribe no contaba con

conocimiento en el tema, durante todo el desarrollo del presente trabajo y en especial al principio, se

llevaron a cabo numerosos tutoriales y experimentos para entender el funcionamiento y

comportamiento de cada una de las herramientas que se investigó.

La última herramienta que se investigó, y con la que se decidió finalmente construir el presente trabajo,

fue Streaming con Python. Se hicieron numerosos experimentos para entender el comportamiento que

presentaba: determinar el método de separación de parámetros; entender el comportamiento de

Python en el manejo de strings, input y output, y ejecución de bash; entender la secuencia de procesos

que ocurren para que funcione Hadoop; determinar la ubicación del directorio de trabajo, donde se

guardan los archivos resultantes de procesos intermedios, y si esto se hacía en el sistema de archivos del

sistema operativo o en el HDFS; averiguar si se trabajaba sobre los archivos originales de map y reduce

en una misma máquina, o si se crea una copia por cada mapper y reducer; determinar cómo se lleva a

cabo la asignación de los grupos de keys en los reducers; etc.

El código final para el programa corresponde a un mapper encargado de crear la partición de los datos,

un reducer encargado del procesamiento de éstos, y un script de unión de los archivos resultantes.

Además se utilizan el software secuencial y los scripts que se crean en el reducer para ejecutarlo.

A continuación se presenta el código del mapper correspondiente a la partición más interesante, la que

resulta en celdas similares a cubos, como graficado en la Figura 8:

Page 44: Paralelización de un Algoritmo para la Detección de Clusters de

44

#!/usr/bin/env python

from __future__ import division

import sys

#------------------------------------ set parameters ----------------------------------

#minimum values of the data, in theta, phy, redshift

min_val = {'x':2.57441, 'y':-0.10975, 'z':0.002}

#maximum values of the data

max_val = {'x':3.88319, 'y':0.04363, 'z':0.2995}

#minimum edge of the "cube", in Mpc

min_cube_edge = 30

#minimum overlap of the cube, in Mpc

min_cube_overlap = 3

#dimensions of the space (cone), in Mpc

cone_dimensions = {'x':1000, 'y':100, 'z':1000}

#------------------------------------ calculate variables ----------------------------------

#separate z in n parts, where (maxz-minz)/n > min_cube_edge

split_number_z = int(cone_dimensions['z'] / min_cube_edge)

#dimension of the z edge of a cube, in Mpc

cube_edge_z = cone_dimensions['z']/split_number_z

#overlap value for the z axis

overlap_val_z = ( (min_cube_overlap * (max_val['z'] - min_val['z'])) / cone_dimensions['z'])

#for each z fringe, (separate in semi cubes) find n so that (thetamax-thetamin)*z = arc, arc/n >

min_cube_edge

split_number_x = [0]

overlap_val_x = [0]

for i in range(1, split_number_z) :

#arc = radius * angle(radians) , in Mpc

arc = (i * cube_edge_z) * (max_val['x'] - min_val['x'])

#number of divisions for that fringe

divisions = int(arc / min_cube_edge)

#overlap in degrees for that fringe, arc -> delta_angles : cube_overlap -> angle_overlap

angle_overlap = min_cube_overlap * (max_val['x'] - min_val['x']) / arc

#add values to corresponding arrays

overlap_val_x.append(angle_overlap)

split_number_x.append(divisions)

#for each z fringe, (separate in semi cubes) find n so that (phy_max-phy_min)*z = arc, arc/n >

min_cube_edge

split_number_y = [0]

overlap_val_y = [0]

for i in range(1, split_number_z) :

#arc = radius * angle(radians) , in Mpc

arc = (i * cube_edge_z) * (max_val['y'] - min_val['y'])

#number of divisions for that fringe

Page 45: Paralelización de un Algoritmo para la Detección de Clusters de

45

divisions = int(arc / min_cube_edge)

#overlap in degrees for that fringe, arc -> delta_angles : cube_overlap -> angle_overlap

angle_overlap = min_cube_overlap * (max_val['y'] - min_val['y']) / arc

#add values to corresponding arrays

overlap_val_y.append(angle_overlap)

split_number_y.append(divisions)

split_number = {'x':split_number_x, 'y':split_number_y, 'z':split_number_z}

overlap_val = {'x':overlap_val_x, 'y':overlap_val_y, 'z':[overlap_val_z] * (split_number['z'] -1)}

#columns with the x, y and z values fron the 2dFNGgals file

col_2d = [0, 1, 2]

#columns with the x, y and z values fron the best.observations file

col_ob = [4, 5, 6]

z_ponderator = [split_number['z'] / (max_val['z'] - min_val['z'])] * (split_number['z'] -1)

x_ponderator = map(lambda x : x / (max_val['x'] - min_val['x']), split_number['x'])

y_ponderator = map(lambda x : x / (max_val['y'] - min_val['y']), split_number['y'])

ponderator = {'x':x_ponderator, 'y':y_ponderator, 'z':z_ponderator}

#function for getting the quadrants to which a value corresponds

def get_quadrant(val, coord, fringe):

list = []

#val moved to simulate overlap

plus_val = val + overlap_val[coord][fringe]

minus_val = val - overlap_val[coord][fringe]

#quadrant to where val belongs

quad = int((val - min_val[coord]) * ponderator[coord][fringe])

#quadrant to where val belongs, considering top overlap

quad_plus = int((plus_val - min_val[coord]) * ponderator[coord][fringe])

#quadrant to where val belongs, considering bottom overlap

quad_minus = int((minus_val - min_val[coord]) * ponderator[coord][fringe])

#correct the max vals problem (max vals get their own cell)

if val == max_val[coord]:

quad -=1

list.append(quad)

if plus_val < max_val[coord] :

list.append(quad_plus)

if minus_val > min_val[coord] :

list.append(quad_minus)

return set(list)

#------------------------------------ process data ----------------------------------

Page 46: Paralelización de un Algoritmo para la Detección de Clusters de

46

# input comes from STDIN (standard input)

for line in sys.stdin:

# remove leading and trailing whitespace

line = line.strip()

# parse the data

coords = line.split()

#if the input is from the 2dFNGgals file

if len(coords) == 8:

coord_x = float(coords[col_2d[0]])

coord_y = float(coords[col_2d[1]])

coord_z = float(coords[col_2d[2]])

coord = {'x':coord_x, 'y':coord_y, 'z':coord_z}

#if the input is from the best.observations file

elif len(coords) == 12:

coord_x = float(coords[col_ob[0]])

coord_y = float(coords[col_ob[1]])

coord_z = float(coords[col_ob[2]])

coord = {'x':coord_x, 'y':coord_y, 'z':coord_z}

else:

continue

#if the values are out of the min and max range

if coord['x'] > max_val['x'] or coord['x'] < min_val['x'] or coord['y'] > max_val['y'] or coord['y'] <

min_val['y'] or coord['z'] > max_val['z'] or coord['z'] < min_val['z']:

continue

#determine corresponding quadrants

quadrants = []

quadrants_z = get_quadrant(coord['z'], 'z', 0)

for fringe in quadrants_z :

quadrants_x = get_quadrant(coord['x'], 'x', fringe)

quadrants_y = get_quadrant(coord['y'], 'y', fringe)

#pair both lists, and add the corresponding fringe

quadrants.extend([[x, y, fringe] for x in quadrants_x for y in quadrants_y])

#print the lines with their corresponding quadrants to the stdout

for quadrant in quadrants :

quadrant_string = `quadrant[0]` + ',' + `quadrant[1]` + ',' + `quadrant[2]`

print '%s\t%s' % (quadrant_string, line)

Page 47: Paralelización de un Algoritmo para la Detección de Clusters de

47

El mapper recibe líneas, una por una, en el stdin, correspondientes a cada línea de los dos archivos de

entrada. Estas líneas pueden tener 8 o 12 datos separados por tabs, dependiendo de cuál de los dos

archivos provienen. De cada línea, se seleccionan los datos correspondientes a las coordenadas de la

galaxia que la línea representa. Las posiciones en las que se encuentran los datos de las coordenadas son

diferentes según el archivo del que provengan, por lo que se usa la cantidad de parámetros que la línea

tenga para determinarlas. Usando los datos de posición, y otros parámetros que determinan el tamaño y

forma de las celdas, se calcula la o las celdas a los que pertenece la galaxia. Finalmente, el mapper

imprime al stdout las celdas a las que pertenece la galaxia, seguido por la línea misma. El primer dato

impreso pasa a ser el key del output, y la línea, es decir el conjunto de valores separados por tabs, pasa a

ser el conjunto de values del output. El key, correspondiente al identificador de la celda, es una

coordenada en tres dimensiones: tres números separados por comas.

Se presenta a continuación el código del reducer:

Page 48: Paralelización de un Algoritmo para la Detección de Clusters de

48

#!/usr/bin/env python

#os.system only works in linux

from operator import itemgetter

import os

import sys

import shlex, subprocess

#------------------------ create the input files ---------------------

#working directory

wd = "/home/maugsbur/Dropbox/hadoop/cludet_004/"

#a dict of dicts, keeping record of the existent keys

#each key is a dict with two arrays corresponding to each file

keys = {}

# input comes from STDIN

for line in sys.stdin:

# remove leading and trailing whitespace

line = line.strip()

# parse the input we got from mapper.py

coords = line.split()

#eliminate first element (key), and save it

key = coords.pop(0)

#remake line without first element

line_wo_key = "\t".join(coords)

line_wo_key += "\n"

#if it's the first time the key appears, open corresponding 2dFNGgals and best.observations

if keys.get(key) == None :

keys[key] = {}

keys[key]['file_2d'] = open(wd + 'work/2dFNGgals_' + key, 'w')

keys[key]['file_ob'] = open(wd + 'work/best.observations_' + key, 'w')

#if the line comes from a the 2dFNGgals file

if len(coords) == 8:

#write line into local 2dFNG file

keys[key]['file_2d'].write(line_wo_key)

else:

#write line into local best.observation file

keys[key]['file_ob'].write(line_wo_key)

#close files

for key in keys :

keys[key]['file_2d'].close()

Page 49: Paralelización de un Algoritmo para la Detección de Clusters de

49

keys[key]['file_ob'].close()

#------------------------ process data with Vocludet ---------------------

#write script

for key in keys :

script = open(wd + 'script_' + key, 'w')

script.write('PREV_DIR=$PWD\n')

script.write('cd $WORK_DIR\n')

script.write('$JREPATH/bin/java -Xms256M -Xmx256M -classpath

"$OTHER_JAR/vecmath.jar$PATHSEP$CLUDET_JAR" cl.uchile.dcc.astro.cludet.parser.TPIGG_parser Z001-

NGP_' + key + ' 16 9 3 -10 0.007 9.000 2dFNGgals_' + key + ' best.observations_' + key + '\n')

#script.write('$JREPATH/bin/java -Xms256M -Xmx256M -classpath

"$OTHER_JAR/vecmath.jar$PATHSEP$CLUDET_JAR" cl.uchile.dcc.astro.cludet.parser.TPIGG_parser Z001-

NGP 16 9 3 -10 0.007 9.000 2dFSGPgals.dat best.observations.idz.photometric\n')

script.write('$JREPATH/bin/java -Xms256M -Xmx256M -classpath

"$OTHER_JAR/vecmath.jar$PATHSEP$CLUDET_JAR"

cl.uchile.dcc.astro.cludet.detector.VTMLE_ClusterDetector Z001-NGP_' + key + '\n')

script.close()

#execute script

#create log file, with stdout info

logout = open(wd + 'work/logout' + key, 'w')

#create log file, with stderr info

logerr = open(wd + 'work/logerr' + key, 'w')

#write command line command

bash = wd + 'run ' + wd + 'script_' + key

args = shlex.split(bash)

#execute command on bash

process = subprocess.Popen(args, shell=False, stdout=logout, stderr=logerr)

a = process.communicate()

#-------------------------- create file for reassembling ---------------------------

#elements hash, id with its corresponding line in file

cells = {}

#file with cell ids and positions

volumeslog = open(wd + 'work/Z001-NGP_' + key + '.VOLUMES_log.log', 'r')

#eliminate first line, with table column names

volumeslog.readline()

for line in volumeslog :

# remove leading and trailing whitespace

line = line.strip()

Page 50: Paralelización de un Algoritmo para la Detección de Clusters de

50

# parse the line

split = line.split()

#obtain the cell id

id = split[0]

#obtain the position

pos = split[1]

#insert in the hash table

cells[id] = pos

#file with clusters, one per line, multiple cell ids

clustersgid = open(wd + 'work/Z001-NGP_' + key + '.VTMLE.clustersGID', 'r')

#outfile with the gid file rewritten with positions

newgid = open(wd + 'work/Z001-NGP_' + key + '.VTMLE.clustersGID.pos', 'w')

for line in clustersgid :

# remove leading and trailing whitespace

line = line.strip()

# parse the input

split = line.split()

#rewrite the clustersgid with positions

for id in split :

#obtain the position of the cell

pos = cells[id]

#write the new file

newgid.write(pos+'\t')

newgid.write('\n')

#---------------------------- write output -------------------------------

#read files

file_2d = open(wd + 'work/Z001-NGP_' + key + '.VTMLE.clustersGID.pos', 'r')

#write them on the stdout

for line in file_2d:

print key + ' ' + line

Page 51: Paralelización de un Algoritmo para la Detección de Clusters de

51

El reducer recibe líneas, una por una, en el stdin, las cuales contienen primero el identificador de la celda

a la que corresponde la galaxia representada por la línea, y luego los datos de posición y fotométricos de

ésta. La totalidad de las líneas que recibe cada reducer corresponden a una o más celdas de la partición

del espacio hecha por el mapper. El número de celdas que reciba cada reducer va a depender de la

proporción entre éstos, siendo idealmente uno a uno, pero pudiendo haber más de una celda por cada

reducer. Primero se hace una separación de la línea, entre el key y los values, que corresponden al

primer dato y el resto de los datos respectivamente. En caso de que el valor del key, identificador de la

celda al que pertenece la galaxia, no haya aparecido en líneas anteriores, se crean los dos archivos

asociados a éste. Luego se escribe una nueva línea con los values en el archivo que corresponda, el cual

se define según la cantidad de values que contenga: 8 y 12 en cada caso. Luego de leídas y procesadas

todas las líneas del stdin, se procede a guardar los archivos escritos. Posteriormente se escribe un script

con las instrucciones para llamar a los procesos del Vocludet necesarios para que se ejecute el VTMLE:

primero un parser que transforme los datos entregados en el formato común de la aplicación, luego el

programa que ejecuta el VTMLE, y finalmente el programa que transforma los datos intermedios al

formato de output final. Se escribe un script por celda que recibe el reducer, difiriendo un script del otro

en el nombre de los archivos de entrada que se entregan como parámetros a los programas del

Vocludet. Cada uno de los scripts creados se ejecuta desde el reducer a través de otro script denominado

run, el cual recibe el script como parámetro y lo ejecuta, además de llevar a cabo tareas como configurar

el ambiente. La ejecución de los scripts crea archivos con resultados, los cuales son leídos e impresos

línea por línea en el stdout, para así completar el proceso de Streaming. Finalmente se ejecuta, una vez

terminado el proceso de Streaming, el script de re ensamblaje de resultados, sobre los archivos con los

cúmulos y posiciones absolutas de las galaxias. Toda la escritura y ejecución se llevan a cabo en una

carpeta definida como variable global al principio del programa, donde se encuentra la estructura

completa del Vocludet.

Por razones que se mencionaron en otras partes de este documento, se construyó el software sin

modificar el Vocludet. Lo único que se tuvo que cambiar fue una variable con un path absoluto, la que se

modificó para trabajar con la estructura de archivos local.

En la sección de anexos se encuentra otro ejemplo de la función mapper y el re ensamblador.

Page 52: Paralelización de un Algoritmo para la Detección de Clusters de

52

5. Evaluación

En este capítulo se presentan los experimentos realizados para probar el software y determinar su

eficacia y eficiencia. Se incluye una descripción de los datos de prueba, las pruebas mismas, y el

desempeño del software.

5.1. Datos de prueba

En el presente trabajo se utilizaron datos astronómicos que describían la distribución de las galaxias,

además de algunas otras propiedades de éstas. En particular se usaron los del estudio 2dF Galaxy

Redshift Survey (2dFGRS), ya que mostraba la posición de las galaxias en tres dimensiones, siendo la

profundidad determinada por el corrimiento al rojo de las ondas de luz.

Figura 9: Mapa del cielo completo mostrando el sondeo APM, en el que se basó el 2dFGRS

Este es un estudio que se llevó a cabo usando las instalaciones 2dF, construidas por el Observatorio

Anglo-Australiano. Su meta fue obtener espectros de alta calidad y datos del corrimiento al rojo de

250.000 galaxias, pertenecientes a las regiones de ambos el norte y sur galáctico (15), como presentado

en la Figura 9.

Page 53: Paralelización de un Algoritmo para la Detección de Clusters de

53

Figura 10: Mapa de la distribución de galaxias obtenidas por el 2dFGRS

La Figura 10 muestra un mapa de la distribución de galaxias obtenido por este estudio.

En el presente trabajo se utilizaron datos del 100k Release, un subconjunto de los datos del estudio. Éste

contiene los datos de 467.214 objetos, de los cuales no todos eran únicos ni correspondían a galaxias. Se

trabajó con una selección de estos objetos que correspondían a galaxias, separados en dos archivos

correspondientes a observaciones del norte y sur galáctico con 78.508 y 112.513 galaxias

respectivamente. Además se trabajó con un archivo que presentaba los datos fotométricos de 245.591

objetos. Se utilizaron estos datos pues son los mismos con los que trabajó Daniel Pizarro en su tesis de

magister.

Si bien durante la mayoría del trabajo se usó el set de datos completo, para la etapa de pruebas

intensivas y comparaciones sólo se utilizaron los datos del sondeo del norte galáctico. Esto se hizo para

facilitar el análisis de datos reales y para disminuir los recursos requeridos para ejecutar las pruebas.

Page 54: Paralelización de un Algoritmo para la Detección de Clusters de

54

5.2. Pruebas

5.2.1. Particiones

Se definieron 3 tipos de particiones, siendo cada una de éstas útil según la cantidad de máquinas

disponibles para ejecutar reducers. Se hicieron pruebas con todas ellas: la partición angular de la Figura 6

y la partición angular y radial de la Figura 7 se probaron para divisiones de hasta 8 celdas, la partición con

celdas similares a cubos de la Figura 8, se probó para aristas de 30, 60 y 120 Mpc.

Para los primeros tipos de partición, y con la cantidad de celdas descrita, no se tuvo problemas. Para la

partición con celdas similares a cubos, se había definido como volumen mínimo un cubo de lado 30 Mpc.

Usando el tamaño mínimo se iban a poder correr la mayor cantidad de procesos en paralelo, al haber

más celdas para procesar. Con este parámetro, el programa que particionaba los datos dividía el slice en

32 cascarones, cada uno subdividido según el ancho y largo del cascarón, formándose un total de 1641

divisiones. En circunstancias ideales, de densidad constante de datos, cada celda debiese haber tenido

alrededor de 50 elementos. Sin embargo, la mayoría de los elementos se concentraba en unas pocas

celdas, y la gran mayoría de las celdas tenía menos de 20 elementos e incluso carecían de éstos. Además,

las celdas con mayor cantidad de datos no se encuentran distribuidos con un patrón claro. Dado que los

cúmulos interesantes para la astronomía tienen al menos 30 elementos, no tiene sentido usar esta

partición de datos.

La experiencia anterior indica que para particiones con muchas celdas sobre todo el espacio, no es

óptimo trabajar con celdas de volumen constante, siendo probablemente mucho mejor una partición ad-

hoc a la distribución de datos. En particular este sondeo muestra una densidad de galaxias mucho menor

para distancias de z grandes, por lo que una buena distribución ad-hoc podría ser obviando las galaxias

que tengan un z mayor a 0,15, y luego aplicando la partición usada en el experimento anterior.

5.2.2. Ensamblaje

Cuando se trabajó con el re ensamblador, se realizaron experimentos para verificar que se eliminaban

los cúmulos repetidos en varias particiones. Fue entonces que se comprobó que el VTMLE repite

elementos en los cúmulos que encuentra. Esto se debe al funcionamiento del software presentado en la

sección 3.3. Se siguió experimentando, y se descubrió que al modificarse los límites de las particiones, se

obtiene un set muy distinto de cúmulos de galaxias. Los cúmulos resultantes son altamente

Page 55: Paralelización de un Algoritmo para la Detección de Clusters de

55

dependientes de las condiciones iniciales del problema, encontrándose cúmulos distintos dependiendo

de qué cúmulo sea el primero en encontrarse. Dado que el software es determinístico, no hay

discordancias en ejecuciones sobre el mismo set de datos, pero si se modifican de tal manera que

cambien las semillas o el orden en que éstas se encuentran, se van a obtener resultados distintos. En

particular si se divide el set de datos, se van a encontrar cúmulos en otro orden, lo que conlleva a

resultados distintos. Otro factor que influye en el re ensamblaje, es que la mayoría de los cúmulos que

encuentra el algoritmo son pequeños, muchos con 2 o 3 elementos.

Para determinar si el funcionamiento del VTMLE se debía a modificaciones introducidas al paralelizarlo,

lo primero que se hizo fue verificar que la ejecución con Hadoop no cambiase el resultado original. Para

esto se ejecutó el Vocludet solo, los scripts de python, y Hadoop con una partición de una celda. Los tres

métodos dieron los mismos archivos resultantes, encontrando 4170 cúmulos de galaxias.

Para que el proceso de re ensamblado sea válido, se debe verificar que el número de cúmulos que

encuentra sea similar al que se obtiene con el algoritmo secuencial. Se analizaron casos con 2 y 4

divisiones, con y sin overlap, obteniendo los siguientes resultados:

Sin

División

2 Divisiones

sin Overlap

2 Divisiones

10% Overlap

4 Divisiones

sin Overlap

4 Divisiones

10% Overlap

N° de cúmulos 4170 4323 4678 4316 4860

N° de cúmulos post

re ensamblaje

4606 4530

La cantidad de cúmulos encontrados en las particiones sin overlap superan a las del archivo original. Esto

se puede explicar pues las divisiones separan cúmulos de galaxias mayores en cúmulos más pequeños,

sin embargo no se puede mostrar una tendencia, ya que varía de forma irregular con la cantidad de

celdas de una partición. Dado que se encontraron más cúmulos al dividirse los datos sin overlap, era

esperable que agregando un overlap se encontraran más aún. Se esperaba que la reducción de datos por

parte del re ensamblador fuese mayor, sin embargo esto puede deberse a las anomalías previamente

descritas.

Otra condición para la validez del proceso de re ensamblado, es que éste conserve los cúmulos

obtenidos en cada celda y no corrompa los resultados parciales obtenidos. Analizando los datos

Page 56: Paralelización de un Algoritmo para la Detección de Clusters de

56

obtenidos con una partición de 2 celdas y un 10 por ciento de overlap, se obtuvo que las coincidencias

entre los cúmulos de galaxias detectados en los sets de datos parciales y el re ensamblado son:

Celda 1 Celda 2

Cúmulos en el set de datos re

ensamblado

2120

97,83%

2491

99,20%

Se puede notar que a pesar de haber un overlap de un 10%, se elimina menos de un 2% de los cúmulos

por repetición. También se ve que una de las dos celdas mantiene una mayor proporción de sus cúmulos.

Esto es debido a que el criterio de eliminación es por cantidad de galaxias, y al haber muchas de dos o

tres galaxias, existen empates donde se favorece a la celda cuyos datos fueron leídos primero.

Uno de los objetivos de este trabajo es comparar los resultados obtenidos entre el método secuencial y

el método paralelo luego del reensamblaje. Al analizar los datos obtenidos con una partición de 2 celdas

y un 10 por ciento de overlap, se obtuvo que las coincidencias en los cúmulos de galaxias detectados

entre los sets de datos son:

Celda 1 Celda 2 Re ensamblado

Coincidencia de cúmulos

con la partición original

238

10,98%

272

10,83%

502

10,89%

Al analizar los datos obtenidos con una partición de 4 celdas y un 10 por ciento de overlap, se obtiene

algo parecido. Las coincidencias en los cúmulos de galaxias detectados entre los sets de datos son:

Celda 1 Celda 2 Celda 3 Celda 4 Re

ensamblado

Coincidencia de cúmulos

con la partición original

166

7,39%

43

8,6%

184

10,21%

27

8,65%

375

8,99%

Esto indica que claramente hay poca coincidencia entre los cúmulos. Observando los archivos

resultantes, se puede notar que a veces se repiten varios miembros de un cúmulo, pero difieren en

algunos, o en la cantidad total de miembros. Esto muestra que los resultados del algoritmo de búsqueda

de cúmulos son altamente dependientes de las condiciones iniciales con las que trabaja. Sin embargo, al

Page 57: Paralelización de un Algoritmo para la Detección de Clusters de

57

analizar la coincidencia entre los primeros miembros de los cúmulos, correspondientes a las semillas, se

encuentra una coincidencia mucho mayor, como se muestra a continuación:

Partición de 2 Celdas Partición de 4 Celdas

Coincidencia de semillas

con la partición original

1224

29%

1150

28%

5.2.3. Verificación de datos y procedimientos

Dados los resultados de las pruebas, se realizaron tres experimentos para determinar si los resultados se

debían o no a un comportamiento errático del software desarrollado. El primero fue verificar que no se

modificaran ni se perdieran datos en el proceso de partición. El segundo fue corroborar que el Vocludet

ejecutado desde Hadoop obtuviese los mismos resultados que el Vocludet ejecutado de forma

secuencial. El tercer experimento consistió en analizar los resultados obtenidos al ejecutar el software

secuencial y el paralelo sobre una partición simple, en términos de cúmulos y galaxias coincidentes.

El primer experimento fue verificar que los archivos generados por las particiones tuviesen los mismos

datos que los archivos originales, y que no se hubiesen perdido datos en el proceso del mapper. Para

esto se hizo una partición simple, en 2 celdas y sin overlap. Se verificó que las líneas de los archivos

generados por la partición coinciden exactamente con las líneas del primer archivo de entrada, no

habiendo repeticiones ni omisiones. Para las líneas del segundo archivo de entrada sí hubo omisiones,

borrándose 6.099 líneas, correspondiendo a un 6,8% de la totalidad de las líneas. Esto no es accidental,

ya que se decidió eliminar todas las líneas del segundo archivo que representasen puntos fuera del

espacio de muestreo del primer archivo. Estas líneas no serían utilizadas en los procesos posteriores,

pues la malla de puntos construida con el Voronoi Tessellation se genera sólo a partir del primer archivo.

Esto se corroboró ejecutando el VTMLE tanto con el segundo archivo de entrada original como con el

reducido, obteniendo exactamente los mismos resultados.

El segundo experimento fue para ver si el VTMLE ejecutado desde Hadoop se comporta de la misma

forma que el VTMLE ejecutado en forma secuencial. Para esto se ejecutó el VTMLE secuencial sobre la

totalidad de los datos, y se ejecutó Hadoop con una partición de una sola celda, obteniéndose resultados

idénticos. Para ver si el proceso de particionamiento afectaba o no el proceso general, se ejecutó el

VTMLE secuencial sobre el set de datos resultantes de un map. Se realizó con una partición de 2 celdas

Page 58: Paralelización de un Algoritmo para la Detección de Clusters de

58

sin overlap. Esta prueba arrojó como resultado archivos idénticos a los obtenidos con el software

paralelo.

Finalmente, se hizo un análisis de los resultados obtenidos por una partición de dos celdas sin overlap,

comparándose con la partición original de sólo uno. De ello se obtuvo la siguiente tabla de datos:

Tabla 1: Partición de dos celdas sin overlap

Celda 1 Celda 2 Ambas

Celdas

Partición

Original

N° de galaxias 45590 33156 78746 78746

N° de cúmulos 2487 1836 4323 4170

N° de cúmulos en la partición original 251 219 470

N° de galaxias en cúmulos 7306 5373 12679 11947

N° galaxias no repetidas en cúmulos 7207 5298 12505 11776

N° de galaxias en cúmulos de la

partición original

2339 2216 4555

El resultado de los experimentos muestra que el software paralelo es consistente con el software

secuencial, no modificando su comportamiento sino sólo paralelizándolo. Los resultados que obtienen

ambos software son altamente dependientes de las condiciones de borde que se le entrega al problema,

variando los cúmulos resultantes según el orden en que se vayan encontrando. Esto explica la baja

coincidencia entre las particiones de 1 y 2 celdas. Al igual que con los cúmulos de galaxias, al analizar las

galaxias que integran estos cúmulos también se encuentra una baja coincidencia entre las particiones.

Las galaxias “nuevas”, que no pertenecían a ningún cúmulo de la partición con una sola celda,

corresponden aproximadamente un 64% de las galaxias de la partición de dos celdas. Para validar este

experimento se verificó además que la partición de los datos correspondía a la totalidad de éstos y fuese

disjunta, al no haber coincidencias entre los datos de las celdas y al sumar entre ambas el mismo número

de líneas que el archivo original.

Una de las razones por la que las que tanto los cúmulos como las galaxias difieran al dividirse los datos,

es que la mayoría de los cúmulos poseen pocos elementos. Esto significa que a pesar que se encuentran

cúmulos, no hay grandes densidades de galaxias en algunas de las zonas donde los encuentran, por lo

Page 59: Paralelización de un Algoritmo para la Detección de Clusters de

59

que si se recorre de manera distinta, o se toma una densidad promedio distinta, se pueden encontrar

distintos cúmulos, en especial de los pequeños.

La tabla 2, adjuntada en el anexo, da cuenta de la distribución de la cantidad de cúmulos en función de

su tamaño. De aquella tabla se obtuvo el siguiente gráfico:

Figura 11: Cantidad de cúmulos de galaxias en función de su tamaño

En la Figura 11 se puede ver que la gran mayoría de los cúmulos tiene sólo 2 galaxias, y que la cantidad

de cúmulos disminuye abruptamente, siendo muy pocos los que tienen más de 6 galaxias. Se esperaba

encontrar resultados distintos al analizar los cúmulos que se repetían entre las particiones con una y dos

celdas, esperando una mayor coincidencia entre los cúmulos con más miembros, sin embargo los

resultados son similares. Estos se pueden observar en la tabla siguiente:

0

500

1000

1500

2000

2500

3000

2 4 6 8 10 12 14 16 18 21 24 26 28 40

Primer Cuadrante

Segundo Cuadrante

Original

Page 60: Paralelización de un Algoritmo para la Detección de Clusters de

60

Tabla 2: Cúmulos repetidos entre las particiones de una y dos celdas

Galaxias por cúmulo Cantidad de cúmulos

2 387

3 54

4 19

5 3

6 4

7 1

9 1

14 1

5.3. Desempeño

En esta sección se analiza el desempeño del software, tanto en uso de recursos como en el tiempo que

se demora, comparándolo con el software secuencial.

5.3.1. Uso de recursos

Las diferentes etapas de desarrollo del software se han probado con sólo una máquina, la que posee un

procesador de cuatro núcleos. Si bien se hicieron ejecuciones en paralelo, no sirve para establecer una

tendencia en el uso de recursos. Sólo se puede decir que dada la magnitud de las pruebas que se

hicieron, al duplicar los reducers, se duplican también nos núcleos utilizados, y el tiempo de ejecución se

reduce en aproximadamente la mitad.

Page 61: Paralelización de un Algoritmo para la Detección de Clusters de

61

Si bien se tuvo acceso a un clúster de máquinas, los nodos de éste compartían el disco duro. Por esta

razón no fue posible, ni tenía sentido, instalar el framework Hadoop, al no poderse trabajar con datos

distribuidos en nodos independientes.

5.3.2. Desempeño comparativo

Ejecutar un programa con Hadoop tiene un sobrecosto asociado a la coordinación y funcionamiento del

sistema distribuido. Esto hace que el desempeño y los costos en recursos computacionales varíen de

forma no lineal con el número de nodos destinados. Además existe un límite en que el tiempo de

procesamiento no va a disminuir al agregar más máquinas.

Experiencias de uso han mostrado que para grandes cantidades de datos Hadoop escala de forma lineal

al agregarse más nodos, siendo el sobrecosto de funcionamiento marginal, tal como se muestra en la

Figura 12. En esta se realizó un experimento simple, donde se computa el histograma de frecuencias

obtenidas por una expresión regular simple sobre un conjunto de datos de 350 GB. Sin embargo, si existe

un cuello de botella relacionado a restricciones en el procesamiento de datos, situación que ocurre al

paralelizar el VTMLE por las restricciones asociadas al tamaño de las celdas, Hadoop escala de forma

logarítimica como se muestra en la Figura 13. Este experimento muestra una iteración de un algoritmo

similar a k-means clustering. El análisis y ambos gráficos fueron obtenidos de un estudio que analiza la

escalabilidad de Hadoop en base a operaciones fáciles de paralelizar (16).

Page 62: Paralelización de un Algoritmo para la Detección de Clusters de

62

Figura 12: Información procesada en función del número de nodos

Figura 13: Información procesada en función del número de nodos, para una ejecución con restricciones

Page 63: Paralelización de un Algoritmo para la Detección de Clusters de

63

El análisis previo muestra que la comparación con un sistema secuencial sea compleja y pierda sentido al

enfocarse en sólo un aspecto a la vez. Claramente la ejecución en paralelo en general va a tomar menos

tiempo, pero va a gastar una mayor cantidad de recursos. Por otra parte, para una cantidad pequeña de

datos el sistema secuencial se va a comportar mejor.

También se pueden hacer comparaciones enfocadas en un área en particular, como por ejemplo: el

tiempo de ejecución, la escalabilidad, la cantidad máxima de datos que se pueden procesar, etc. No tiene

sentido comparar la escalabilidad y la cantidad máxima de datos que se pueden procesar, ya que sólo es

posible lograr buenos resultados con una aplicación distribuida, estando la lineal limitada en ambos

aspectos. Para comparar el tiempo de ejecución, se escribieron scripts para cada una de las pruebas que

se realizaron, donde se medía el tiempo de ejecución de los procesos en su totalidad. Se hicieron al

menos dos pruebas no consecutivas para cada uno de los procesos, no con el fin de obtener estadísticas,

sino simplemente verificar que estos resultados no fuesen accidentales, corroborando que el nuevo

tiempo obtenido estuviese dentro de un rango de cercanía.

Para ver el sobrecosto de la ejecución de scripts de python para el manejo de datos, se realizaron dos

pruebas:

Se ejecutó el script del Vocludet directamente, entregándose datos de entrada y recibiendo los

archivos de salida correspondientes. Esta prueba tomó un tiempo aproximado de 18 minutos.

Se ejecutó un script que entregaba los datos de entrada línea por línea al stdin del mapper, cuyo

resultado era entregado por el stdoud al stdin del reducer, el cual además de generar los

archivos de resultado también creaba uno utilizado para un posterior reensamblaje de

resultados. Es una ejecución similar a lo que haría Streaming, pero sin usar hadoop y con una

partición de sólo una celda. Esta prueba tomó alrededor de 19 minutos.

De los tiempos de ejecución se puede concluir que el sobrecosto del manejo de datos por parte de

python es bajo, si además se consideran las tareas de parear y crear archivos que no se realizaron en la

primera prueba.

Para ver el sobrecosto que significaba todo el aparataje asociado a hadoop (sistema de archivos,

redundancia de datos, sincronización y control, etc.), se hizo una tercera prueba:

Se ejecutó el programa en hadoop con una partición de sólo una celda, y por ende sin

paralelismo al estar trabajando con un solo núcleo. Esta prueba tomó aproximadamente 20

minutos en ejecutarse.

Page 64: Paralelización de un Algoritmo para la Detección de Clusters de

64

Del resultado de las pruebas anteriores se puede concluir que el sobrecosto en tiempo de hadoop es

menor, aunque no se sabe cuánto de este tiempo es constante y cuánto depende de la cantidad de datos

de entrada.

Luego se llevó a cabo una prueba para ver el incremento en eficiencia al ejecutarse hadoop con 2

núcleos:

Se creó una partición de los datos con dos celdas, y en la configuración se definió que se debían

utilizar 2 reducers. Esta prueba resultó en un tiempo total de 10 minutos.

Con este resultado se verificó que al duplicar la cantidad de procesadores, el tiempo tiende a reducirse a

la mitad. Además se comprobó que el tiempo de sobrecosto fijo pasa a ser secundario a pesar de que las

pruebas no sean tan intensivas en el uso de recursos. La división fue angular, por lo que la cantidad de

datos en cada celda fue similar y el tiempo pudo por ende reducirse a la mitad. De haber sido una

división radial, o alguna otra en la que la cantidad o dispersión de datos hubiese sido muy distinta, el

tiempo total estaría determinado por el procesamiento de datos en la celda de más carga.

Se hizo una cuarta prueba, esta vez usando hadoop con 4 reducers:

Se creó una partición de los datos en cuatro celdas, y se definió en la configuración que se

debían utilizar 4 reducers. El tiempo resultante fue de aproximadamente 10 minutos.

Si bien se esperaba que el tiempo disminuyese nuevamente a la mitad, se ve que a pesar de que se

incrementó la cantidad de reducers, la cantidad de procesadores utilizados siguió siendo dos. Esto se

debe a que la máquina usada tiene sólo cuatro núcleos, y al estar el sistema operativo ejecutando otros

procesos, no se pudieron asignar todos los recursos a hadoop.

Las pruebas anteriores no contemplaron el tiempo de re ensamblaje de los datos, por lo que hay que

agregarle este costo a una ejecución real. Sin embargo, cuando se llevó a cabo este proceso, la ejecución

duró del orden de unidades de segundos, por lo que no tiene mayor relevancia si el rango de error es de

minutos.

Page 65: Paralelización de un Algoritmo para la Detección de Clusters de

65

6. Conclusiones

A continuación se presentan las conclusiones agrupadas según los objetivos que se plantearon:

Se logró implementar un software que permite el análisis de datos astronómicos en forma

paralela. Para esto se utilizó el framework Hadoop en la partición de los datos, ejecución del

software detector de cúmulos de galaxias, y en la distribución de la carga de procesamiento.

Para el re ensamblaje de los resultados se utilizó un script escrito en Python. Con estas

herramientas se logró ejecutar el algoritmo VTMLE y reconstruir los resultados, pudiendo

además ejecutarse otros procesos astronómicos. Quedan propuestas herramientas para el re

ensamblado de otros procesos astronómicos que puedan ser útiles en un futuro. También queda

propuesto determinar el número óptimo de mappers y reducers, y la relación entre éstos y los

parámetros usados para la división de los datos.

Se diseñaron e implementaron 3 estrategias para el particionamiento de datos, dos de las cuales

sirven para paralelismo de menor escala, y una para paralelismo a gran escala. Se obtuvieron los

parámetros límites para esta última, y se determinó que dada la distribución de datos con la que

se trabajó, la cual no es homogénea, no es posible lograr un alto nivel de paralelismo. Queda

propuesta una partición ad-hoc para la distribución de datos existente, y el desarrollo de

estrategias basadas en esta última para la partición de otros sets de datos.

Se diseñaron 2 estrategias de re ensamblaje de datos, y se implementó una de estas. La

estrategia implementada trabaja correctamente sobre cúmulos sin repetición de elementos, sin

embargo no funciona de manera óptima con la implementación del algoritmo VTMLE utilizada,

pues ésta devuelve galaxias repetidas en varios cúmulos. Los cúmulos de galaxias resultantes

varían según la partición que se utilice, por lo que no se puede hacer una verdadera

comparación con el resultado del software secuencial.

Se verificó una mejora al software secuencial, al haberse logrado ejecuciones en paralelo que

dividieron el tiempo de procesamiento en 2. Es evidente que el tiempo se puede seguir

reduciendo al asignar más nodos de ejecución al problema. Queda propuesto ejecutar este

software en un clúster de computadores o con cloud computing, para medir las mejoras en

tiempo. También queda propuesta la ejecución de este software con sets de datos más grandes,

para medir la escalabilidad de éste.

Se proponen mejoras al software secuencial, implementando los cambios al algoritmo

propuestos en la sección 3.2.

Page 66: Paralelización de un Algoritmo para la Detección de Clusters de

66

7. Anexos

Tabla 3: Distribución de cúmulos por tamaño

Galaxias por

Cúmulo

Primera Celda Segunda Celda Original

2 1549 1137 2678

3 461 347 788

4 203 150 303

5 90 92 165

6 72 31 80

7 34 21 45

8 18 13 22

9 20 11 23

10 4 9 17

11 10 5 10

12 2 4 6

13 2 6 6

14 9 2 8

15 2 0 4

16 4 0 3

17 2 2 1

18 1 3 2

20 1 1 0

21 0 0 1

22 1 0 0

24 0 0 2

25 0 1 0

26 0 0 2

27 1 0 0

28 1 0 0

30 0 1 2

40 0 0 1

88

0 0 1

Page 67: Paralelización de un Algoritmo para la Detección de Clusters de

67

Mapper Function 2 celdas 10% de overlap

#!/usr/bin/env python

import sys

split_number = {'x':2, 'y':1, 'z':1}

min_val = {'x':2.57441, 'y':-0.10975, 'z':0.002}

max_val = {'x':3.88319, 'y':0.04363, 'z':0.2995}

max_dimensions = {'x':1000, 'y':100, 'z':1000}

overlap_perc = {'x':0.1, 'y':0.1, 'z':0.1}

x_overlap_val = ((max_val['x'] - min_val['x']) / split_number['x']) * overlap_perc['x']

y_overlap_val = ((max_val['y'] - min_val['y']) / split_number['y']) * overlap_perc['y']

z_overlap_val = ((max_val['z'] - min_val['z']) / split_number['z']) * overlap_perc['z']

overlap_val = {'x':x_overlap_val, 'y':y_overlap_val, 'z':z_overlap_val}

#columns with the x, y and z values fron the 2dFNGgals file

col_2d = [0, 1, 2]

#columns with the x, y and z values fron the best.observations file

col_ob = [4, 5, 6]

x_ponderator = split_number['x'] / (max_val['x'] - min_val['x'])

y_ponderator = split_number['y'] / (max_val['y'] - min_val['y'])

z_ponderator = split_number['z'] / (max_val['z'] - min_val['z'])

ponderator = {'x':x_ponderator, 'y':y_ponderator, 'z':z_ponderator}

def get_quadrant(val, coord):

list = []

plus_val = val + overlap_val[coord]

minus_val = val - overlap_val[coord]

quad = int((val - min_val[coord]) * ponderator[coord])

quad_plus = int((plus_val - min_val[coord]) * ponderator[coord])

quad_minus = int((minus_val - min_val[coord]) * ponderator[coord])

#correct the max vals problem (max vals get their own cell)

if val == max_val[coord]:

quad -=1

Page 68: Paralelización de un Algoritmo para la Detección de Clusters de

68

list.append(quad)

#if the values are out of the min and max range

if plus_val < max_val[coord] :

list.append(quad_plus)

if minus_val > min_val[coord] :

list.append(quad_minus)

return set(list)

# input comes from STDIN (standard input)

for line in sys.stdin:

# remove leading and trailing whitespace

line = line.strip()

#added cast to coords[n]

coords = line.split()

#if the input is from the 2dFNGgals file

if len(coords) == 8:

coord_x = float(coords[col_2d[0]])

coord_y = float(coords[col_2d[1]])

coord_z = float(coords[col_2d[2]])

coord = {'x':coord_x, 'y':coord_y, 'z':coord_z}

#if the input is from the best.observations file

elif len(coords) == 12:

coord_x = float(coords[col_ob[0]])

coord_y = float(coords[col_ob[1]])

coord_z = float(coords[col_ob[2]])

coord = {'x':coord_x, 'y':coord_y, 'z':coord_z}

else:

continue

#if the values are out of the min and max range

if coord['x'] > max_val['x'] or coord['x'] < min_val['x'] or coord['y'] > max_val['y'] or coord['y'] <

min_val['y'] or coord['z'] > max_val['z'] or coord['z'] < min_val['z']:

continue

quadrants = {}

quadrants['x'] = get_quadrant(coord['x'], 'x')

quadrants['y'] = get_quadrant(coord['y'], 'y')

quadrants['z'] = get_quadrant(coord['z'], 'z')

all_quadrants = []

Page 69: Paralelización de un Algoritmo para la Detección de Clusters de

69

for x in quadrants['x'] :

for y in quadrants['y'] :

for z in quadrants['z'] :

all_quadrants.append(`x`+','+`y`+','+`z`)

#print all quadrants to output

for quadrant in all_quadrants :

print '%s\t%s' % (quadrant, line)

Page 70: Paralelización de un Algoritmo para la Detección de Clusters de

70

Re Assembly Function

def merge_clusters(file1_path, file2_path) :

#----------------- create hash table with positions from the first file ------------------

#read the first gid file

file1 = open(file1_path, 'r')

#hash table with {position : (line_number, number_of_elements)}

table = {}

#list of line numbers with invalid clusters

invalid_clusters = []

#line number counter

line_num = 0

for line in file1 :

# remove leading and trailing whitespace

line = line.strip()

# parse the line

split = line.split()

#add the list of elements to the table

for elem in split :

#{pos : (line, numElems)}

table[elem] = [line_num, len(split)]

#increment line number counter

line_num += 1

#-------- read second file and find intersection of elements between both sets of clusters ---------

#open the second file

file2 = open(file2_path, 'r')

#create a new file for writing the merged result

merged_file = open('merged_file', 'w')

#compare new elements in a double for

for line in file2 :

#boolean for determinig validity of cluster

valid_cluster = True

# remove leading and trailing whitespace

line = line.strip()

# parse the line

split = line.split()

#check for repetition

for elem in split :

#if the element is part of another cluster

Page 71: Paralelización de un Algoritmo para la Detección de Clusters de

71

if table.has_key(elem) :

#if the cluster isn't already eliminated

if invalid_clusters.count(table[elem][1]) == 0 :

#if the cluster in file2 is larger than the one in file1

if len(split) > table[elem][1] :

#discard the cluster in file1

invalid_clusters.append(table[elem][0])

#no need to eliminate every element with that line number

#if the cluster in file1 is larger than the one in file2

else:

#eliminate the whole cluster

valid_cluster = False

break

#if none of the elements were already part of another cluster

if valid_cluster :

#write line in the merged file

merged_file.write(line + '\n')

#-------------------------- write valid clusters from file1 --------------------------

#file with clusters

file1 = open(file1_path, 'r')

#line number counter

line_num = 0

#for every cluster in file1

for line in file1 :

#if the cluster is valid

if invalid_clusters.count(line_num) == 0 :

#write cluster in the merged file

merged_file.write(line.strip() + '\n')

#increment counter

line_num += 1

Page 72: Paralelización de un Algoritmo para la Detección de Clusters de

72

8. Bibliografía

1. Okabe. Spatial Tessellations. s.l. : John Wiley & Sons, 2000.

2. Pizarro, Daniel. Galaxy Cluster Detection Using Nonparametric Maximum Likelihood Estimation of

Features in Voronoi Tessellations. 2007, Master thesis in computer science, University of Chile.

3. Pizarro, Daniel, Hitschfeld, Nancy & Campusano, Luis. Clustering of 3D Spatial Points Using Maximum

Likelihood Estimator over Voronoi Tessellations: Study of the Galaxy Distribution in Redshift Space. 2006,

IEEE Computer Society.

4. Large Synoptic Survey Telescope. http://www.lsst.org/lsst/faq.

5. Colless, Matthew. 2dFGRS an Introduction.

http://www2.aao.gov.au/~TDFgg/Public/Survey/description.html.

6. Intel. Excerpts from A Conversation with Gordon Moore: Moore's Law. 2005.

http://download.intel.com/museum/Moores_law/Video-

transcripts/excepts_a_Conversation_with_gordon_Moore.pdf.

7. Adve, Sarita V., Adve, Vikram S. & Agha, Gul. Parallel Computing Research at Illinois The UPCRC

Agenda. 2008. http://www.upcrc.illinois.edu/UPCRC_Whitepaper.pdf.

8. Yahoo! Inc. Yahoo! Hadoop Tutorial. Yahoo! Developer Network.

http://developer.yahoo.com/hadoop/tutorial/.

9. Voit, G. Mark. Tracing cosmic evolution with clusters of galaxies. 2004.

10. Shankland, Stephen. news.cnet.com. http://news.cnet.com/8301-10784_3-9955184-7.html.

11. Wiley, Keith. Astronomical Image Processing With Hadoop. http://escience.washington.edu/get-

help-now/astronomical-image-processing-hadoop.

12. Amazon Web Services. Amazon Web Services Blog. http://aws.typepad.com/aws/2008/02/taking-

massive.html.

13. Goodman, Jacob & O'Rourke, Joseph. Handbook of Discrete and Computational Geometry. 2004.

Page 73: Paralelización de un Algoritmo para la Detección de Clusters de

73

14. Ghemawat, Sanjay, Gobioff, Howard & Leung, Shun-Tak. The Google File System.

http://static.googleusercontent.com/external_content/untrusted_dlcp/labs.google.com/en//papers/gfs-

sosp2003.pdf.

15. Virtual Observatory India. http://vo.iucaa.ernet.in/2df/Survey/description.html.

16. Papadimitriou, Spiros. bitquill. 2008. http://www.bitquill.net/blog/?p=17.