22

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

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

这似乎可行*,但您还有其他建议吗?我目前正在使用 MySQL 4(希望尽快为这个应用程序迁移到版本 5),但我也对通用解决方案感兴趣。

谢谢!

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

更新:定义我所说的“更好”:更准确,执行更有效,或者更“正确”(易于维护,良好实践等)。对于我现有的内容,上面的查询速度足够快,并且对于这个项目来说是准确的,但我将来可能需要类似的东西(所以我问了)。

4

5 回答 5

45

MySQL 的文本处理能力不足以满足您的需求。存储函数是一种选择,但可能会很慢。在 MySQL 中处理数据的最佳选择是添加一个用户定义的函数。如果你无论如何要构建一个更新版本的 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 ;
于 2009-04-15T23:30:35.580 回答
5

这要快得多,尽管准确度略低。我发现它的计数只有 4%,这对于“估计”场景来说是可以的。

SELECT
    ROUND (   
        (
            CHAR_LENGTH(content) - CHAR_LENGTH(REPLACE (content, " ", "")) 
        ) 
        / CHAR_LENGTH(" ")        
    ) AS count    
FROM documents
于 2017-08-13T20:02:05.727 回答
0

您可以使用来自https://github.com/spachev/mysql_udf_bundleword_count()的UDF 。我从接受的答案中移植了逻辑,不同之处在于我的代码仅支持 latin1 字符集。需要重新设计逻辑以支持其他字符集。此外,两种实现都始终将非字母数字字符视为分隔符,这可能并不总是可取的 - 例如,两种实现都将“教师用书”视为三个单词。

当然,UDF 版本要快得多。为了进行快速测试,我在 Project Guttenberg 的数据集上进行了尝试,该数据集包含 9751 条记录,总计约 3 GB。UDF 在 18 秒内完成了所有这些,而存储函数只用了 63 秒来处理 30 条记录(UDF 在 0.05 秒内完成)。所以在这种情况下,UDF 大约快 1000 倍。

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

于 2018-05-31T21:18:47.110 回答
0

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

SELECT *, (CHAR_LENGTH(student)-CHAR_LENGTH(REPLACE(student,' ','')))+1 as 'count'
FROM files;

于 2021-05-17T18:43:01.913 回答
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
     $$
于 2021-07-15T09:57:59.803 回答