在文本块中查找单词/短语中字符的百分比

Posted

技术标签:

【中文标题】在文本块中查找单词/短语中字符的百分比【英文标题】:Look for percentage of characters in a word/phrase within a block of text 【发布时间】:2017-09-22 13:47:17 【问题描述】:

希望创建一个条件以在文本块中的每个单词中查找 % 的字符。我在想 regexp_matches 可能是我需要的,但我不确定如何对其进行编码以查找每个单词/短语的出现百分比。

过去,我使用下面的方法来精确定位整个文本块中的空格,然后计算整个块长度的百分比:

(select count(*) from regexp_matches(table.blocktext, ' ', 'gi')

例如,每个文本块可以说是 100 到 1000 个字符(一个或两个段落)。在这些字符中,例如,对于每个单词,它们是否有 80% 或更多的相同字符出现(可能是字母、数字或其他任何东西)。所以我不会告诉它这个字符只是说任何构成单词/短语的 80% 或更多的字符。我还认为我必须添加一个长度条件,以避免在常见的情况下使用较短的流行词(如“woohoo”等)。因此,长度条件也可能为 8 或更多。

我希望这在 Postgres 中是可能的,尽管到目前为止我还没有在我的搜索中找到任何示例。任何帮助将不胜感激,非常感谢您查看。

【问题讨论】:

我认为这甚至不可能使用正则表达式;更别说实用了。但经过快速研究,您似乎可以使用full text search 来做到这一点? 谢谢你,Tom,你是对的,虽然我设法在 Erwin 的帮助下得到了一个版本,但它永远不会很快。我以前从未使用过全文搜索,所以接下来会学习。再次感谢您发布一些反馈,非常感谢! 【参考方案1】:

一种方法:

SELECT c, count(*) AS ct, (count(*) * 100) / length($1) AS pct
FROM   unnest(string_to_array($1, NULL)) c
WHERE  length($1) > 7  -- maybe a length condition of 8 or more
GROUP  BY 1 
HAVING count(*) > (length($1) * 80) / 100  -- 80 is your % threshold
ORDER  BY 2 DESC;

$1是要分析的字符串。

返回占给定文本 80% 以上的字符。显然,对于 50 及以上的百分比,只能是单行。或者如果没有足够频繁地使用字符,则什么都没有。

(count(*) * 100) / length($1) 是使用整数除法进行舍入和计算的最快方法。如果您想要精确的结果,请改用count(*) >= (length($1) * 80) / 100.0(另请注意>= 此处)。 (100.0 将计算结果强制为numeric 并且精确。)

您可以轻松地将其包装到函数或准备好的语句中,并将字符串和百分比作为参数传递。像这样:

CREATE OR REPLACE FUNCTION f_char_pct(_word text, _pct int)
  RETURNS boolean AS
$func$
SELECT EXISTS (
   SELECT 1
   FROM   unnest(string_to_array(_word, NULL)) c
   GROUP  BY c 
   HAVING count(*) > (length(_word) * _pct) / 100
   )
$func$  LANGUAGE sql IMMUTABLE;

呼叫:

“如果给定文档中有一个单词超过 7 个字符且字符百分比低于给定阈值,则返回 false。否则为 true

SELECT NOT EXISTS (
   SELECT 1
   FROM   unnest(string_to_array('1000000000000z abc 1234567890', ' ')) word
   WHERE  length(word) > 7
   AND    NOT f_char_pct(word, 80)
   );

返回 false。 为“1000000000000z abc 2222222”返回 true,因为“abc”被忽略并且其他两个单词具有 > 80 % 的相同字符。 顺便说一句,对于 NULL 输入返回 false

dbfiddle here

您还可以将整个内容包装在一个函数中...

unnest(string_to_array($1, ' ')) 在每个空格处分割单词。更复杂的定义是可能的。您可能会使用文本搜索基础结构。考虑:

Finding the most commonly used non-stop words in a column

顺便说一句,我会替换你的简单计数:

select count(*) from regexp_matches(table.blocktext, ' ', 'gi')

.. 使用这个等价物,但速度更快:

SELECT length(table.blocktext) - length(replace(table.blocktext, ' ', ''))

正则表达式函数功能强大,但要付出代价。聚合步骤使它变得更加昂贵。相关:

GROUP BY or COUNT Like Field Values - UNPIVOT?

【讨论】:

非常感谢,我在让“FROM unnest(string_to_array($1, NULL)) c”工作时遇到了一些问题,但是我稍微修改了代码并使用了 CTE 样式并进行了管理最终得到一些工作。 unnest(string_to_array()) 绝对是关键,所以感谢您提供它,因为没有它我将无事可做。还比 k 你提供了等效且更快的 'SELECT length(table.blocktext) - length(replace(table.blocktext, ' ', ''))'。我最终在一些相关查询中也成功使用了它...... 我还没有真正探索过函数的包装,不过感谢您提供这些信息,这里有很多新的东西,我肯定会用它们来建立我的知识。现在输出很好,所以我将这个标记为已解决。我希望在 AWS 中进行重写,因为这将有助于缩短处理时间,如果您有任何想法,我将很快发布另一个问题。但是再次感谢,非常感谢您详尽而详细的回答。

以上是关于在文本块中查找单词/短语中字符的百分比的主要内容,如果未能解决你的问题,请参考以下文章

关于频度的英语单词

通配符百分号表示啥意思

导入文本查询字母单词个数

单词统计

单词统计

文件读取