V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
forkme
V2EX  ›  程序员

千万级数据库记录模糊匹配效率问题

  •  1
     
  •   forkme · 2017-12-04 11:18:54 +08:00 · 4728 次点击
    这是一个创建于 2549 天前的主题,其中的信息可能已经有所发展或是发生改变。

    存量数据库 记录 ID 姓名(%50 ) 性别( 10%) 手机号( 20%) 籍贯(%10 ) 电子邮箱( 10%) 1 张三 女 13800001111 山西太原 [email protected] 2 张三 男 13800001111 山西太原 [email protected] 3 李四 男 15611112345 湖南长沙 [email protected] 4 王五 男 17022220000 广东广州 [email protected]

    新增记录 5 李四 女 15611112345 广西桂林 [email protected]

    需求是新增记录时做相似性匹配: 规则如下 相似性=(李四==李四)*50% + (男==女)10%+(15611112345==15611112345)20%+(湖南长沙==广西桂林)10%+([email protected][email protected])10%= 150% + 010% + 120% + 0%10% + 110% = 80% >=80% 按照规则,各字段加权计算,阈值设为 80%时,表示记录 5 和记录 3 是相似的。

    存在问题: 现在问题是存量记录表有上“千万”记录,每次新添加记录时需要与存量的记录进行相似度匹配,但是每次都遍历扫描数据库效率太低。 请问有没有什么好的方式 /算法?或者使用其他数据结构代替关系数据库进行记录存储?使得匹配时间控制在 1 分钟级别左右。

    17 条回复    2017-12-05 17:22:21 +08:00
    forkme
        1
    forkme  
    OP
       2017-12-04 11:30:27 +08:00
    mpich
        2
    mpich  
       2017-12-04 11:30:47 +08:00
    ES ?
    forkme
        3
    forkme  
    OP
       2017-12-04 11:32:44 +08:00
    @mpich 什么 ES ?不懂
    kxxoling
        4
    kxxoling  
       2017-12-04 11:40:11 +08:00 via iPad
    @forkme elastic search
    gamexg
        5
    gamexg  
       2017-12-04 11:47:19 +08:00
    @forkme #3 es 指的是 Elasticsearch。
    看需求怎么和之前的一个做小货的帖子需求类是,他的只要求匹配相识的通信录。

    但是仔细看了下需求,没什么难度吧?
    给姓名做索引,然后第一个筛选掉姓名,只要姓名不符合怎么也不可能达到 80%。
    另外重名的数据量应该不大,之后直接遍历吧。

    如果数据库压力大上个 kv 储存来保存姓名。
    zhengxiaowai
        6
    zhengxiaowai  
       2017-12-04 11:59:24 +08:00
    ES 太重 千万的数据量不需要要用到,而且学习曲线不友好。

    推荐使用 pg 的 ts_query 可以设置 rank,效率也不错,挺好上手的
    ytmsdy
        7
    ytmsdy  
       2017-12-04 12:20:16 +08:00
    上个 SSD 试试看。。
    tomczhen
        8
    tomczhen  
       2017-12-04 12:28:43 +08:00
    不知道你当前的 sql 是怎么写的,感觉这种 100 分制后面也许会有问题,如果再加一个条件,比例要重新分配?业务代码相关部分都得改?


    select a,b,c,d,e, sum(weights) from (
    select a,b,c,d,e,1 as weights from table where a = '李四' and b = '女'
    union all
    select a,b,c,d,e,2 as weights from table where a = '李四' and c = '15611112345'
    union all
    select a,b,c,d,e,1 as weights from table where a = '李四' and d = '广西桂林'
    union all
    select a,b,c,d,e,1 as weights from table where a = '李四' and e = '[email protected]'
    )
    group by a,b,c,d,e
    having sum(weights)>=3;
    lkjkkk
        9
    lkjkkk  
       2017-12-04 12:43:13 +08:00 via iPhone
    分区表?
    BadCat
        10
    BadCat  
       2017-12-04 12:43:50 +08:00
    分区呀,可以先分区,然后再索引 效率会高很多
    diginWu
        11
    diginWu  
       2017-12-04 12:55:53 +08:00
    2G 不到的数据难道不能内存搞?
    forkme
        12
    forkme  
    OP
       2017-12-04 14:37:04 +08:00
    @gamexg @tomczhen 目前 sql 业务逻辑还没有写,现在在研究方案。就是考虑到后期字段可能增加,不同版本字段权重要精细化调整。 逻辑上最省心的就是一条条遍历匹配,但是效率太低了。
    forkme
        13
    forkme  
    OP
       2017-12-04 14:45:03 +08:00
    @diginWu 数据量会一直增长,另外放在内存怕有丢失。
    zhx1991
        14
    zhx1991  
       2017-12-04 18:57:12 +08:00
    用 es
    noNOno
        15
    noNOno  
       2017-12-04 20:34:04 +08:00
    分区索引,处理大文本数据用全文索引
    ryd994
        16
    ryd994  
       2017-12-05 00:22:14 +08:00 via Android
    你这算法有问题,添加一条扫一次全表
    放队列,晚上批量处理
    其次,可以对几个高分项先用索引过滤
    如果高分项不匹配,那可以扔到后面批次,用更大的批量,更低的频率去扫
    diginWu
        17
    diginWu  
       2017-12-05 17:22:21 +08:00
    @forkme 内存和 db 增量加全量的同步,然后计算放在内存搞。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1075 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 20:29 · PVG 04:29 · LAX 12:29 · JFK 15:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.