博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线上数据清洗-一个有趣的算法
阅读量:5859 次
发布时间:2019-06-19

本文共 8133 字,大约阅读时间需要 27 分钟。

文章目录

需求:

I look at you

You look at me
两个功能:a.我可以查看谁 look at 了我 b.查看我look at 了谁。
历史设计:
MySQL数据库分了100张表,当 I look at you , 我的表里存一条数据: I look at you 状态为0 ,you的 表里插一条数据 我被你look at 状态为1 。 当
You look at me ,you的表里插入 状态为0 的数据,我的表里插入状态为1 的数据,即:一方look at 插入双方的数据。

比如: 我的id 为111111 你的id为222222,当我look at 你的时候,表的情况是这样的

我的表 LOOK_AT_11

MY_IDYOU_IDSTATUSCREATE_TIMEUPDATE_TIME11111122222202005-06-04 13:45:44

你的表 LOOK_AT_22

MY_IDYOU_IDSTATUSCREATE_TIMEUPDATE_TIME22222211111112005-06-04 13:45:44

当你也look at 了我 , 我也look at 了你的时候,表的情况是这样的。

我的表 LOOK_AT_11

你的表 LOOK_AT_22

在这里插入图片描述

需求2:现在有新需求,当我look at 了你,你也look at 了我的时候,说明俩人看对眼儿了, 产品经理要把看对眼儿的人挑出来展示给用户。在当前设计的基础上,我们新增了一个状态,STATUS=2 为对眼儿,当 我俩互相 look at 的时候,插入一条STATUS=2 的数据,由于我查询对眼儿用户的时候,需要按照UPDATE_TIME排序查询,所以上线之后数据是这样的。

(我的id:333333 , 你的id:444444,我俩互相look at)

我的表 LOOK_AT_33

在这里插入图片描述

你的表 LOOK_AT_22

在这里插入图片描述

那么问题来了,老数据该怎么办?

我们需要写个job,来给历史互相look at 的用户插入一条STATUS=2 的对眼儿数据。

READY===========================GO!!!

第一版:

1.循环100张表,每次循环,在每张表里取出所有我被你 look at 的beLookEdAtlist 和 我look at 你的iLookAtList.

2.将beLookEdAtlist 转成map ,结构:Map<myId,youIdList> ,目的:用来判断是否有look我的人,有则继续判断,没有则下一轮循环,用于减少判断。

3.循环beLookEdAtlist 和 iLookAtList ,找出myid 相等,youId相等的数据组装。 插入数据

public void execute()  {
for (int table = 0; table<100; table++) {
//param 控制第几张表 String dbTable = "LOOK_AT" + table; Integer lookType = LookAtEnum.ILOOKATYOU.getType(); List
iLookAtList = Dao.findByLookAtType(dbTable, lookType); if (CollectionUtils.isEmpty(iLookAtList)) {
return; } Integer beLookType = LookActionEnum.BE_LookED.getType(); List
beLookEdAtlist = Dao.findByLookAtType(dbTable, beLookType); if (CollectionUtils.isEmpty(beLookEdAtlist )) {
return; } Map
> map = new HashMap<>(); beLookEdAtlist.forEach(lookAtEmpty -> {
if (map.get(lookAtEmpty.getUserId()) == null) {
List
list = new ArrayList<>(); list.add(lookAtEmpty.getOtherUserId()); map.put(lookAtEmpty.getUserId(), list); } else {
List
existList = map.get(lookAtEmpty.getUserId()); existList.add(lookAtEmpty.getOtherUserId()); map.put(lookAtEmpty.getUserId(), existList); } }); List
resList = new ArrayList<>(); for (LookAtEmpty lookAtEmpty : iLookAtList) { List
beLookEdAtUserIds = map.get(lookAtEmpty.getUserId()); if (CollectionUtils.isEmpty(beLookEdAtUserIds) || !beLookEdAtUserIds.contains(lookAtEmpty.getOtherUserId())) { continue; } for (LookAtEmpty beLookedAtEmpty : beLookEdAtlist ) { if (beLookedAtEmpty.getUserId() == beLookUser.getUserId() && beLookedAtEmpty.getOtherUserId() == beLookedAtEmpty.getOtherUserId()) { Date updateTime = beLookUser.getCreateTime().before(beLookedAtEmpty.getCreateTime()) ? beLookedAtEmpty.getCreateTime() : beLookUser.getCreateTime(); beLookUser.setCreateTime(updateTime); beLookUser.setUpdateTime(updateTime); resList.add(beLookUser); } } } } }

老大看了我的代码后说:“其实可以分页”

我说:“不能,因为关系可能存在于下一页”
老大说:“可以分页…”
我说:“不能!”
老大说:“可以分页……”
我说:“不能!!”

我还是让老大把话说完了 ,才有了第二版代码。

第二版:

1.循环100张表,在每张表中用数据库limit分页取出我look at 你的数据,全部取出到内存里,用map 存储,key为 myId-youId , value 为Createtime。因为我需要在我look at 你 和你look at 我两条数据里取出Createtime 最大的,放到对眼儿数据的Createtime 和 UpdateTime里。

2.然后分页取出我被你look at 的数据,在map中找有没有Createtime ,有则说明两者有过对眼儿,需要插入数据

3.插入数据

