tutorial icon example create java database matlab large-data

java - icon - ¿Cómo puedo analizar ~ 13GB de datos?



set border jpanel java (4)

Es muy probable que tenga un problema que se pueda resolver con NOSQL y tecnologías distribuidas.

i) Escribiría un sistema distribuido utilizando Hadoop / HBase.

ii) Alquile varias máquinas de decenas / cientos de AWS, pero solo por unos segundos (todavía le costará menos de $ 0.50)

iii) Beneficio !!!

Tengo ~ 300 archivos de texto que contienen datos en rastreadores, torrents y compañeros. Cada archivo está organizado de esta manera:

tracker.txt

time torrent time peer time peer ... time torrent ...

Tengo varios archivos por rastreador y gran parte de la información se repite (la misma información, hora diferente).

Me gustaría poder analizar lo que tengo e informar estadísticas sobre cosas como

  • Cuántos torrents hay en cada rastreador
  • ¿Cuántos rastreadores están listados en torrents?
  • ¿Cuántos compañeros tienen los torrentes?
  • ¿Cuántos torrentes tienen los compañeros?

La gran cantidad de datos me está dificultando esto. Esto es lo que he intentado.

MySQL

Pongo todo en una base de datos; una tabla por tipo de entidad y tablas para mantener las relaciones (por ejemplo, este torrent está en este rastreador).

Agregar la información a la base de datos fue lento (y no tenía 13 GB cuando intenté esto), pero analizar las relaciones después fue un no-go. Todas las consultas levemente complejas tardaron más de 24 horas en completarse (en todo caso).

Una consulta de ejemplo sería:

SELECT COUNT(DISTINCT torrent) FROM TorrentAtPeer, Peer WHERE TorrentAtPeer.peer = Peer.id GROUP BY Peer.ip;

Intenté subir las asignaciones de memoria en mi archivo my.cnf pero no pareció ayudar. Utilicé el archivo de configuración my-innodb-heavy-4G.cnf .

EDITAR: Agregar detalles de la tabla

Esto es lo que estaba usando:

Peer Torrent Tracker ----------- ----------------------- ------------------ id (bigint) id (bigint) id (bigint) ip* (int) infohash* (varchar(40)) url (varchar(255)) port (int) TorrentAtPeer TorrentAtTracker ----------------- ---------------- id (bigint) id (bigint) torrent* (bigint) torrent* (bigint) peer* (bigint) tracker* (bigint) time (int) time (int) *indexed field. Navicat reports them as being of normal type and Btree method. id - Always the primary key

No hay claves foráneas. Tenía confianza en mi capacidad de usar solo las ID que correspondían a las entidades existentes, y agregar una verificación de clave externa parecía un retraso innecesario. ¿Esto es ingenuo?

Matlab

Esto parecía una aplicación que fue diseñada para un trabajo pesado, pero no pude asignar suficiente memoria para almacenar todos los datos de una sola vez.

No tenía datos numéricos, por lo que estaba usando arreglos de celdas, pasé de estos a intentos en un esfuerzo por reducir la huella. No pude hacerlo funcionar.

Java

Mi intento más exitoso hasta ahora. Encontré una implementación de Patricia Tries provista por la gente de Limewire. Usando esto, pude leer los datos y contar cuántas entidades únicas tenía:

  • 13 seguidores
  • 1.7mil torrents
  • 32mil compañeros

Todavía me resulta muy difícil calcular las frecuencias de la cantidad de torrentes en los compañeros. Estoy intentando hacerlo construyendo intentos como este:

Trie<String, Trie<String, Object>> peers = new Trie<String, Trie<String, Object>>(...); for (String line : file) { if (containsTorrent(line)) { infohash = getInfohash(line); } else if (containsPeer(line)) { Trie<String, Object> torrents = peers.get(getPeer(line)); torrents.put(infohash, null); } }

Por lo que he podido hacer hasta ahora, si puedo hacer que se construyan estos peers , puedo descubrir fácilmente cuántos torrentes hay en cada uno. Lo ejecuté todo ayer y cuando regresé noté que no se iba a escribir el archivo de registro, I ^Z la aplicación y la time informaron lo siguiente:

real 565m41.479s user 0m0.001s sys 0m0.019s

Esto no me parece correcto, ¿el usuario y el sistema deberían ser tan bajos? Debo mencionar que también he aumentado el tamaño de pila de la JVM a 7 GB (máximo y de inicio), sin eso, rápidamente obtengo un error de falta de memoria.

No me importa esperar durante varias horas / días, pero parece que la cosa se detiene al cabo de unas 10 horas.

Supongo que mi pregunta es, ¿cómo puedo analizar estos datos? ¿Son las cosas que he probado las cosas correctas? ¿Hay cosas que me estoy perdiendo? La solución de Java parece ser la mejor hasta ahora, ¿hay algo que pueda hacer para que funcione?


Le daría a MySQL otro intento pero con un esquema diferente:

  • no utilice las columnas de ID aquí
  • Utilice claves primarias naturales aquí:

    Peer : ip, puerto
    Torrent : infohash
    Rastreador : url
    TorrentPeer : peer_ip, torrent_infohash, peer_port, time
    TorrentTracker : tracker_url, torrent_infohash, tiempo

  • usar el motor innoDB para todas las tablas

Esto tiene varias ventajas:

  • InnoDB utiliza índices agrupados para la clave principal. Significa que todos los datos se pueden recuperar directamente del índice sin una búsqueda adicional cuando solo solicita datos de las columnas de clave principal. Así que las tablas InnoDB son en cierto modo tablas organizadas por índices.
  • Tamaño más pequeño ya que no tiene que almacenar las claves sustitutas. -> Velocidad, porque menor IO para los mismos resultados.
  • Es posible que pueda hacer algunas consultas ahora sin usar uniones (caras), porque usa claves primarias y externas naturales. Por ejemplo, la tabla de vinculación TorrentAtPeer contiene directamente la peer ip como clave externa a la tabla peer. Si necesita consultar los torrentes utilizados por los pares en una subred, ahora puede hacer esto sin usar una unión, porque todos los datos relevantes se encuentran en la tabla de vinculación.

Si desea el recuento de torrentes por igual y también desea la ip del igual en los resultados, nuevamente tenemos una ventaja cuando usamos claves primarias / externas naturales aquí.

Con tu esquema tienes que unirte para recuperar la ip:

SELECT Peer.ip, COUNT(DISTINCT torrent) FROM TorrentAtPeer, Peer WHERE TorrentAtPeer.peer = Peer.id GROUP BY Peer.ip;

Con claves primarias / extranjeras naturales:

SELECT peer_ip, COUNT(DISTINCT torrent) FROM TorrentAtPeer GROUP BY peer_ip;

EDITAR Bien, el esquema original publicado no era el real. Ahora la tabla de Peer tiene un campo de port . Yo sugeriría usar la clave principal (ip, puerto) aquí y aún así soltar la columna de identificación. Esto también significa que la tabla de vinculación debe tener claves externas de varias columnas. Ajustó la respuesta ...


Si pudieras usar C ++, deberías echar un vistazo al peso mosca Boost .

Con el uso de flyweight, puede escribir su código como si tuviera cadenas, pero cada instancia de una cadena (el nombre de su rastreador, etc.) utiliza solo el tamaño de un puntero.

Independientemente del idioma, debe convertir la dirección IP a un int (lea esta pregunta ) para ahorrar más memoria.


Usted declara que sus consultas de MySQL tomaron demasiado tiempo. ¿Se ha asegurado de que existan los índices adecuados para respaldar el tipo de solicitud que envió? En su ejemplo, ese sería un índice para Peer.ip (o incluso un índice anidado (Peer.ip,Peer.id) ) y un índice para TorrentAtPeer.peer .

Como entiendo los resultados de Java, tiene muchos datos pero no tantas cadenas diferentes. Por lo tanto, quizás pueda ahorrar algo de tiempo asignando un número único a cada rastreador, torrent y igual. Usando una tabla para cada uno, con un valor indexado que contiene la cadena y una clave primaria numérica como la identificación. De esa manera, todas las tablas que relacionan estas entidades solo tendrían que lidiar con esos números, lo que podría ahorrar mucho espacio y hacer sus operaciones mucho más rápidas.