El hecho de trabajar con grandes volúmenes de datos, hizo que gran parte del sistema esté enfocado en minimizar los costos de operaciones entre los datos. Para esto, se planteó un sistema externo, que permite transformar los datos para que estos puedan ser operados de manera más eficiente.
Este sistema, conocido como Data Transformation System o por su acrónimo DTS, es un conjunto de objetos y utilidades que permite la automatización de operaciones de extracción, transformación y carga para o desde una base de datos. Los objetos son paquetes DTS y sus componente y utilidades son llamados DTS Tools.
Figura 15. Interacción entre el sistema de recomendación y el DTS
En la Figura 15 se muestra la interacción entre el sistema de transformación de datos y el sistema de recomendación.
En un principio, el sistema de recomendación, no contaba con esta implementación de transformación de datos, lo que fue sumamente costoso ya que se manejaban millones de registros operados a través de un simple data set. El motivo de esta implementación fue la ineficiencia en las operaciones que incluyen gran cantidad de datos. Debido a la gran cantidad de operaciones, es sumamente crítico en cuanto a rendimiento y recursos las decisiones que se tomen tanto a nivel de diseño como de implementación.
Con el objetivo de reducir estos tiempo de operaciones, se realizó el sistema DTS, que hizo que disminuyeran significativamente los tiempos y recursos utilizados. La transformación de datos, es un proceso costoso en cuanto a tiempos iniciales, pero gracias al uso de una red estática (dataset) nos permitió realizar una
transformación masiva de los datos a una estructura más efectiva, la cual será empleada para cualquier tipo de operación.
Este sistema, como se dijo anteriormente, realiza una transformación de datos a estructuras más eficientes. Agregado a esto, realiza cálculos para cada usuario en la red, como son cantidades de seguidores, cantidad de réplicas, menciones, etc, con el objetivo de reducir las operaciones en tiempo de ejecución. La nueva estructura,
permite acceder de manera directa a cálculos que con la estructura inicial demandaban innecesariamente recursos y tiempo de procesamiento.
Figura 16. Estructura de archivo inicial, y estructura de tabla final
En la Figura 16, se intenta ilustrar mediante un ejemplo, cómo se reducen los tiempos de procesamiento a través de la nueva estructura generada por el DTS.
La misma analogía puede ser usada para las relaciones de mentions, replies, retweets, etc. Obteniendo cuántas menciones hizo y cuántas le hicieron a un
determinado usuario, si de menciones se tratase. También, se realizaron cálculos de categorización de usuarios, lo que ayuda a determinar a qué categoría pertenece un determinado usuario sin realizar el cálculo cada vez que se necesite saber la misma.
Si bien esta implementación reduce de manera considerable el tiempo de cálculo, toda la información de las distintas relaciones será almacenada en una única entidad, la cual va ser almacenada en memoria.
La Figura 17, hace referencia a la clase ‘User’, de la cual se cargaran cientos de miles de instancias en memoria. Estos objetos serán mapeados mediante el framework Hibernate, que permite tener un mapeo directo objeto-relacional (ORM). En este caso el mapeo de atributos entre la estructura resultante del DTS y nuestra entidad ‘User’.
Figura 17. Entidad User para mapeo ORM
La entidad contiene, por cada usuario, los resultados de los cálculos hechos entre los archivos del dataset. Cada columna de la entidad contiene la cantidad de seguidores, cantidad de personas que sigue, número de replicas/mentions/retweets hechas por y hacia el usuario, de manera que con la este esquema se reduce de cálculos complejos, a una consulta directa de base de datos.
Pese a esta gran ventaja, el hecho de manejar un objeto más complejo, produce un tradeoff entre tiempos de procesamiento y el almacenamiento en memoria. Cuando un programa o algoritmo compensa el uso de tiempo con espacio se lo conoce como space-time or time-memory tradeoff.
Para atacar el problema de espacio en memoria se retrasó el uso de esta clase hasta que fuese estrictamente necesario realizar cálculos con los datos de cantidad de
menciones, replies, etc. En su lugar, se usó una collection haciendo sólo referencia al identificador del usuario (id de la clase User).
Imaginemos que obtenemos la lista de los seguidores del usuario U T con 200 mil seguidores.
Figura 18. Lista de seguidores del usuario U T
User
1User
2User
3 . . . .User
20000
Simplificaremos cada objeto ‘User’ de la lista a un String (user_id) y ocho Integers (followers, followees, replies_to, etc).
Dejando de lado factores como la arquitectura y la JVM de java, para un objeto de tipo String se requiere 20+(n/2)*4 bytes de memoria, siendo n la cantidad de
caracteres del objeto, y 4 Bytes para un objeto tipo Integer. Supondremos un
identificador standard de 4 caracteres para la identificación del usuario y simplificando su cálculo a (n/2)*4 tendremos:
String = 8 Bytes Integer = 4 bytes
User = 8 bytes + 32 bytes = 40 bytes.
El espacio para manejar una lista con 200 mil elementos sera superior a 8 Mb.
Imaginemos ahora que cada objeto usuario es representado únicamente por su identificador, como muestra la Figura 19.
Figura 19. Lista de ids de seguidores del usuario U T
user_id
1user_id
2user_id
3 . . . .user_id
20000Cada identificador ocupará el tamaño de un String. De la misma manera que para el cálculo del objeto ‘User’ tendremos que cada objeto ocupa 8 bytes de memoria. Por lo que la lista se reducirá a 1,6 Mb. En conclusión, podemos decir que este enfoque reduce el uso de memoria significativamente.
4.2.2 Service Layer
Dado que la implementación del DTS permite únicamente la comunicación con nuestro dataset, es decir, no podría establecer comunicación con otro Data Source, lo que podría ser otro formato de dataset, o la misma API de Twitter, se creó una capa intermedia que establece las operaciones por las cuales se dará la comunicación.
Gracias a esta capa, se tiene una abstracción, que permite cambiar la fuente inicial de información e implementando una interface se pueda establecer una comunicación con otras fuentes evitando el uso del DTS. Si bien el hecho de poder comunicarse directamente con la API de twitter sin pasar por el sistema de transformación de datos aporta una mayor flexibilidad, se pierde el aporte de rendimiento obtenido por el DTS, pasándole toda la responsabilidad a la API que se esté implementando. Para el caso de twitter, es muy poco práctico dado a las grandes limitaciones que tiene en cuanto a cantidad de request por tiempo que se puede pedir a la red.