在解决es入库问题上,之前使用过rest方式,经过一段时间的测试发现千万级别的数据会存在10至上百条数据的丢失问题,

在需要保证数据的准确性的场景下,rest方式并不能保证结果的准确性,因此采用了elasticsearch的BulkProcessor方式来进行数据入库,

实际上采用es客户端不同,rest方式采用的是restClient,基于http协议,BulkProcessor使用的是TransportClient,基于Tcp协议。

下面是在spring下具体的实现步骤:
1 定义一个student类,并json序列化
2 json的具体实现

3 构造BulkProcessor

* setBulkActions(1000):每添加1000个request,执行一次bulk操作
* setBulkSize(new ByteSizeValue(5, ByteSizeUnit.MB)):每达到5M的请求size时,执行一次bulk操作
* setFlushInterval(TimeValue.timeValueSeconds(5)):每5s执行一次bulk操作
* setConcurrentRequests(1):默认是1,表示积累bulk requests和发送bulk是异步的,其数值表示发送bulk的并发线程数,设置为0表示二者同步的
*setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100),3)):当ES由于资源不足发生异常
EsRejectedExecutionException重試策略:默认(50ms, 8),
* 策略算法:start + 10 * ((int) Math.exp(0.8d * (currentlyConsumed)) - 1)

package es;

import org.elasticsearch.action.bulk.BackoffPolicy;
import org.elasticsearch.action.bulk.BulkProcessor;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import java.net.InetAddress;
import java.net.UnknownHostException; @Configuration
public class ESConfiguration {
public static final Logger logger = LoggerFactory.getLogger(ESConfiguration.class); @Bean
public BulkProcessor bulkProcessor() throws UnknownHostException { Settings settings = Settings.builder().put("cluster.name", "elasticsearch").build(); Client client = new PreBuiltTransportClient(settings)
.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("http://192.168.10.33"), Integer.parseInt("9300"))); return BulkProcessor.builder(client, new BulkProcessor.Listener() {
@Override
public void beforeBulk(long l, BulkRequest bulkRequest) { } @Override
public void afterBulk(long l, BulkRequest bulkRequest, BulkResponse bulkResponse) { } @Override
public void afterBulk(long l, BulkRequest bulkRequest, Throwable throwable) {
logger.error("{} data bulk failed,reason :{}", bulkRequest.numberOfActions(), throwable);
} }).setBulkActions(1000)
.setBulkSize(new ByteSizeValue(5, ByteSizeUnit.MB))
.setFlushInterval(TimeValue.timeValueSeconds(5))
.setConcurrentRequests(1)
.setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3))
.build();
}
}

  

4. 入库代码实现

package es;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.elasticsearch.action.bulk.BulkProcessor;
import org.elasticsearch.action.index.IndexRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository; @Repository
public class StudentInsertDao{
private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired
private BulkProcessor bulkProcessor; private ObjectMapper objectMapper = new ObjectMapper(); public void insert(Student student) {
String type = student.getAge();
String id = student.getName()+student.getAddr()+student.getAge();
try {
byte[] json = objectMapper.writeValueAsBytes(student); bulkProcessor.add(new IndexRequest("students", type, id).source(json)); } catch (Exception e) {
logger.error("bulkProcessor failed ,reason:{}",e);
}
}
}

  

5. 测试代码

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {"classpath:servlet-context.xml", "classpath:applicationContext.xml"})
public class StudentInsertDaoTest {
@Autowired
private StudentInsertDao insertDao; @Test
public void insert() throws Exception { Student student = new Student();
student.setAge(12);
student.setAddr("SH");
student.setName("Jack"); insertDao.insert(student);
}
}

  

原文链接:https://blog.csdn.net/wslyk606/article/details/79413980

Elasticsearch-BulkProcessor浅析:

https://blog.csdn.net/baichoufei90/article/details/97117025

