一、说明
使用线程池导入mysql数据到ElasticSearch效率极高
平均速度30s,测试数据88000条
正常遍历导入需要花费20分钟
创建线程池:需要必要参数(核心线程数、最大线程数、线程持续时间、空闲线程最大存活时间、时间单位、阻塞队列、拒绝策略)
拒绝策略有四种: 这里使用第三个
- ThreadPoolExecutor.AbortPolicy
丢弃任务并抛出RejectedExecutionException异常,默认策略
- DiscardPolicy
丢弃任务,不抛异常
- DiscardOldestPolicy
抛弃队列中等待最久的任务(队列第一个)然后把当前任务加入队列中
- CallerRunsPolicy
调用任务的 run()方法绕过线程池直接执行
二、 代码
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class InjectData {
@Autowired
private RestHighLevelClient esClient;
@Autowired
private ItemClient itemClient;
//多线程导入es
@Test
public void injectDataByThread() throws IOException {
//创建线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 10, 60,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(3),
new ThreadPoolExecutor.DiscardOldestPolicy());
//查询总条数
Integer total = itemClient.itemCount();
//计算总页数
int pages = (int) Math.ceil((double) total / 10000);
//分页导入数据
for (int page = 1; page <= pages; page++) {
PageDTO<Item> dto = itemClient.itemPage(page, 10000);
if (dto.getList() != null && dto.getList().size() > 0) {
//
threadPool.execute(new Runnable() {
@Override
public void run() { //加入到线程池任务
try {
//创建request对象
BulkRequest bulkRequest = new BulkRequest();
//遍历每条数据转换为es实体
for (Item item : dto.getList()) {
ItemDoc itemDoc = new ItemDoc(item);
//转为json配置indexRequest对象添加请求
IndexRequest indexRequest = new IndexRequest("hmall")
.id(itemDoc.getId().toString())
.source(JSON.toJSONString(itemDoc), XContentType.JSON);
bulkRequest.add(indexRequest);
}
esClient.bulk(bulkRequest, RequestOptions.DEFAULT);
log.info("【es】thread:{},msg:本次同步 {} 条数据",
Thread.currentThread().getName(), dto.getList().size());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
try {
//延迟3秒等elasticsearch完成写入数据
Thread.sleep(3000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}