使用SQL确定文本字段的字数统计信息

时间:2009-04-14 16:01:55

标签: mysql sql text-processing word-count

我最近一直在研究一些数据库搜索功能,并希望获得一些信息,例如每个文档的平均单词(例如数据库中的文本字段)。到目前为止我唯一找到的东西(没有在DB之外选择语言处理)是:

SELECT AVG(LENGTH(content) - LENGTH(REPLACE(content, ' ', '')) + 1)
FROM documents

这似乎有效*但您有其他建议吗?我目前正在使用MySQL 4(希望尽快转移到这个应用程序的第5版),但我也对一般解决方案感兴趣。

谢谢!

*我可以想象这是一个非常粗略的方法来确定这一点,因为它不会在内容等中考虑HTML。对于这个特定的项目来说这没关系,但又有更好的方法吗?

更新:通过“更好”来定义我的意思:要么更准确,要么效率更高,要么更“正确”(易于维护,良好做法等)。对于我可用的内容,上面的查询足够快,并且对于这个项目是准确的,但我将来可能需要类似的东西(所以我问)。

5 个答案:

答案 0 :(得分:40)

MySQL的文本处理功能不足以满足您的需求。存储的函数是一个选项,但可能会很慢。在MySQL中处理数据的最佳选择是添加user defined function。如果您打算构建更新版本的MySQL,您还可以添加native function

“正确”的方法是处理数据库外部的数据,因为数据库用于存储而不是处理,任何繁重的处理都可能会给DBMS带来过多的负担。此外,计算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 ;

答案 1 :(得分:2)

虽然稍微不准确,但速度要快得多。我发现它的亮度为4%,这对于#34;估计&#34;场景。

{{1}}

答案 2 :(得分:0)

您可以使用https://github.com/spachev/mysql_udf_bundle中的word_count() UDF。我从接受的答案中移植了逻辑,区别在于我的代码只支持latin1字符集。逻辑需要重新设计以支持其他字符集。此外,两种实现都始终将非字母数字字符视为分隔符,这可能并不总是令人满意 - 例如&#34;老师的书&#34;被两种实现都认为是三个字。

UDF版本当然要快得多。为了进行快速测试,我尝试了来自Project Guttenberg的数据集,其中包含总共约3 GB的9751条记录。 UDF在18秒内完成所有这些操作,而存储的函数需要63秒才能处理30条记录(UDF在0.05秒内完成)。因此,在这种情况下,UDF大约快1000倍。

UDF将超越任何其他不涉及修改MySQL源代码的方法。这是因为它可以访问内存中的字符串字节,并且可以直接在字节上操作,而不必移动它们。它也被编译成机器代码并直接在CPU上运行。

答案 3 :(得分:0)

一些类似情况的简单解决方案(MySQL):

选择 *, (CHAR_LENGTH(student)-CHAR_LENGTH(REPLACE(student,' ','')))+1 为 'count'
来自文档;

答案 4 :(得分:0)

好吧,我尝试使用上面定义的函数,它很棒,除了一种情况。

在英语中,你经常使用 ' 作为单词的一部分。上面的函数,至少对我来说,把“没有”算作 2。

这里是我的小更正:

DELIMITER $$
CREATE FUNCTION wordcount(str TEXT)
            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);
         WHILE idx < maxIdx DO
             SET currChar=SUBSTRING(str, idx, 1) RLIKE '[[:alnum:]]' OR SUBSTRING(str, idx, 1) RLIKE "'";
             IF NOT prevChar AND currChar THEN
                 SET wordCnt=wordCnt+1;
             END IF;
             SET prevChar=currChar;
             SET idx=idx+1;
         END WHILE;
         RETURN wordCnt;
       END
     $$