使用 SQL 确定文本字段的字数统计
Posted
技术标签:
【中文标题】使用 SQL 确定文本字段的字数统计【英文标题】:Using SQL to determine word count stats of a text field 【发布时间】:2010-10-19 09:30:15 【问题描述】:我最近一直在研究一些数据库搜索功能,并希望获得一些信息,例如每个文档的平均字数(例如数据库中的文本字段)。到目前为止,我发现的唯一一件事(没有在数据库之外选择语言进行处理)是:
SELECT AVG(LENGTH(content) - LENGTH(REPLACE(content, ' ', '')) + 1)
FROM documents
这似乎可行*,但您还有其他建议吗?我目前正在使用 mysql 4(希望尽快为这个应用迁移到版本 5),但我也对通用解决方案感兴趣。
谢谢!
* 我可以想象这是一种非常粗略的确定方法,因为它也没有考虑内容中的 html 等。这对这个特定项目来说没问题,但还有更好的方法吗?
更新: 定义我所说的“更好”:更准确、执行更高效或更“正确”(易于维护、良好实践等)。对于我现有的内容,上面的查询速度足够快,并且对于这个项目来说是准确的,但我将来可能需要类似的东西(所以我问了)。
【问题讨论】:
这帮助我解决了我的问题,但我发现我的一些字段有尾随空格,所以我使用了 LENGTH(TRIM(content)) 而不是 LENGTH(content)。 【参考方案1】:MySQL 的文本处理能力不足以满足您的需求。存储函数是一种选择,但可能会很慢。在 MySQL 中处理数据的最佳选择是添加user defined function。如果您仍然要构建更新版本的 MySQL,您还可以添加 native function。
“正确”的方法是在 DB 之外处理数据,因为 DB 用于存储而不是处理,任何繁重的处理都可能会给 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 ;
【讨论】:
您的功能解决方案很棒,我喜欢它。对我来说,它只计算带有 ' 的单词(就像没有 2 一样)。我确实发布了对您的功能的更新。【参考方案2】:这要快得多,但准确度稍差。我发现它的计数亮了 4%,这对于“估计”场景来说是可以的。
SELECT
ROUND (
(
CHAR_LENGTH(content) - CHAR_LENGTH(REPLACE (content, " ", ""))
)
/ CHAR_LENGTH(" ")
) AS count
FROM documents
【讨论】:
【参考方案3】:您可以使用来自https://github.com/spachev/mysql_udf_bundle 的word_count()
UDF。我从接受的答案中移植了逻辑,不同之处在于我的代码仅支持 latin1 字符集。需要重新设计逻辑以支持其他字符集。此外,两种实现都始终将非字母数字字符视为分隔符,这可能并不总是可取的 - 例如,两种实现都将“教师用书”视为三个单词。
当然,UDF 版本要快得多。为了进行快速测试,我在 Project Guttenberg 的数据集上进行了尝试,该数据集包含 9751 条记录,总计约 3 GB。 UDF 在 18 秒内完成了所有这些,而存储函数只用了 63 秒来处理 30 条记录(UDF 在 0.05 秒内完成)。所以在这种情况下,UDF 大约快 1000 倍。
UDF 将在速度上击败任何其他不涉及修改 MySQL 源代码的方法。这是因为它可以访问内存中的字符串字节,并且可以直接对字节进行操作,而无需移动它们。它也被编译成机器码,直接在CPU上运行。
【讨论】:
【参考方案4】:一些类似情况的简单解决方案(MySQL):
选择 *, (CHAR_LENGTH(student)-CHAR_LENGTH(REPLACE(student,' ','')))+1 as 'count' 来自文件;
【讨论】:
【参考方案5】:好吧,我尝试使用上面定义的函数,它很棒,除了一种情况。
在英语中,你经常使用 ' 作为单词的一部分。上面的函数,至少对我来说,算“没有”为 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
$$
【讨论】:
以上是关于使用 SQL 确定文本字段的字数统计的主要内容,如果未能解决你的问题,请参考以下文章
如果文本是在 textarea 中生成的,则 Javascript 字数统计功能不起作用