记录一个有意思的v2ex问题

栏目: 数据库 · 发布时间: 7年前

内容简介:今日闲逛v2ex发现一个罕见的正八经的技术需求,恰好可以用ES解决,所以特地记录一下。仔细审题发现,问题的核心诉求就是找到一个老用户,他与新用户拥有最多数量的相同号码。表结构就是(user_id,phone),数据规模在千万级别。

今日闲逛v2ex发现一个罕见的正八经的技术需求,恰好可以用ES解决,所以特地记录一下。

楼主的问题

需求: 对于每一个新用户,希望能计算出和老用户的通讯录最高匹配度,找到类似伪造通讯录的情况。
 
例子: 每一个用户的通讯录表结构如下
 
user_id phone
 
123 18721212111
 
123 18721212112
 
123 18721212113
 
124 18721212111
 
124 18721212112
 
124 18721212115
 
124 18721212116
 
假设 user_id:123 是一个新用户,可以发现用户 123 和用户 124 存有相同的联系人
 
用户 123 和 124 的匹配度为: 相同号码数量 /新用户的号码数量 = 2/3 = 0.67
 
需要遍历找到匹配度最高的用户,或者是大于某一阈值的用户群体。
 
各位大佬,这个复杂度似乎有点高,有没有可行的方案。

仔细审题发现,问题的核心诉求就是找到一个老用户,他与新用户拥有最多数量的相同号码。

表结构就是(user_id,phone),数据规模在千万级别。

那么网友们的脑洞一般是找一些奇招妙想,我觉得没法落地的空洞想法还是无法让楼主把工作搞定,所以我有了接下来的思考。

基本思路

因为新用户的通讯录是明确的,所以他的每个号码都可以找到一些同样关联的老用户,对找到的老用户的计数+1,最后看一下哪个老用户的计数最多就是相同号码最多了。

正常情况来说,除了110,119,10086这种官方电话,普通私人电话是不太可能有太多人重复拥有的,所以实际上我们可以找出来的老用户规模并不会很大。

所以最简单的做法,就是去遍历新用户通讯录中每个号码,每一个去 mysql 里查出关联的老用户,在内存里做count累加,最后 排序 取出top N就是拥有最多相同号码的老用户了。当然这样做的前提还是假设不会有一个号码被大量用户共享,否则就需要对mysql的IO和计算节点的内存和计算量都带来很大的负担。

更简单的做法就是直接跑个SQL:

select user_id, count(*) phone_count from t where phone in (xxx,yyy,zzz) and user_id != new_user_id group by user_id order by phone_count asc;

但要注意新用户的通讯录越大,搜索耗费的时间越多,需要参与统计排序的量越多,对于mysql来说这个 SQL 是非常低效的。

我的方案

无论是新用户通讯录大还是号码热门,都可能给单机存储/程序造成性能问题,所以最直接的想法就是依靠分布式计算。

因为我最近用ES很多,所以很自然就联想到ES如何解决这个扩展性问题:

  • 查询阶段:in查询可以走terms query,召回关联了任意号码的记录。
  • 聚合阶段:terms agg直接统计每个user_id的出现次数,这就是每个老用户拥有相同号码的数量。

再考虑到之前提到的热门号码导致的计算倾斜问题,因为ES把记录打散在集群的多个节点中,所以计算得以并行加速。

更好的方案?

ES实时计算方案成本还是挺高的,得有很多高配的机器来保障响应时间,尤其是热门号码带来的可怕agg计算量,对在线查询来说是很昂贵的。

我们也许可以考虑用更便宜的方案,也就是离线计算,接下来大概说一下思路。

先做一些前提准备:

  • 用户的通讯录保存在hbase上,按2种key保存2份:user_id+phone与phone+user_id。
  • 对新增用户来说,把它的user_id写入到hdfs中,作为我们接下来离线计算的输入。

好了,每隔一段时间,我们可以启动spark任务,输入就是新增的user_id文件。

  • 第一轮:先拿着new_user_id去hbase里scan遍历他所有的通讯录电话,输出 new_user_id => phone。
  • 第二轮:输入一条new_user_id => phone,拿着phone去hbase做scan所有phone+user_id的key,对于每个old_user_id,输出new_user_id+old_user_id => phone。
  • 第三轮:聚合得到 new_user_id+old_user_id => count
  • 第四轮:转化为new_user_id => old_user_id, count
  • 第五轮:按new_user_id分组
  • 第六轮:在组内按count做sort,取top N。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

JavaScript & jQuery

JavaScript & jQuery

David Sawyer McFarland / O Reilly / 2011-10-28 / USD 39.99

You don't need programming experience to add interactive and visual effects to your web pages with JavaScript. This Missing Manual shows you how the jQuery library makes JavaScript programming fun, ea......一起来看看 《JavaScript & jQuery》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

在线进制转换器
在线进制转换器

各进制数互转换器

SHA 加密
SHA 加密

SHA 加密工具