这周接到了一个对爬取数据进行清理的任务,具体需求为,有一张接近百万的key值表,每一个key对应一个对象,但是在es中存在大量的相似对象,需要按照相似度清除key值表中重复的对象。
下面简单的介绍一下本人的思路。
文件准备
因为百万级数据的清理在单机模式下其实是很耗时的操作,所以我们需要考虑到一些异常的发生,并且要暂存一下重复的key值,所以需要构建三个临时文件
touch out.json set.json error.json
分别代表输出文件,key值暂存文件,以及错误文件
重试机制的简单实现
有时调用es进行查询会出现超时的情况,为了防止服务的直接停止,我们需要捕获异常进行处理。
对于重试,思路如下:
catch (Exception e) {
// 重试超过三次后退出并写入错误文件中
if (map.getOrDefault(key, 0) >= 3) {
FileWriter fw2 = new FileWriter(errorFile, true);
fw2.write("\"" + key + "\"" + ",");
fw2.close();
continue;
}
log.warn("error!", e);
// 当失败时放入队列头部
list.addFirst(key);
map.put(key,map.getOrDefault(key, 0) + 1);
}
我们使用一个map来统计当前key的失败次数,进入异常后判断一下当前失败次数,当超过3次后,写入错误文件,并跳到下一个key,未达到三次时,放入队列头部,下次继续重试
开始清洗
首先将数据读取到队列中
String content = FileUtils.readFileToString(file, "UTF-8");
// 提取json的values
JSONObject jsonObject = JSONObject.fromObject(content);
LinkedList<String> list = new LinkedList<>(jsonObject.values());
然后通过当前key去es中查找唯一的对象,再通过对象值去查找与之相似的key,存入set中。
删除队列中存在的相似key
list.removeAll(set);
最好统计一下当前运行的进度,比如每一千个输出一次
if (count % 1000 == 0) {
// 已清洗数据量
log.info("count: " + count);
// 已删除数据量
log.info("cleanCount: " + cleanCount);
FileWriter fw1 = new FileWriter(setFile, true);
fw1.write("\"" + count + "\":" + "\"" + cleanCount + "\"" + ",");
fw1.close();
}
今天的介绍就到这里了,如有问题,请联系博主
付出不到,就不要想着收获
网友评论