Aumento del performance en el procesamiento de text

He escrito un progtwig que indica todas las instancias de una class de palabra deseada en un text. Así es como lo hago:

  • Haz una selección de palabras de todo el text

  • Iterar esta matriz Para cada palabra, mira cuál es su primera letra.

    • Salta a la matriz correspondiente en un object de todas las palabras de la class de palabra seleccionada (por ejemplo, "S") y repárelo. Rompe si se encuentra la palabra e introdúcela en una serie de coincidencias.
  • Después de que se marcan todas las palabras, itere la matriz de coincidencias y resalte cada una en el text.

Un text que consta de 240000 palabras se procesa en 100 segundos con respecto a los sustantivos y aproximadamente 4,5 segundos con respecto a las preposiciones en mi máquina.

Estoy buscando una manera de mejorar el performance y esas son las ideas que podría encontrar:

  • Reorganiza los elementos en cada bloque de mi list de palabras. Ordénelos de manera que si la palabra comienza con una voz, todos los elementos que tienen una consonante como segundo carácter aparecen primero y viceversa. (en el supuesto de que las palabras con vocales dobles o consonantes son raras)
  • Estructure el text en capítulos y procese solo el capítulo mostrado actualmente.

¿Son esas ideas sólidas y hay más ideas o técnicas comprobadas para mejorar este tipo de procesamiento?

Usa el poder de javascript.

Manipula dictionarys con keys de cadena como una operación fundamental. Para cada class de palabra, crea un object con cada palabra posible como key y un valor simple como verdadero o 1. Luego, verificando cada palabra es simplemente typeof(wordClass[word]) !== "undefined" . Espero que esto sea mucho más rápido.

Las expresiones regulares son otra área altamente optimizada de Javascript. Probablemente pueda hacer todo el process como una expresión regular masiva para cada class de palabra. Si su resaltado está en HTML, entonces también puede usar un reemploop en el RE para get el resultado. Es probable que este trabajo dependa de cuán grande sea el set de palabras.

La solución que propongo es implementar una estructura de datos trie . Requiere más esfuerzo implementarlo, pero tiene varias ventajas sobre una tabla hash (dictionary).

Buscar datos en un trie llevará, como máximo, O ( k ) time, donde k es la longitud de la cadena de búsqueda. Con una tabla hash, el almacenamiento de cada palabra como una key podría funcionar, pero ¿qué es lo que está almacenando como el valor de esa key en la tabla? Las tablas hash no me parecen muy eficientes para este problema.

Además, un trie puede proporcionar el order alfabético de sus inputs key de forma nativa a través del recorrido previo a la order. Una tabla hash no puede. Para orderar sus keys, debe implementar una function de orderación por su count, que solo agrega más time y espacio.

Si sigues leyendo en los bashs, te encontrarás con treees de sufijos y treees de raíz , que abordan el problema exacto que estás tratando de resolver. Entonces, en cierto sentido, estás reinventando la rueda, pero no estoy afirmando que sea algo malo. Aprender esto te hace un mejor progtwigdor.

Podemos implementar un trie simple como un set de nodos conectados que almacena tres elementos de información: 1) un símbolo (carácter), 2) un puntero al primer hijo de este nodo, y 3) un puntero al siguiente hijo del nodo padre .

 class TrieNode { constructor(symbol) { this.symbol = symbol; this.child = null; this.next = null; } } 

Luego puedes build una networking de palabras, unidas por cada letra de la palabra. Las palabras que comparten el mismo prefijo se vinculan de forma nativa a través del niño y los pointers siguientes, por lo que la búsqueda es bastante rápida. Te animo a que busques más en los bashs. Son estructuras de datos limpias y creo que se adapta mejor a tu problema.

Creo que los pasos que cuestan un alto time computacional serían:

  • Buscando una palabra en particular en el contenedor de class mundial.
  • Resaltando las coincidencias en el documento de origen.

