知识点
- RestHighLevelClient使用
- 异步HttpClient创建
- HTTP连接池
- ES 游标使用
一、引入pom
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.10</version>
</dependency>
<!--为了使用@ConfigurationProperties,还需要这个依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
<version>2.3.7.RELEASE</version>
</dependency>
<!-- ES Java Api -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elasticsearch.version}</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.6.0</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.6.0</version>
</dependency>
<!-- commons-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.0</version>
</dependency>
二、配置文件 application-local.yml
es:
index: vehaior-2021
outPath: D:\\usr\\esData.txt
spring:
http-client:
pool:
maxTotalConnect: 500
maxConnectPerRoute: 400
connectTimeout: 3000
readTimeout: 5000
connectionRequestTimout: 200
retryTimes: 3
charset: UTF-8
keepAliveTime: 15
config:
elasticsearch:
address: 1xx.xxx.xxx.xxx:9012
connectTimeout: 10000
socketTimeout: 30000
connectionRequestTimeout: 15000
三、config包
1、ElasticSearchProperty
@Data
@Configuration
@ConfigurationProperties(prefix = "config.elasticsearch")
public class ElasticSearchProperty {
private String address;
private String userName;
private String password;
private int connectTimeout = 10000;
private int socketTimeout = 10000;
private int connectionRequestTimeout = 10000;
}
2、ElasticSearchConfig
@Configuration
@Slf4j
public class ElasticSearchConfig {
@Resource
private ElasticSearchProperty elasticSearchProperty;
@Resource
private HttpClientPoolConfig httpClientPoolConfig;
@Bean
public RestClientBuilder restClientBuilder() {
Assert.notNull(elasticSearchProperty, "elasticSearchProperty cannot null ");
Assert.notNull(elasticSearchProperty.getAddress(), "address hosts cannot null ");
HttpHost[] httpHosts = this.getElasticSearchHttpHosts();
return RestClient.builder(httpHosts).setRequestConfigCallback(requestConfigBuilder -> {
requestConfigBuilder.setConnectTimeout(elasticSearchProperty.getConnectTimeout());
requestConfigBuilder.setSocketTimeout(elasticSearchProperty.getSocketTimeout());
requestConfigBuilder.setConnectionRequestTimeout(elasticSearchProperty.getConnectionRequestTimeout());
return requestConfigBuilder;
}).setFailureListener(new RestClient.FailureListener() {
@Override
public void onFailure(Node node) {
log.error("[ ElasticSearchClient ] >> node :{}, host:{}, fail !", node.getName(),
node.getHost());
}
}).setHttpClientConfigCallback(httpSyncClientBuilder -> {
try {
SSLContext sslContext = SSLContexts.createDefault();
Registry<SchemeIOSessionStrategy> sessionStrategyRegistry = RegistryBuilder
.<SchemeIOSessionStrategy>create()
.register("http", NoopIOSessionStrategy.INSTANCE)
.register("https", new SSLIOSessionStrategy(sslContext))
.build();
IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
.setIoThreadCount(Runtime.getRuntime().availableProcessors())
.build();
ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
Assert.notNull(ioReactor, "ioReactor init error");
PoolingNHttpClientConnectionManager poolConnManager = new PoolingNHttpClientConnectionManager(ioReactor,
null, sessionStrategyRegistry, (DnsResolver) null);
poolConnManager.setMaxTotal(httpClientPoolConfig.getMaxTotalConnect());
poolConnManager.setDefaultMaxPerRoute(httpClientPoolConfig.getMaxConnectPerRoute());
httpSyncClientBuilder.setConnectionManager(poolConnManager);
List<Header> headers = getDefaultHeaders();
httpSyncClientBuilder.setDefaultHeaders(headers);
httpSyncClientBuilder.setKeepAliveStrategy(connectionKeepAliveStrategy());
httpSyncClientBuilder.disableAuthCaching();
} catch (IOReactorException e) {
log.error("ES的Http异步连接池配置错误", e);
}
return getHttpAsyncClientBuilder(httpSyncClientBuilder);
});
}
@Bean
public RestHighLevelClient restHighLevelClient(@Qualifier("restClientBuilder") RestClientBuilder restClientBuilder) {
return new RestHighLevelClient(restClientBuilder);
}
private HttpHost[] getElasticSearchHttpHosts() {
String[] hosts = elasticSearchProperty.getAddress().split(",");
HttpHost[] httpHosts = new HttpHost[hosts.length];
for (int i = 0; i < httpHosts.length; i++) {
String host = hosts[i];
host = host.replaceAll("http://", "").replaceAll("https://", "");
Assert.isTrue(host.contains(":"), String.format("your host %s format error , Please refer to [ 127.0.0" +
".1:9200 ] ", host));
httpHosts[i] = new HttpHost(host.split(":")[0], Integer.parseInt(host.split(":")[1]), "http");
}
return httpHosts;
}
private HttpAsyncClientBuilder getHttpAsyncClientBuilder(HttpAsyncClientBuilder httpAsyncClientBuilder) {
if (ObjectUtils.isEmpty(elasticSearchProperty.getUserName()) || ObjectUtils.isEmpty(elasticSearchProperty.getPassword())) {
return httpAsyncClientBuilder;
}
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(elasticSearchProperty.getUserName(),
elasticSearchProperty.getPassword()));
httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
return httpAsyncClientBuilder;
}
public ConnectionKeepAliveStrategy connectionKeepAliveStrategy() {
return (response, context) -> {
HeaderElementIterator it = new BasicHeaderElementIterator(
response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
log.info("HeaderElement:{}", JSON.toJSONString(he));
String param = he.getName();
String value = he.getValue();
if (value != null && "timeout".equalsIgnoreCase(param)) {
try {
return Long.parseLong(value) * 1000;
} catch (NumberFormatException ignore) {
log.error("解析长连接过期时间异常", ignore);
}
}
}
HttpHost target = (HttpHost) context.getAttribute(
HttpClientContext.HTTP_TARGET_HOST);
Optional<Map.Entry<String, Integer>> any =
Optional.ofNullable(httpClientPoolConfig.getKeepAliveTargetHost()).orElseGet(HashMap::new)
.entrySet().stream().filter(
e -> e.getKey().equalsIgnoreCase(target.getHostName())).findAny();
return any.map(en -> en.getValue() * 1000L).orElse(httpClientPoolConfig.getKeepAliveTime() * 1000L);
};
}
private List<Header> getDefaultHeaders() {
List<Header> headers = new ArrayList<>();
headers.add(new BasicHeader("Connection", "Keep-Alive"));
return headers;
}
}
3、HttpClientPoolConfig
@Component
@ConfigurationProperties(prefix = "spring.http-client.pool")
@Data
public class HttpClientPoolConfig {
private int maxTotalConnect;
private int maxConnectPerRoute;
private int connectTimeout = 2 * 1000;
private int readTimeout = 30 * 1000;
private String charset = "UTF-8";
private int retryTimes = 2;
private int connectionRequestTimout = 200;
private Map<String, Integer> keepAliveTargetHost;
private int keepAliveTime = 10;
}
4、WebServerConfiguration
@Component
public class WebServerConfiguration implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
@Override
public void customize(ConfigurableWebServerFactory factory) {
((TomcatServletWebServerFactory) factory).addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
protocol.setKeepAliveTimeout(10000);
protocol.setMaxKeepAliveRequests(8000);
}
});
}
}
三、utils包
1、EsUtils
@Slf4j
@Component
public class EsUtils {
private EsUtils() {
}
@Autowired
private RestHighLevelClient restHighLevelClient;
public List<Map<String, Object>> getAllData(String index) {
List<Map<String, Object>> mapList = new ArrayList<>();
try {
SearchRequest searchRequest = new SearchRequest(index);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
boolQuery.must(QueryBuilders.matchAllQuery());
sourceBuilder.size(5000);
sourceBuilder.query(boolQuery);
final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));
searchRequest.scroll(scroll);
searchRequest.source(sourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
String scrollId = searchResponse.getScrollId();
SearchHit[] searchHits = searchResponse.getHits().getHits();
for (SearchHit searchHit : searchHits) {
mapList.add(searchHit.getSourceAsMap());
}
while (searchHits != null && searchHits.length > 0) {
SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
scrollRequest.scroll(scroll);
searchResponse = restHighLevelClient.scroll(scrollRequest, RequestOptions.DEFAULT);
scrollId = searchResponse.getScrollId();
searchHits = searchResponse.getHits().getHits();
if (searchHits != null && searchHits.length > 0) {
for (SearchHit searchHit : searchHits) {
mapList.add(searchHit.getSourceAsMap());
}
}
}
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
clearScrollRequest.addScrollId(scrollId);
ClearScrollResponse clearScrollResponse = restHighLevelClient.clearScroll(clearScrollRequest,
RequestOptions.DEFAULT);
boolean succeeded = clearScrollResponse.isSucceeded();
} catch (IOException e) {
log.error("请求ES出错", e);
}
return mapList;
}
public void batchAdd(List<String> lineList, String index) {
BulkProcessor bulkProcessor = null;
try {
bulkProcessor = BulkProcessor.builder(
(request, bulkListener) ->
restHighLevelClient.bulkAsync(request, RequestOptions.DEFAULT, bulkListener), listener
)
.setBulkActions(10000)
.setBulkSize(new ByteSizeValue(30, ByteSizeUnit.MB))
.setFlushInterval(TimeValue.timeValueSeconds(5))
.setConcurrentRequests(1)
.setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3))
.build();
for (String line : lineList) {
IndexRequest indexRequest = new IndexRequest(index);
System.out.println(line);
indexRequest.source(line, XContentType.JSON);
indexRequest.type("_doc");
bulkProcessor.add(indexRequest);
}
bulkProcessor.close();
} catch (Exception e) {
log.error("bulk-processor-error:", e);
} finally {
bulkProcessor.close();
}
}
BulkProcessor.Listener listener = new BulkProcessor.Listener() {
@Override
public void beforeBulk(long executionId, BulkRequest request) {
int i = request.numberOfActions();
log.error("ES 同步数量{}", i);
}
@Override
public void afterBulk(long executionId, BulkRequest request, BulkResponse response) {
Iterator<BulkItemResponse> iterator = response.iterator();
while (iterator.hasNext()) {
System.out.println(JSON.toJSONString(iterator.next()));
}
}
@Override
public void afterBulk(long executionId, BulkRequest request, Throwable failure) {
log.error("写入ES 重新消费");
}
};
}
四、批量更新和下载左右
1、Service
@Service
@Slf4j
public class AllDataServiceImpl implements AllDataService {
@Autowired
private EsUtils esUtils;
@Autowired
private Environment environment;
@Override
public String getAllData() {
String index = environment.getProperty("es.index");
String outPath = environment.getProperty("es.outPath");
List<Map<String, Object>> allData = esUtils.getAllData(index);
BufferedWriter bufferedWriter = null;
try {
bufferedWriter = new BufferedWriter(new FileWriter(outPath));
for (Map<String, Object> sourceAsMap : allData) {
String vehicleVin = sourceAsMap.get("vehicleVin").toString();
double drivingDistance = Double.parseDouble(sourceAsMap.get("drivingDistance").toString());
int tripTimes = Integer.parseInt(sourceAsMap.get("tripTimes").toString());
int breakTimes = Integer.parseInt(sourceAsMap.get("breakTimes").toString());
int accelerateTimes = Integer.parseInt(sourceAsMap.get("accelerateTimes").toString());
int speedOverTimes = Integer.parseInt(sourceAsMap.get("speedOverTimes").toString());
double drivingTime = Double.parseDouble(sourceAsMap.get("drivingTime").toString());
LocalDate currentDate = LocalDate.parse(sourceAsMap.get("currentDate").toString(),
DateTimeFormatter.ofPattern("yyyy-MM-dd"));
Object scoreObj = sourceAsMap.get("score");
Long score = null;
if (Optional.ofNullable(scoreObj).isPresent()) {
score = Long.parseLong(scoreObj.toString());
}
String vehicle_state = sourceAsMap.get("vehicle_state").toString();
Vehiclebehavior vehiclebehavior = new Vehiclebehavior(vehicleVin, drivingDistance, tripTimes,
breakTimes, accelerateTimes, speedOverTimes,
drivingTime, currentDate, score, vehicle_state);
String beanString = JSON.toJSON(vehiclebehavior).toString();
bufferedWriter.write(beanString);
bufferedWriter.newLine();
bufferedWriter.flush();
}
} catch (IOException e) {
log.error("ES数据写出失败");
} finally {
if (bufferedWriter != null) {
try {
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return "写出完成";
}
@Override
public String putAllData() {
String index = environment.getProperty("es.index");
BufferedReader br = null;
List<String> lineList = new ArrayList<>();
try {
br = new BufferedReader(new FileReader("C:\\Users\\zmm\\Desktop\\esdata.txt"));
String line;
while ((line = br.readLine()) != null) {
lineList.add(line);
}
esUtils.batchAdd(lineList, index);
} catch (FileNotFoundException e) {
log.error("读取本地ES数据时出错", e);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return "批量更新成功";
}
}