You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostgreSQL百万行文本:统计高相似度行数并生成自动掩码

PostgreSQL 相似文本分组统计与掩码生成方案

1. 前置准备

先启用PostgreSQL内置的pg_trgm扩展,用于高效计算文本相似度:

CREATE EXTENSION IF NOT EXISTS pg_trgm;

2. 性能优化:创建相似度索引

针对百万级数据,必须创建GIN索引加速相似度查询,避免全表扫描:

CREATE INDEX idx_desc_trgm ON your_table USING GIN (description gin_trgm_ops);

3. 方案实现

3.1 场景1:固定模式差异(如数字替换)

如果相似文本的差异仅为数字(如示例中的something 1/something 2),直接用正则快速生成掩码并统计:

SELECT
    regexp_replace(description, '\d+', '*', 'g') AS "mask (auto-generated)",
    COUNT(*) AS "row count"
FROM your_table
GROUP BY "mask (auto-generated)"
ORDER BY "row count" DESC;

3.2 场景2:通用相似度分组(80%匹配度)

对于任意形式的文本相似性,使用递归聚类将相似度≥80%的文本归为一组,再生成通用掩码:

步骤1:自定义掩码生成函数

该函数接收同组文本数组,提取公共模板并将差异片段替换为*:

CREATE OR REPLACE FUNCTION generate_mask(text_array text[])
RETURNS text AS $$
DECLARE
    base text := text_array[1];
    mask text := base;
    curr text;
    i int;
    j int;
BEGIN
    IF array_length(text_array, 1) = 1 THEN RETURN mask; END IF;

    -- 逐字符对比所有文本,标记差异位置
    FOR i IN 1..length(base) LOOP
        FOR j IN 2..array_length(text_array, 1) LOOP
            curr := text_array[j];
            IF length(curr) < i OR substr(curr, i, 1) != substr(base, i, 1) THEN
                mask := overlay(mask placing '*' from i for 1);
                -- 跳过连续差异字符
                WHILE length(curr) >= i+1 AND substr(curr, i+1, 1) != substr(base, i+1, 1) LOOP
                    i := i + 1;
                END LOOP;
                EXIT;
            END IF;
        END LOOP;
    END LOOP;

    -- 处理文本长度差异
    FOR j IN 2..array_length(text_array, 1) LOOP
        curr := text_array[j];
        IF length(curr) > length(base) THEN
            mask := mask || '*';
        END IF;
    END LOOP;

    -- 合并连续的*为单个
    mask := regexp_replace(mask, '\*+', '*', 'g');
    RETURN mask;
END;
$$ LANGUAGE plpgsql;

步骤2:递归聚类与统计

WITH RECURSIVE text_clusters AS (
    -- 初始化:每个文本作为独立簇
    SELECT
        description AS cluster_key,
        ARRAY[description] AS cluster_texts
    FROM your_table
    UNION ALL
    -- 合并相似度≥80%的文本到同一簇
    SELECT
        tc.cluster_key,
        tc.cluster_texts || yt.description
    FROM text_clusters tc
    JOIN your_table yt 
        ON similarity(tc.cluster_key, yt.description) >= 0.8
        AND NOT yt.description = ANY(tc.cluster_texts)
)
-- 去重并统计每个簇的行数
SELECT
    generate_mask(cluster_texts) AS "mask (auto-generated)",
    COUNT(DISTINCT unnest(cluster_texts)) AS "row count"
FROM text_clusters
GROUP BY cluster_key, cluster_texts
HAVING COUNT(DISTINCT unnest(cluster_texts)) > 1
ORDER BY "row count" DESC;

注意事项

  • 递归聚类方案适合通用场景,但百万级数据可能需要分批处理,或调整相似度阈值平衡精度与性能
  • 若仅需处理数字/特定格式差异,正则方案性能远高于通用聚类方案
  • 务必先创建GIN索引,否则百万级数据的相似度查询会极慢

内容的提问来源于stack exchange,提问作者btlart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 10:55:16