Использование SQL для определения статистики количества слов в текстовом поле
-
09-09-2019 - |
Вопрос
Недавно я работал над некоторыми функциями поиска по базе данных и хотел получить некоторую информацию, такую как среднее количество слов в документе (напримертекстовое поле в базе данных).Единственное, что я нашел до сих пор (без обработки на выбранном языке вне базы данных), это:
SELECT AVG(LENGTH(content) - LENGTH(REPLACE(content, ' ', '')) + 1)
FROM documents
Кажется, это работает * но есть ли у вас другие предложения?В настоящее время я использую MySQL 4 (надеюсь скоро перейти на версию 5 для этого приложения), но меня также интересуют общие решения.
Спасибо!
* Я могу себе представить, что это довольно грубый способ определить это, поскольку он также не учитывает HTML в содержимом и тому подобное.Это нормально для данного конкретного проекта, но опять же, есть ли способы получше?
Обновить: Чтобы определить, что я подразумеваю под "лучше":либо более точен, работает более эффективно, либо более "корректен" (прост в обслуживании, хорошая практика и т.д.).Что касается контента, который у меня есть, приведенный выше запрос выполняется достаточно быстро и является точным для этого проекта, но мне может понадобиться что-то подобное в будущем (поэтому я спросил).
Решение
Возможности MySQL по обработке текста недостаточно хороши для того, что вы хотите.Сохраненная функция - это вариант, но, вероятно, он будет медленным.Ваш лучший выбор для обработки данных в MySQL - добавить определяемая пользователем функция.Если вы все равно собираетесь создавать более новую версию MySQL, вы также могли бы добавить собственная функция.
"Правильный" способ - обрабатывать данные вне базы данных, поскольку базы данных предназначены для хранения, а не обработки, и любая интенсивная обработка может создать слишком большую нагрузку на СУБД.Кроме того, вычисление количества слов вне MySQL упрощает изменение определения того, что считается словом.Как насчет сохранения количества слов в базе данных и обновления его при изменении документа?
Пример сохраненной функции:
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 ;
Другие советы
Это немного быстрее, хотя и немного менее точно.Я обнаружил, что это на 4% меньше, чем подсчет, что нормально для сценариев "оценки".
SELECT
ROUND (
(
CHAR_LENGTH(content) - CHAR_LENGTH(REPLACE (content, " ", ""))
)
/ CHAR_LENGTH(" ")
) AS count
FROM documents
Вы можете использовать word_count()
UDF из https://github.com/spachev/mysql_udf_bundle.Я перенес логику из принятого ответа с той разницей, что мой код поддерживает только кодировку latin1.Логику необходимо было бы переработать для поддержки других кодировок.Кроме того, обе реализации всегда рассматривают не буквенно-цифровой символ в качестве разделителя, что не всегда может быть желательным - например, "книга учителя" считается тремя словами в обеих реализациях.
Версия UDF, конечно, значительно быстрее.Для быстрого тестирования я попробовал оба варианта на наборе данных из Project Guttenberg, состоящем из 9751 записи общим объемом около 3 ГБ.UDF выполнила все из них за 18 секунд, в то время как сохраненной функции потребовалось 63 секунды, чтобы обработать всего 30 записей (что UDF выполняет за 0,05 секунды).Таким образом, UDF в этом случае работает примерно в 1000 раз быстрее.
UDF превзойдет любой другой метод по скорости, который не требует изменения исходного кода MySQL.Это связано с тем, что он имеет доступ к строковым байтам в памяти и может работать непосредственно с байтами без необходимости их перемещения.Он также компилируется в машинный код и запускается непосредственно на центральном процессоре.