Este es uno de los proyectos de investigación por los que estoy pasando. El requisito es casi exactamente como el tuyo y hemos desarrollado buenos algoritmos para resolver el problema.
La entrada
La entrada es un flujo interminable de palabras o frases en inglés (las llamamos tokens
).
La salida
- Salida de los primeros N tokens que hemos visto hasta ahora (¡de todos los tokens que hemos visto!)
- Genere los primeros N tokens en una ventana histórica, por ejemplo, el último día o la semana pasada.
Una aplicación de esta investigación es encontrar el tema candente o las tendencias del tema en Twitter o Facebook. Tenemos un rastreador que rastrea en el sitio web, lo que genera un flujo de palabras, que se alimentará en el sistema. A continuación, el sistema generará las palabras o frases de máxima frecuencia, ya sea en general o históricamente. Imagínense que en las últimas semanas la frase "Copa del Mundo" aparecería muchas veces en Twitter. También lo hace "Paul el pulpo". :)
Cadena en enteros
El sistema tiene un ID entero para cada palabra. Aunque hay casi infinitas palabras posibles en Internet, pero después de acumular un gran conjunto de palabras, la posibilidad de encontrar nuevas palabras es cada vez menor. Ya hemos encontrado 4 millones de palabras diferentes y hemos asignado una identificación única para cada una. Todo este conjunto de datos se puede cargar en la memoria como una tabla hash, consumiendo aproximadamente 300 MB de memoria. (Hemos implementado nuestra propia tabla hash. La implementación de Java requiere una gran sobrecarga de memoria)
Entonces, cada frase puede identificarse como una matriz de números enteros.
Esto es importante, porque ordenar y comparar números enteros es mucho más rápido que en cadenas.
Archivar datos
El sistema mantiene los datos de archivo de cada token. Básicamente son pares de (Token, Frequency)
. Sin embargo, la tabla que almacena los datos sería tan grande que tendríamos que particionar la tabla físicamente. Una vez que el esquema de partición se basa en ngramas del token. Si la ficha es una sola palabra, es 1 gramo. Si la ficha es una frase de dos palabras, es 2 gramos. Y esto continúa. Aproximadamente en 4 gramos tenemos mil millones de registros, con un tamaño de tabla de alrededor de 60 GB.
Procesamiento de transmisiones entrantes
El sistema absorberá las oraciones entrantes hasta que la memoria se utilice por completo (Sí, necesitamos un MemoryManager). Después de tomar N oraciones y almacenarlas en la memoria, el sistema hace una pausa y comienza a convertir cada oración en palabras y frases. Se cuenta cada ficha (palabra o frase).
Para tokens muy frecuentes, siempre se guardan en la memoria. Para los tokens menos frecuentes, se ordenan en función de los ID (recuerde que traducimos la Cadena en una matriz de números enteros) y se serializan en un archivo de disco.
(Sin embargo, para su problema, dado que solo está contando palabras, puede poner todo el mapa de frecuencia de palabras solo en la memoria. Una estructura de datos cuidadosamente diseñada consumiría solo 300 MB de memoria para 4 millones de palabras diferentes. Alguna sugerencia: use ASCII char para representan cadenas), y esto es muy aceptable.
Mientras tanto, habrá otro proceso que se activará una vez que encuentre cualquier archivo de disco generado por el sistema, luego comenzará a fusionarlo. Dado que el archivo de disco está ordenado, la combinación requeriría un proceso similar como la ordenación por combinación. También hay que tener cuidado con algunos diseños aquí, ya que queremos evitar demasiadas búsquedas de disco aleatorias. La idea es evitar la lectura (proceso de fusión) / escritura (salida del sistema) al mismo tiempo, y dejar que el proceso de fusión se lea desde un disco mientras se escribe en un disco diferente. Esto es similar a implementar un bloqueo.
Fin del día
Al final del día, el sistema tendrá muchos tokens frecuentes con frecuencia almacenados en la memoria y muchos otros tokens menos frecuentes almacenados en varios archivos de disco (y cada archivo está ordenado).
El sistema vacía el mapa en memoria en un archivo de disco (ordénelo). Ahora, el problema se convierte en fusionar un conjunto de archivos de disco ordenados. Usando un proceso similar, obtendríamos un archivo de disco ordenado al final.
Luego, la tarea final es fusionar el archivo de disco ordenado en la base de datos de archivo. Depende del tamaño de la base de datos del archivo, el algoritmo funciona como se muestra a continuación si es lo suficientemente grande:
for each record in sorted disk file
update archive database by increasing frequency
if rowcount == 0 then put the record into a list
end for
for each record in the list of having rowcount == 0
insert into archive database
end for
La intuición es que después de algún tiempo, el número de inserciones será cada vez menor. Cada vez más operaciones se realizarán solo en la actualización. Y esta actualización no será penalizada por index.
Espero que toda esta explicación ayude. :)
what is the most frequent item in the subsequence [2; 2; 3; 3; 3; 4; 4; 4; 4; 5; 5] of your sequence?