Por lo tanto, propondría una estructura de datos más eficiente para almacenar su contenedor de class de palabras y la list de coincidencias . Entonces la búsqueda y búsqueda se ejecuta más rápido.

Si entiendo su problema correctamente, solo desea resaltar aquellas palabras que están en la list de class mundial . Entonces propondría Bloom Filter, que hace este trabajo de manera sobresaliente.

http://en.wikipedia.org/wiki/Bloom_filter

Bloom Filter es un contenedor de set en el que puede almacenar cualquier elemento (palabras) y comprobar si ya hay alguna palabra nueva en este set. La velocidad es increíblemente rápida y se adapta bien al procesamiento de datos grandes.

Los casos de uso serían:

  • Usted almacena las classs de palabras en un Bloom Filter, vamos a llamarlo bfWordClass .
  • Itere a través de la list de las palabras extraídas, compruebe si cada palabra es miembro de bfWordClass (Esta operación es extremadamente rápida y 100% precisa).
  • Si la palabra pertenece a bfWordClass , busque el text y resáltelos. Puede considerar otra estructura de datos para almacenar las palabras únicas extraídas del documento y todos los índices encontrados en el documento para una reference más rápida.
  • Use los primeros 3 caracteres como key, no como primer carácter.
  • Descarga tu trabajo a muchos hilos de background
  • Procesar text visible primero

De hecho, 2,40,000 palabras son un gran dato para procesar en el lado del cliente, esto creará problemas de performance tanto en javascript como en DOM cuando resaltes el text. Intente procesar un set más pequeño si es posible, como páginas o párrafos o secciones.

Si puede o no puede networkingucir su set activo de palabras, aquí hay algunas optimizaciones que puede intentar para el procesamiento de su text:

Almacenar el text en DOM

Puedes probar dos enfoques aquí:

  1. Elemento DOM único que contiene todo el text, es decir, 240k palabras
  2. Múltiples elementos DOM que contienen cada uno N palabras, digamos 240 elementos con 1000 palabras cada uno.

Tendrás que usar herramientas como jsPerf , para ver qué tan rápido están los cambios innerHTML en ambos enfoques, es decir, replace un gran HTML interno o text en un solo elemento DOM versus replace múltiplesHTML internos de elementos DOM coincidentes.

Coincidencia: resaltar palabras cuando han sido completamente tipadas

Por ejemplo, desea resaltar "Javascript" y "text" en su text después de haber sido escritos completamente. En este caso, como se mencionó en @DrC, preprocesar el text para almacenar la key frente a los datos sería una buena idea. Genere una key para la palabra (puede querer normalizar la key en caso de que quiera hacer coincidir mayúsculas y minúsculas o ignorar caracteres especiales, etc., es decir, 'nosql' será la key para 'NoSQL' o 'NOSQL' o 'No-SQL `. Tu object de búsqueda se verá así:

 { 'nosql': {'matches':[{'NoSQL':3},{'NOSQL':6}], // indexes of strings where this occurs } 

cada vez que se busca una palabra, se genera la key para search índices de todas las coincidencias y se resalta el text.

Coincidencia: resaltar palabras a medida que se escriben Para este enfoque, necesitaría una estructura basada en trie creada en el object javascript. Otro enfoque sería generar y comstackr expresiones regulares en function de la cadena actual, por ejemplo, si el usuario tiene el tipo 'jav' la expresión regular sería \jav\gi y hacer una coincidencia de expresiones regulares en todo el text. Ambos enfoques necesitarían una comparación de performance

Haría algo así.

HTML

 <section id="text">All keywords in this sentence will be marked</section> 

JavaScript

 element = document.getElementId('text'); text = element.innerHTML; array_of_keywords = ['keyword', 'will']; eval('text = text.replace(/(' + array_of_keywords.join('|') + ')/g, "<mark>\$1</mark>");'); element.innerHTML = text;