首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用pg_trgm按相似值分组

如何使用pg_trgm按相似值分组
EN

Stack Overflow用户
提问于 2017-11-09 21:55:02
回答 2查看 1.3K关注 0票数 1

我有下表

代码语言:javascript
复制
id error
-  ----------------------------------------
1  Error 1234eee5, can not write to disk
2  Error 83457qwe, can not write to disk
3  Error 72344ee, can not write to disk
4  Fatal barier breach on object 72fgsff
5  Fatal barier breach on object 7fasdfa
6  Fatal barier breach on object 73456xcc5

我希望能够得到一个由相似性来计算的结果,其中相似度> 80%意味着两个错误相等。我一直在使用pg_trgm扩展,它的相似函数对我来说非常有用,这是我唯一能知道如何生成下面的分组结果的东西。

代码语言:javascript
复制
Error                                  Count
-------------------------------------  ------
Error 1234eee5, can not write to disk, 3
Fatal barier breach on object 72fgsff, 3
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-11-09 22:55:57

基本上,您可以自己加入一个表来查找类似的字符串,但是这种方法在更大的数据集中以一个非常慢的查询结束。此外,在某些情况下,使用similarity()可能会导致不准确(您需要找到适当的限值)。

你应该试着找出模式。例如,如果字符串中的所有变量字都以数字开头,则可以使用regexp_replace():掩蔽它们。

代码语言:javascript
复制
select id, regexp_replace(error, '\d\w+', 'xxxxx') as error
from errors;

 id |                error                
----+-------------------------------------
  1 | Error xxxxx, can not write to disk
  2 | Error xxxxx, can not write to disk
  3 | Error xxxxx, can not write to disk
  4 | Fatal barier breach on object xxxxx
  5 | Fatal barier breach on object xxxxx
  6 | Fatal barier breach on object xxxxx
(6 rows)    

因此,您可以轻松地根据错误消息对数据进行分组:

代码语言:javascript
复制
select regexp_replace(error, '\d\w+', 'xxxxx') as error, count(*)
from errors
group by 1;

                error                | count 
-------------------------------------+-------
 Error xxxxx, can not write to disk  |     3
 Fatal barier breach on object xxxxx |     3
(2 rows)

上面的查询只是一个示例,因为特定的解决方案取决于数据格式。

使用pg_trgm

该解决方案基于OP的想法(请参阅下面的注释)。similarity()的限值0.8当然太高了。似乎应该在大约0.6的地方。

该表用于唯一错误(我使用了一个临时表,当然它也是一个常规表):

代码语言:javascript
复制
create temp table if not exists unique_errors(
    id serial primary key, 
    error text, 
    ids int[]);

ids列存储基表中包含类似错误的行的id

代码语言:javascript
复制
do $$
declare
    e record;
    found_id int;
begin
    truncate unique_errors;
    for e in select * from errors loop
        select min(id)
        into found_id
        from unique_errors u
        where similarity(u.error, e.error) > 0.6;
        if found_id is not null then
            update unique_errors
            set ids = ids || e.id
            where id = found_id;
        else
            insert into unique_errors (error, ids)
            values (e.error, array[e.id]);
        end if;
    end loop;
end $$;

最后结果:

代码语言:javascript
复制
select *, cardinality(ids) as count
from unique_errors;

 id |                 error                 |   ids   | count 
----+---------------------------------------+---------+-------
  1 | Error 1234eee5, can not write to disk | {1,2,3} |     3
  2 | Fatal barier breach on object 72fgsff | {4,5,6} |     3
(2 rows)
票数 1
EN

Stack Overflow用户

发布于 2022-12-02 13:36:46

对于这种特殊情况,您可以只按左分组( Error,5),这将导致两个组,一个组包含以Error开头的所有字符串,另一个组包含以致命开头的所有字符串。如果计划添加更多错误类型,则必须更新此标准。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47212230

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档