SpringMvc整合elasticsearch
1、elasticsearch(以下简称es)的特性可以简单归结为以下三点:
- 一个分布式的实施文档存储,每个字段可以被索引与搜索;
- 一个分布式实时分析搜索引擎;
- 可以胜任上百个服务节点的扩展,并支持PB级别的结构化或者非结构化数据;
2、es对于版本的兼容性要求较高,因此应特别主要版本的兼容。
- es官网可以下载最新版本的es压缩包(https://www.elastic.co/downloads/elasticsearch),解压后即可使用。
- \elasticsearch-6.3.2\bin\elasticsearch.bat 通过该路径启动es服务。
- 浏览器输入http://localhost:9200/?pretty检查服务是否启动,正常启动如下:
4、引入maven依赖包(切记版本对应)。
<elasticsearch.version>6.3.2</elasticsearch.version>
<!-- 引入Elasticsearch相关jar包-->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
3、java端代码:可自行整理配置文件
1、ElasticsConfig建立es连接,HttpHost参数可为数组,集群分布多个ip端口时可重新该方法。
package com.fcbox.fms.elasticSearch;
import com.fcbox.fms.disconf.AppConfig;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class ElasticsConfig {
@Autowired
private AppConfig appConfig;
/**
* 初始化
*/
@Bean
public RestHighLevelClient restHighLevelClient() {
return getEsClientDecorator().getRestHighLevelClient();
}
@Bean
@Scope("singleton")
public ESClientDecorator getEsClientDecorator() {
//可以配置集群 通过逗号隔开
return new ESClientDecorator(new HttpHost("localhost",9200));
}
}
2、ESClientDecorator es客户端连接
package com.fcbox.fms.elasticSearch;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class ESClientDecorator implements InitializingBean, DisposableBean {
private RestHighLevelClient restHighLevelClient;
private HttpHost httpHost;
public ESClientDecorator(HttpHost httpHost) {
this.httpHost = httpHost;
}
public RestHighLevelClient getRestHighLevelClient() {
if (restHighLevelClient == null) {
restHighLevelClient = new RestHighLevelClient(RestClient.builder(httpHost));
}
return restHighLevelClient;
}
@Override
public void destroy() throws Exception {
restHighLevelClient.close();
}
@Override
public void afterPropertiesSet() throws Exception {
restHighLevelClient = new RestHighLevelClient(RestClient.builder(httpHost));
}
}
3、构建查询接口ISearchClient 和接口实现EsSearchClient
package com.fcbox.fms.elasticSearch.service;
import com.alibaba.fastjson.JSONObject;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import java.util.List;
public interface ISearchClient {
/**
* 搜索结果
*/
List<JSONObject> search(SearchRequest request);
List<String> searchString(SearchRequest request);
/**
* 搜索
*/
<T> List<T> search(SearchRequest request, Class<T> tClass);
/**
*
* @param index 数据库名称
* @param type 数据库表名
* @param id 数据库主键ID
* @param t 实体class
* @param <T>
* @return
*/
<T> IndexResponse saveEntity(String index, String type, String id, T t);
// IndexResponse saveEntity(TestBean testBean);
}
package com.fcbox.fms.elasticSearch.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fcbox.fms.elasticSearch.service.ISearchClient;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service("searchClient")
public class EsSearchClient implements ISearchClient {
@Autowired
private RestHighLevelClient client;
@Override
public List<JSONObject> search(SearchRequest request) {
try {
SearchResponse response = client.search(request);
if (response.getHits() == null) {
return null;
}
List<JSONObject> list = new ArrayList<>();
response.getHits().forEach(item -> list.add(JSON.parseObject(item.getSourceAsString())));
log.info("Hits",response.getHits().toString());
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public List<String> searchString(SearchRequest request) {
try {
SearchResponse response = client.search(request);
if (response.getHits() == null) {
return null;
}
List<String> list = new ArrayList<>();
response.getHits().forEach(item -> list.add(item.getSourceAsString()));
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public <T> List<T> search(SearchRequest request, Class<T> tClass) {
List<JSONObject> searchResponse = this.search(request);
if (searchResponse == null) {
return null;
}
List<T> list = new ArrayList<>(searchResponse.size());
searchResponse.forEach(item -> list.add(JSON.parseObject(JSON.toJSONString(item), tClass)));
return list;
}
@Override
public <T> IndexResponse saveEntity(String index, String type, String id, T t) {
IndexResponse indexResponse = null;
try {
IndexRequest indexRequest = new IndexRequest(index, type , id);
indexRequest.source(JSON.toJSONString(t) , XContentType.JSON);
/*BulkRequest bulkRequest = new BulkRequest();
bulkRequest.add(indexRequest);
Header basicHeader = new BasicHeader("Content-Type:application" , "json");*/
//this.client.bulk(bulkRequest , basicHeader);
indexResponse = this.client.index(indexRequest);
} catch (IOException e) {
e.printStackTrace();
}
return indexResponse;
}
}
4、es插入、查询测试类:
package com.fcbox.fms.report.web.controller;
import com.fcbox.fms.base.web.controller.BaseController;
import com.fcbox.fms.domain.user.FmsUserDto;
import com.fcbox.fms.elasticSearch.service.ISearchClient;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.MatchPhraseQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
@RequestMapping("/testLocalController")
/**
* es测试类
* @since 2018-05-24
* @author 002157
* @version V1.0
*/
public class testLocalController extends BaseController {
private final Logger LOG = LoggerFactory.getLogger(testLocalController.class);
@Autowired
private ISearchClient iSearchClient;
@RequestMapping("/testEs")
@ResponseBody
public void testEs() throws Exception {
//插入数据
for(int i=11;i<20;i++){
FmsUserDto user = new FmsUserDto();
user.setName("es测试数据名称1");
user.setCompanyname("测试企业2");
user.setId(Long.valueOf(i+""));
IndexResponse indexResponse = iSearchClient.saveEntity("mytest", "testBean", i+"",user );
System.out.println(indexResponse.toString());
}
//es查询
SearchRequest request =new SearchRequest();
//数据库名称
request.indices("mytest");
//表名
request.types("testBean");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchQuery("name", "数据"))
.query(QueryBuilders.matchQuery("companyname", "开心"));
//设置排序
sourceBuilder.sort("id",SortOrder.DESC);
//设置分页
sourceBuilder.from(0);
sourceBuilder.size(5);
request.source(sourceBuilder);
List<FmsUserDto> users = iSearchClient.search(request, FmsUserDto.class);
System.out.println("user :"+users.toString());
}
@RequestMapping("/testMoreEs")
@ResponseBody
public void testMoreEs() throws Exception {
//多条件设置
SearchRequest request =new SearchRequest();
request.indices("mytest");
request.types("testBean");
MatchPhraseQueryBuilder mpq1 = QueryBuilders.matchPhraseQuery("name","数据");
MatchPhraseQueryBuilder mpq2 = QueryBuilders.matchPhraseQuery("companyname","企业");
QueryBuilder qb2 = QueryBuilders.boolQuery().must(mpq1).must(mpq2);
SearchSourceBuilder sourceBuilderm = new SearchSourceBuilder();
sourceBuilderm.query(qb2);
sourceBuilderm.sort("id",SortOrder.DESC);
sourceBuilderm.from(0);
sourceBuilderm.size(5);
request.source(sourceBuilderm);
List<FmsUserDto> users = iSearchClient.search(request, FmsUserDto.class);
System.out.println("user :"+users.toString());
}
}
5、es进行深度分页的性能是比较差的,当我们要拉取全量数据的时候,经常会用到scroll API 拉取全量数据。主要的思路是每次拉取少量的数据,同时返回一个scrollId,通过scrollid获取下一批数据循环。
@Test
public void test3(){
RestClient lowLevelRestClient = RestClient.builder(
new HttpHost("172.16.73.50", 9200, "http")).build();
RestHighLevelClient client =
new RestHighLevelClient(lowLevelRestClient);
SearchRequest searchRequest = new SearchRequest("bank");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
MatchAllQueryBuilder mqb = QueryBuilders.matchAllQuery();
searchSourceBuilder.query(mqb);
searchSourceBuilder.size(10);
searchRequest.source(searchSourceBuilder);
searchRequest.scroll(TimeValue.timeValueMinutes(1L));
try {
SearchResponse searchResponse = client.search(searchRequest);
String scrollId = searchResponse.getScrollId();
SearchHit[] hits = searchResponse.getHits().getHits();
System.out.println("first scroll:");
for (SearchHit searchHit : hits) {
System.out.println(searchHit.getSourceAsString());
}
Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L));
System.out.println("loop scroll:");
while(hits != null && hits.length>0){
SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
scrollRequest.scroll(scroll);
searchResponse = client.searchScroll(scrollRequest);
scrollId = searchResponse.getScrollId();
hits = searchResponse.getHits().getHits();
for (SearchHit searchHit : hits) {
System.out.println(searchHit.getSourceAsString());
}
}
ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
clearScrollRequest.addScrollId(scrollId);
ClearScrollResponse clearScrollResponse = client.clearScroll(clearScrollRequest);
boolean succeeded = clearScrollResponse.isSucceeded();
System.out.println("cleared:"+succeeded);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
6、链接方式,有兴趣的可以从我的github下载下来看看,基本也就是上面贴出来的代码https://github.com/linqing5407/javaPro.git