public void execute() {
int pageSize = 500; int pageNum = 0 ; for (int table = 0; table<100; table++){
String dbTable ="LOOK_AT"+table; Map
lookAtMap = new HashMap<>(); for (int i =0;i<= 400;i++){
List
lookAtList = Dao.findByLookAtType(dbTable,LookAtEnum.ILOOKATYOU.getType(),pageNum*pageSize,pageSize); if (CollectionUtils.isEmpty(lookAtList) ){
break; } for (LookAtEmpty lookAtEmpty :lookAtList){
String key = lookAtEmpty.getMyId()+"-"+lookAtEmpty.getYouId(); lookAtMap.put(key,lookAtEmpty.getCreateTime()); } if( lookAtList.size()
idResList = new ArrayList<>(); int res=0; int pageNum1 =0; for (int i =0;i<=400;i++){
List
beLookList = Dao.findByLookAtType(dbTable,LookAtEnum.IBELOOKEDBYYOU.getType(),pageNum1*pageSize,pageSize); if (CollectionUtils.isEmpty(beLookList)){
break; } for (LookAtEmpty lookAtEmpty :beLookList){
String key = lookAtEmpty.getMyId()+"-"+lookAtEmpty.getYouId(); if (lookAtMap.get(key) !=null){
Date lookDate = lookAtMap.get(key); Date updateTime = lookAtEmpty.getCreateTime().before(lookDate) ? lookDate:userRelation.getCreateTime(); LookAtEmpty u = new LookAtEmpty( lookAtEmpty.getMyId(), lookAtEmpty.getYouId(), LookAtEnum.DUIYANER.getType(), updateTime, updateTime); idResList.add(u); } } if (CollectionUtils.isNotEmpty(idResList)){
res += Dao.insertLookAtEmptyList(dbTable,idResList); } idResList.clear(); pageNum1++; if (beLookList.size()

老大看过之后又给了几条建议:

1.for循环里已经有了终止条件:

if(lookAtList.size() < pageSize){
break;}

所以不需要在for循环里限定400

2.findByLookAtType 方法的查询分页,用的是MySQL的limit,limit在分页越往后,效率就越低,所以不如以时间倒序查询,每次记录最后一条数据的createtime,下次查询<createtime的数据即可,createtime加索引。

第三版:

public void execute() {
int pageSize = 500; for (int table = 0; table<100; table++){
String dbTable ="LOOK_AT"+table; Map
lookAtMap = new HashMap<>(); Date iLookCreateTime = new Date(); for (int i =0;;i++){
List
lookAtList = Dao.findByTime(dbTable,LookAtEnum.ILOOKATYOU.getType(),iLookCreateTime,pageSize); if (CollectionUtils.isEmpty(lookAtList) ){
break; } for (LookAtEmpty lookAtEmpty :lookAtList){
String key = lookAtEmpty.getMyId()+"-"+lookAtEmpty.getYouId(); lookAtMap.put(key,lookAtEmpty.getCreateTime()); } if( lookAtList.size()
idResList = new ArrayList<>(); int res=0; int pageNum1 =0; Date beLookDateTime = new Date(); for (int i =0;;i++){
List
beLookList = Dao.findByTime(dbTable,LookAtEnum.IBELOOKEDBYYOU.getType(),beLookDateTime,pageSize); if (CollectionUtils.isEmpty(beLookList)){
break; } for (LookAtEmpty lookAtEmpty :beLookList){
String key = lookAtEmpty.getMyId()+"-"+lookAtEmpty.getYouId(); Date lookDate = lookAtMap.get(key); if (lookDate !=null){
Date updateTime = lookAtEmpty.getCreateTime().before(lookDate) ? lookDate:userRelation.getCreateTime(); LookAtEmpty u = new LookAtEmpty( lookAtEmpty.getMyId(), lookAtEmpty.getYouId(), LookAtEnum.DUIYANER.getType(), updateTime, updateTime); idResList.add(u); } } if (CollectionUtils.isNotEmpty(idResList)){
res += Dao.insertLookAtEmptyList(dbTable,idResList); } beLookDateTime = beLookList.get(beLookList.size()-1).getCreateTime(); idResList.clear(); if (beLookList.size()

结语:

如此,用数据结构提高了不少效率,有趣吧!

转载地址:http://ptgjx.baihongyu.com/

你可能感兴趣的文章
Grpc介绍 — ProToBuf基本使用
查看>>
是maven项目在指定JDK版本下编译和运行
查看>>
封装的一些常用的javascript函数
查看>>
NIO案例
查看>>
log4j的MDC
查看>>
OCR文字识别可以帮助PDF文档处理吗
查看>>
ABBYY FineReader 12 识别文档语言有哪些
查看>>
BarTender打印额外字符的方法
查看>>
Mysql 错误日志
查看>>
iOS开发 使用Xcode自带的Leaks:动态的检测内存泄露
查看>>
ubuntu faience图标推荐
查看>>
扫雷(windows xp winmine)内存读取
查看>>
grails使用经验笔记
查看>>
nagios+centreon总结之第一章——nagios+centreon简介
查看>>
Iptables
查看>>
Postman全局变量
查看>>
MySQL命令行工具
查看>>
sed awk第2讲: sed基本用法(视频)
查看>>
1个拥有很多编辑器的网站
查看>>
机器学习库初探之MXnet
查看>>