elasticsearch 集群的搭建 和 概念这里不说
主要记录下,自己工作中要去集成es 时,选用操作es的方式
三种方式
操作es的主要有三种方式:
第一种 :spring date es ,这种方式简单,多用于一些简单业务,但因为方法都帮你封装好了,灵活度不高!(复杂业务不推荐)
第二种 :transportClient ,这种方式,官方已经明确表示在ES 7.0版本中将弃用TransportClient客户端,且在8.0版本中完全移除它
第三种 :REST Client 这种方式是基于http 与 es 通信,方便(官网推荐),主要有restHighLevelClient 和restlowLevelClient俩版本,这里也是我是选用的方式.
依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>esearch</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>esearch</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Java Low Level REST Client -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>6.3.2</version>
</dependency>
<!-- Java High Level REST Client -->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.3.2</version>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<!--<version>4.3.10.RELEASE</version>-->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties 配置
集群用","连接
elasticSearch.hostlist=127.0.0.1:9201,127.0.0.1:9200
elasticSearch.client.connectNum=10
elasticSearch.client.connectPerRoute=50
配置REST Client
这里配置了restHighLevelClient 和restlowLevelClient 两种 ,因为restHighLevelClient 还有不完善的地方,可以用restlowLevelClient 补充
@Configuration
@ComponentScan(basePackageClasses=ESClientSpringFactory.class)
public class ElasticsearchConfig {
@Value("${elasticSearch.client.connectNum}")
private Integer connectNum;
@Value("${elasticSearch.client.connectPerRoute}")
private Integer connectPerRoute;
@Value("${elasticSearch.hostlist}")
private String hostlist;
@Bean
public HttpHost[] httpHost(){
//解析hostlist配置信息
String[] split = hostlist.split(",");
//创建HttpHost数组,其中存放es主机和端口的配置信息
HttpHost[] httpHostArray = new HttpHost[split.length];
for(int i=0;i<split.length;i++){
String item = split[i];
httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
}
return httpHostArray;
}
@Bean(initMethod="init",destroyMethod="close")
public ESClientSpringFactory getFactory(){
return ESClientSpringFactory.
build(httpHost(), connectNum, connectPerRoute);
}
@Bean
@Scope("singleton")
public RestClient getRestClient(){
return getFactory().getClient();
}
@Bean(name = "restHighLevelClient")
@Scope("singleton")
public RestHighLevelClient getRHLClient(){
return getFactory().getRhlClient();
}
}
配置ESClientSpringFactory
public class ESClientSpringFactory {
public static int CONNECT_TIMEOUT_MILLIS = 1000;
public static int SOCKET_TIMEOUT_MILLIS = 30000;
public static int CONNECTION_REQUEST_TIMEOUT_MILLIS = 500;
public static int MAX_CONN_PER_ROUTE = 10;
public static int MAX_CONN_TOTAL = 30;
private static HttpHost[] HTTP_HOST;
private RestClientBuilder builder;
private RestClient restClient;
private RestHighLevelClient restHighLevelClient;
private static ESClientSpringFactory esClientSpringFactory = new ESClientSpringFactory();
private ESClientSpringFactory(){}
public static ESClientSpringFactory build(HttpHost[] httpHostArray,
Integer maxConnectNum, Integer maxConnectPerRoute){
HTTP_HOST = httpHostArray;
MAX_CONN_TOTAL = maxConnectNum;
MAX_CONN_PER_ROUTE = maxConnectPerRoute;
return esClientSpringFactory;
}
public static ESClientSpringFactory build(HttpHost[] httpHostArray,Integer connectTimeOut, Integer socketTimeOut,
Integer connectionRequestTime,Integer maxConnectNum, Integer maxConnectPerRoute){
HTTP_HOST = httpHostArray;
CONNECT_TIMEOUT_MILLIS = connectTimeOut;
SOCKET_TIMEOUT_MILLIS = socketTimeOut;
CONNECTION_REQUEST_TIMEOUT_MILLIS = connectionRequestTime;
MAX_CONN_TOTAL = maxConnectNum;
MAX_CONN_PER_ROUTE = maxConnectPerRoute;
return esClientSpringFactory;
}
public void init(){
builder = RestClient.builder(HTTP_HOST);
setConnectTimeOutConfig();
setMutiConnectConfig();
restClient = builder.build();
restHighLevelClient = new RestHighLevelClient(builder);
System.out.println("init factory");
}
// 配置连接时间延时
public void setConnectTimeOutConfig(){
builder.setRequestConfigCallback(requestConfigBuilder -> {
requestConfigBuilder.setConnectTimeout(CONNECT_TIMEOUT_MILLIS);
requestConfigBuilder.setSocketTimeout(SOCKET_TIMEOUT_MILLIS);
requestConfigBuilder.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT_MILLIS);
return requestConfigBuilder;
});
}
// 使用异步httpclient时设置并发连接数
public void setMutiConnectConfig(){
builder.setHttpClientConfigCallback(httpClientBuilder -> {
httpClientBuilder.setMaxConnTotal(MAX_CONN_TOTAL);
httpClientBuilder.setMaxConnPerRoute(MAX_CONN_PER_ROUTE);
return httpClientBuilder;
});
}
public RestClient getClient(){
return restClient;
}
public RestHighLevelClient getRhlClient(){
return restHighLevelClient;
}
public void close() {
if (restClient != null) {
try {
restClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("close client");
}
}
配置esUtils
public final class SpringBeanUtil
{
private SpringBeanUtil()
{
}
/**
* 根据bean名称获取
*
* @param name
* @return
*/
public static Object getBean(String name)
{
return ApplicationContextRegister.getApplicationContext().getBean(name);
}
}
@Component
public class ApplicationContextRegister implements ApplicationContextAware {
private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationContextRegister.class);
private static ApplicationContext APPLICATION_CONTEXT;
/**
* 设置spring上下文 * * @param applicationContext spring上下文 * @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
LOGGER.debug("ApplicationContext registed-->{}", applicationContext);
APPLICATION_CONTEXT = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return APPLICATION_CONTEXT;
}
}
public class EsUtils {
private static RestHighLevelClient client;
public static RestHighLevelClient getInstance() {
if (client == null) {
synchronized (RestHighLevelClient.class) {
if (client == null) {
client = (RestHighLevelClient) SpringBeanUtil.getBean("restHighLevelClient");
System.out.println(client);
}
}
}
return client;
}
public static void main(String[] args) {
getInstance();
}
/**
* 创建索引
*
* @param index 索引名称
* @param type 类型名称,可传入多个type逗号分隔
* @param arg1 分片数
* @param arg2 副本数
* @param source 需要设置的映射(配置是否分词,是否索引等)
* @return boolean
*/
public static boolean addIndex(String index, String type, int arg1, int arg2, String source) {
CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
//设置索引参数
createIndexRequest.settings(Settings.builder().put("number_of_shards", arg1).put("number_of_replicas", arg2));
//操作索引的客户端
createIndexRequest.mapping(type, source, XContentType.JSON);
IndicesClient indices = getInstance().indices();
//执行创建
CreateIndexResponse createIndexResponse = null;
try {
indices.create(createIndexRequest);
} catch (IOException e) {
e.printStackTrace();
}
//得到响应
return true;
}
/**
* 删除索引
*
* @param index 索引名称
* @return boolean
*/
public static boolean delIndex(String index) throws IOException {
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index);
//操作索引的客户端
IndicesClient indices = getInstance().indices();
//执行删除
DeleteIndexResponse deleteIndexResponse = indices.delete(deleteIndexRequest);
//得到响应
return deleteIndexResponse.isAcknowledged();
}
/**
* 添加数据
*
* @param index 索引名称
* @param type 类型
* @param jsonObject json对象(要添加的数据)
* @return boolean
*/
public static boolean addDoc(String index, String type, String id, JSONObject jsonObject) {
//索引请求对象
IndexRequest indexRequest = new IndexRequest(index, type, id);
indexRequest.source(jsonObject);
//索引响应对象
try {
getInstance().index(indexRequest);
} catch (IOException e) {
e.printStackTrace();
}
//获取响应结果
return true;
}
/**
* 修改数据
*
* @param index 索引名称
* @param type 类型
* @param jsonObject json对象(要添加的数据)
* @param id
* @return RestStatus ok
*/
public static boolean updateDoc(String index, String type, JSONObject jsonObject, String id) {
UpdateRequest updateRequest = new UpdateRequest(index, type, id);
updateRequest.doc(jsonObject);
//索引响应对象
UpdateResponse update = null;
try {
getInstance().update(updateRequest);
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
/**
* 删除数据
*
* @param index 索引名称
* @param type 类型
* @param id 文档id(即某条数据的id)
* @return RestStatus ok
*/
public static boolean deleteDoc(String index, String type, String id) {
DeleteRequest deleteRequest = new DeleteRequest(index, type, id);
//索引响应对象
try {
getInstance().delete(deleteRequest);
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
/**
* 使用分词查询
*
* @param index 索引名称
* @param type 类型
* @param fields 需要显示的字段,逗号分隔(缺省为全部字段)
* @param query 查询条件
* @param sortField 排序字段(倒序)
* @return List<Map < String, Object>>
*/
public static List<Map<String, Object>> search(String index, String type, String fields, QueryBuilder query, String sortField, String highlightField) {
//搜索对象
SearchRequest searchRequest = new SearchRequest(index);
//设置类型
searchRequest.types(type);
//搜索源对象构建
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//搜索条件
searchSourceBuilder.query(query);
//设置按字段排序
if (StringUtils.isNotEmpty(sortField)) {
searchSourceBuilder.sort(sortField, SortOrder.DESC);
}
//过滤字段
if (StringUtils.isNotEmpty(fields)) {
searchSourceBuilder.fetchSource(fields.split(","), null);
}
return trySearch(searchRequest, searchSourceBuilder, highlightField);
}
/**
* 使用分词查询 并分页
*
* @param index 索引名称
* @param type 类型
* @param fields 需要显示的字段,逗号分隔(缺省为全部字段)
* @param query 查询条件
* @param sortField 排序字段
* @param highlightField 高亮字段
* @return List<Map < String, Object>>
*/
public static List<Map<String, Object>> searchPage(
String index, String type, String fields, QueryBuilder query,
String sortField, int size, int page, String highlightField) {
//搜索对象
SearchRequest searchRequest = new SearchRequest(index);
//设置类型
searchRequest.types(type);
//搜索源对象构建0
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//计算起始下标
int from = (page - 1) * size;
searchSourceBuilder.from(from);//起始下标,从0开始
searchSourceBuilder.size(size);//每页记录数
//设置搜索条件
searchSourceBuilder.query(query);
//过滤字段
if (StringUtils.isNotEmpty(fields)) {
searchSourceBuilder.fetchSource(fields.split(","), null);
}
//设置按字段排序
if (StringUtils.isNotEmpty(sortField)) {
searchSourceBuilder.sort(sortField, SortOrder.DESC);
}
return trySearch(searchRequest, searchSourceBuilder, highlightField);
}
/**
* 进行搜索
*
* @param searchRequest
* @param searchSourceBuilder
*/
public static List<Map<String, Object>> trySearch(SearchRequest searchRequest, SearchSourceBuilder searchSourceBuilder, String highlightField) {
//设置搜索源
searchRequest.source(searchSourceBuilder);
//设置高亮
if (StringUtils.isNotEmpty(highlightField)) {
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.preTags("<highlight>");
highlightBuilder.postTags("</highlight>");
highlightBuilder.fields().add(new HighlightBuilder.Field(highlightField));
searchSourceBuilder.highlighter(highlightBuilder);
}
//执行搜索
SearchResponse searchResponse = null;
try {
searchResponse = getInstance().search(searchRequest);
} catch (IOException e) {
e.printStackTrace();
}
//搜索匹配结果
SearchHits hits = searchResponse.getHits();
//搜索总记录数
long totalHits = hits.getTotalHits();
System.out.println("搜索总记录数=====" + totalHits);
//匹配度较高的前n的文档
SearchHit[] searchHits = hits.getHits();
List<Map<String, Object>> searchList = new ArrayList<>();
for (SearchHit hit : searchHits) {
//文档id
String id = hit.getId();
//源文档内容
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
//获取源文档需要高亮的字段
String name = (String) sourceAsMap.get(highlightField);
//取出高亮字段
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
if (highlightFields != null) {
//取出name高亮字段
HighlightField nameField = highlightFields.get(highlightField);
if (nameField != null) {
Text[] fragments = nameField.fragments();
StringBuffer stringBuffer = new StringBuffer();
for (Text text : fragments) {
stringBuffer.append(text);
}
name = stringBuffer.toString();
hit.getSourceAsMap().put(highlightField, name);
}
}
searchList.add(hit.getSourceAsMap());
System.out.println(name);
}
return searchList;
}
}
测试代码
@RestController
@RequestMapping("/es")
public class TestController {
@RequestMapping("/search")
public List<Map<String, Object>> test(){
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("酒", "name");
List<Map<String, Object>> search = EsUtils.search("test", "doc", null, multiMatchQueryBuilder, null, "name");
return search;
}
@RequestMapping("/page")
public List<Map<String, Object>> aa() {
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("酒", "name");
List<Map<String, Object>> aa = EsUtils.searchPage("test", "doc", null, multiMatchQueryBuilder, null, 1,1,"");
return aa;
}
@RequestMapping("/del")
public void del() throws IOException {
EsUtils.delIndex("test");
}
@RequestMapping("/add")
public void add() {
EsUtils.addIndex("test","doc",1,0,"{\n" +
" \"properties\": {\n" +
" \t \"id\": {\n" +
" \"type\": \"text\"\n" +
" },\n" +
" \"name\": {\n" +
" \"type\": \"text\"\n" +
" },\n" +
" \"describe\": {\n" +
" \"type\": \"text\"\n" +
" },\n" +
" \"pic\": {\n" +
" \"type\": \"text\",\n" +
" \"index\": false\n" +
" }\n" +
" }\n" +
"}");
}
@RequestMapping("/addDoc")
public void addDoc() {
//指定索引添加文档
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", "a");
jsonObject.put("name", "你的酒馆对我打了样");
jsonObject.put("describe", "这一首简单的你的酒馆对我打了样....");
jsonObject.put("pic", "10");
EsUtils.addDoc("test","doc","1",jsonObject);
}
@RequestMapping("/updateDoc")
public void updateDoc() {
//指定索引添加文档
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", "b");
jsonObject.put("name", "你的酒馆对我打样");
jsonObject.put("describe", "这一首简单的你的酒馆对我打样....");
jsonObject.put("pic", "20");
EsUtils.updateDoc("test","doc",jsonObject,"1");
}
@RequestMapping("/delDoc")
public void delDoc() {
EsUtils.deleteDoc("test","doc","1");
}
}
以上代码亲测有效!希望能帮助大家!如果有错误,也希望多多指教!