Uso de SQL para determinar las estadísticas de palabras de conteo de un campo de texto
-
09-09-2019 - |
Pregunta
Hace poco he estado trabajando en algunas funciones de búsqueda de base de datos y quería obtener alguna información como las palabras promedio por documento (campo de texto, por ejemplo, en la base de datos). La única cosa que he encontrado hasta el momento (sin procesamiento en el idioma de su elección fuera de la DB) es:
SELECT AVG(LENGTH(content) - LENGTH(REPLACE(content, ' ', '')) + 1)
FROM documents
Esto parece funcionar * pero no tiene otras sugerencias? Actualmente estoy usando MySQL 4 (espero que para mover a la versión 5 para esta aplicación en breve), pero también estoy interesado en soluciones generales.
Gracias!
* Me puedo imaginar que esta es una manera bastante duro para determinar esto, ya que no tiene en cuenta el contenido HTML en y similares también. Eso está bien para este proyecto en particular, pero de nuevo ¿Hay mejores maneras?
Actualización: Para definir lo que quiero decir con "mejor": ya sea más preciso, lleva a cabo de manera más eficiente, o es más (de fácil mantenimiento, buenas prácticas, etc.) "correcta". Para el contenido que tengo disponible, la consulta anterior es lo suficientemente rápido y es exacta para este proyecto, pero puede necesitar algo similar en el futuro (por lo que se solicita).
Solución
Las capacidades de manejo de texto de MySQL no son lo suficientemente buenos para lo que quieres. Una función almacenada es una opción, pero probablemente será lenta. Su mejor opción para procesar los datos dentro de MySQL es añadir un usuario definido función. Si va a construir una nueva versión de MySQL de todos modos, también se puede añadir un función nativa .
La forma "correcta" es procesar los datos fuera de la base de datos desde el DB son para el almacenamiento, procesamiento no, y cualquier procesamiento pesada podría poner demasiado de una carga en el DBMS. Además, calculando el número de palabras fuera de MySQL hace que sea más fácil cambiar la definición de lo que se considera una palabra. ¿Qué hay de almacenar el número de palabras en la base de datos y su actualización cuando se cambia un documento?
Ejemplo función almacenada:
DELIMITER $$
CREATE FUNCTION wordcount(str LONGTEXT)
RETURNS INT
DETERMINISTIC
SQL SECURITY INVOKER
NO SQL
BEGIN
DECLARE wordCnt, idx, maxIdx INT DEFAULT 0;
DECLARE currChar, prevChar BOOL DEFAULT 0;
SET maxIdx=char_length(str);
SET idx = 1;
WHILE idx <= maxIdx DO
SET currChar=SUBSTRING(str, idx, 1) RLIKE '[[:alnum:]]';
IF NOT prevChar AND currChar THEN
SET wordCnt=wordCnt+1;
END IF;
SET prevChar=currChar;
SET idx=idx+1;
END WHILE;
RETURN wordCnt;
END
$$
DELIMITER ;
Otros consejos
Esto es un poco más rápido, aunque sólo un poco menos precisa. He encontrado que 4% de luz en el recuento, lo cual está bien para escenarios "estimar".
SELECT
ROUND (
(
CHAR_LENGTH(content) - CHAR_LENGTH(REPLACE (content, " ", ""))
)
/ CHAR_LENGTH(" ")
) AS count
FROM documents
Puede utilizar la UDF word_count()
de https://github.com/spachev/mysql_udf_bundle . Porté la lógica de la respuesta aceptada con una diferencia que mi código sólo es compatible con juego de caracteres latin1. tendría que ser revisado a fin de apoyar a otros juegos de caracteres de la lógica. Además, ambas implementaciones siempre consideran un carácter no alfanumérico ser un delimitador, que puede que no siempre es deseable. - por ejemplo, "El libro de profesor" es considerada como tres palabras por ambas implementaciones
La versión UDF es, por supuesto, mucho más rápido. Para una prueba rápida He intentado tanto en un conjunto de datos de proyecto Guttenberg que consiste en 9751 registros de un total de aproximadamente 3 GB. La UDF hizo todo de ellos en 18 segundos, mientras que la función almacenada tomó 63 segundos para procesar sólo 30 registros (que UDF hace en 0,05 segundos). Por lo que la UDF es aproximadamente 1000 veces más rápido en este caso.
UDF le ganará a cualquier otro método de la velocidad que no implica modificar el código fuente de MySQL. Esto es debido a que tiene acceso a los bytes de cadena en la memoria y puede operar directamente en bytes sin que tengan que ser movido alrededor. También se compila en código máquina y se ejecuta directamente en la CPU.