elasticsearch使用BulkProcessor批量入库数据的更多相关文章

  1. Elasticsearch使用BulkProcessor批量插入

    https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high-document-bulk. ...

  2. elasticsearch REST API方式批量插入数据

    elasticsearch REST API方式批量插入数据 1:ES的服务地址  http://127.0.0.1:9600/_bulk 2:请求的数据体,注意数据的最后一行记得加换行 { &quo ...

  3. discuz数据批量入库接口

    近期在做社区,首选discuz,数据需要用scrapy爬虫批量入库,就写了一个php入库接口. <?php define('PW', 'abc123456');//一定要修改 if($_REQU ...

  4. SqlBulkCopy 批量复制数据到数据表

    使用 SqlBulkCopy 类只能向 SQL Server 表写入数据.但是,数据源不限于 SQL Server:可以使用任何数据源,只要数据可加载到 DataTable 实例或可使用 IDataR ...

  5. SQLServer使用表值参数,高性能批量插入数据

    记得前段时间帮同事写了个解析账号并入库的小工具,来批量导入账号信息,账号量相当大,程序每读取一条记录便执行一次insert来插入数据,整整跑了一下午才把账号全部入库. 今天又接到同事类似的需求,不过这 ...

  6. 高并发简单解决方案————redis队列缓存+mysql 批量入库(ThinkPhP)

    问题分析 问题一:要求日志最好入库:但是,直接入库mysql确实扛不住,批量入库没有问题,done.[批量入库和直接入库性能差异] 问题二:批量入库就需要有高并发的消息队列,决定采用redis lis ...

  7. myBatis获取批量插入数据的主键id

    在myBatis中获取刚刚插入的数据的主键id是比较容易的 , 一般来说下面的一句话就可以搞定了 , 网上也有很多相关资料去查. @Options(useGeneratedKeys = true, k ...

  8. 转载:【高并发简单解决方案 | 靠谱崔小拽 】redis队列缓存 + mysql 批量入库 + php离线整合

    需求背景:有个调用统计日志存储和统计需求,要求存储到mysql中:存储数据高峰能达到日均千万,瓶颈在于直接入库并发太高,可能会把mysql干垮. 问题分析 思考:应用网站架构的衍化过程中,应用最新的框 ...

  9. redis 队列缓存 + mysql 批量入库 + php 离线整合

    问题分析 思考:应用网站架构的衍化过程中,应用最新的框架和工具技术固然是最优选择:但是,如果能在现有的框架的基础上提出简单可依赖的解决方案,未尝不是一种提升自我的尝试. 解决: 问题一:要求日志最好入 ...

随机推荐

  1. 输入web网站点击之后发生的事情

    (1)用户在浏览器(客户端)里输入或者点击一个连接: (2)浏览器向服务器发送HTTP请求: (3)服务器处理请求,如果查询字符串或者请求体里含有参数,服务器也会把这些参数信息考虑进去: (4)服务器 ...

  2. 【转】国内CPU现状

    首页 博客 学院 下载 图文课 论坛 APP CSDN                            CSDN学院                            问答 商城 VIP会员 ...

  3. Java--8--新特性--接口中的变化!!

    package InterfaceP; public interface Interface1 { default String getName(){ return "Interface1& ...

  4. 分配swap分区空间

    1. 分区,并修改为swap分区ID [root@centos2 ~]# fdisk /dev/sdb 欢迎使用 fdisk (util-linux ). 更改将停留在内存中,直到您决定将更改写入磁盘 ...

  5. altium designer(AD13)隐藏敷铜的方法

    覆铜,就是将PCB上闲置的空间作为基准面,然后用固体铜填充,这些铜区又称为灌铜.敷铜的意义在于,减小地线阻抗,提高抗干扰能力;降低压降,提高电源效率;还有,与地线相连,减小环路面积. 如果拿到别人的P ...

  6. 微信小程序~生命周期方法详解

    生命周期是指一个小程序从创建到销毁的一系列过程 在小程序中 ,通过App()来注册一个小程序 ,通过Page()来注册一个页面 先来看一张小程序项目结构 从上图可以看出,根目录下面有包含了app.js ...

  7. 织梦xss通杀所有版本漏洞【学习笔记】

    漏洞原因:DEDECMS由于编辑器过滤不严,将导致恶意脚本运行.可getshell取得权限.为什么说它是0Day呢?能getshell的都算0Day(鸡肋发挥起来也能变凤凰)目前只是测试过5.3到5. ...

  8. 找回IntelliJ IDEA中丢失的Run Dashboard视图

    一般项目中包含多个springboot项目的时候都会出现run dashboard视图,但如果一开始它提示的时候,不点击展示,就再也找不到这个视图了,给我们后续启动一个一个的启动项目带来了很大的不便, ...

  9. python - django (视图)

    # """ 一:# 视图 (接收请求返回响应的那部分) FBV版:基于 函数的 请求 CBV版:基于 类的 请求 注册方法: url(r'^add_publisher/' ...

  10. [Angular] How to show global loading spinner for application between page navigation

    app.component.ts: import { Component, OnInit } from "@angular/core"; import { select, Stor ...