SpringBoot+RestHighLevelClient集成ElasticSearch

搭建准备

ElasticSearch 7.0.0 已经对Transport client 方式弃用了,且在8.0版本中完全移除它。而且springboot yml 的 Transport配置 也过期了。虽然之前用Transport 的方式特别好用😂,但是没办法,既然官方说弃用了,那我们就用另外一种方式:RestHighLevelClient
在这里插入图片描述

注意
1.es版本与maven 版本一致 本次用的是7.4.0
2.maven es 依赖版本写法使用properties 标签,不然可能会出现
java.lang.NoSuchMethodError: org.elasticsearch.client.Request.addParameters(Ljava/util/Map;)V
错误
3.es 下载解压之后 修改 config 目录下的 elasticsearch.yml 打开
cluster.name: my-application 和 node.name: node-1 注释

环境依赖配置

pom.xml

<properties>
		<elasticsearch.version>7.4.0</elasticsearch.version>
</properties>
<dependencies>
		<dependency>
			<groupId>org.elasticsearch.client</groupId>
			<artifactId>elasticsearch-rest-high-level-client</artifactId>
			<version>${elasticsearch.version}</version>
		</dependency>
		<dependency>
			<groupId>org.elasticsearch</groupId>
			<artifactId>elasticsearch</artifactId>
			<version>${elasticsearch.version}</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.12</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.62</version>
		</dependency>
		<dependency>		
</dependencies>

lombok 和fastjson 是本次实例需要用到的包

application.yml

elasticsearch:
  host: localhost
  port: 9200
  connectNum: 10
  connectPerRoute: 50

创建 RestHighLevelClient 客户端

ESClientSpringFactory.java


import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;

import java.io.IOException;

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 httpHost,
                                              Integer maxConnectNum, Integer maxConnectPerRoute){
        HTTP_HOST = httpHost;
        MAX_CONN_TOTAL = maxConnectNum;
        MAX_CONN_PER_ROUTE = maxConnectPerRoute;
        return  esClientSpringFactory;
    }

    public static ESClientSpringFactory build(HttpHost httpHost,Integer connectTimeOut, Integer socketTimeOut,
                                              Integer connectionRequestTime,Integer maxConnectNum, Integer maxConnectPerRoute){
        HTTP_HOST = httpHost;
        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");
    }
}

ESConfig.java


import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Configuration
@Component
@ConfigurationProperties(prefix = "elasticsearch")//配置注解表示这个类可以读取所有yml以 "elasticSearch"开头的配置项
public class ESConfig {

    private String host;

    private int port;

    private Integer connectNum;

    private Integer connectPerRoute;

    @Bean
    public HttpHost httpHost(){
        return new HttpHost(host,port,"http");
    }

    @Bean(initMethod="init",destroyMethod="close")
    public ESClientSpringFactory getFactory(){
        return ESClientSpringFactory.
                build(httpHost(), connectNum, connectPerRoute);
    }

    @Bean
    @Scope("singleton")
    public RestClient getRestClient(){
        return getFactory().getClient();
    }

    @Bean
    @Scope("singleton")
    public RestHighLevelClient getRHLClient(){
        return getFactory().getRhlClient();
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public Integer getConnectNum() {
        return connectNum;
    }

    public void setConnectNum(Integer connectNum) {
        this.connectNum = connectNum;
    }

    public Integer getConnectPerRoute() {
        return connectPerRoute;
    }

    public void setConnectPerRoute(Integer connectPerRoute) {
        this.connectPerRoute = connectPerRoute;
    }
}


这样就可以尽情使用RestHighLevelClient 客户端了

测试API

准备测试实体类


import lombok.Data;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;

import java.util.Date;
import java.util.Map;

/**
 * @program: esdemo
 * @description
 * @author: liuhui
 * @create: 2020-05-09 12:45
 **/
@Data
public class Twitter {

    private Long id;

    private String user;

    private Date postDate;

    private String message;

    private Map<String, HighlightField> highlight;


}

测试用例都是参照官网api 官网链接

	@Resource
	private RestHighLevelClient client;

创建索引

	@Test
	public void createIndex() {

		CreateIndexRequest request = new CreateIndexRequest("twitter");

		try {
			CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
			System.out.println(createIndexResponse);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

官网还有很多方式和配置,这里就不举例了

是否存在索引

	@Test
	public void indexExists(){

		GetIndexRequest request = new GetIndexRequest("twitter");

		try {
			boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
			System.out.println(exists);

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

删除索引

	@Test
	public void deleteIndex() {

		DeleteIndexRequest request = new DeleteIndexRequest("twitter");

		try {
			AcknowledgedResponse acknowledgedResponse =client.indices().delete(request, RequestOptions.DEFAULT);
			System.out.println(acknowledgedResponse);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

新增数据

	/**
	 * map 方式
	 */
	@Test
	public void add(){
		Map<String, Object> jsonMap = new HashMap<>();
		jsonMap.put("user", "kimchy");
		jsonMap.put("postDate", new Date());
		jsonMap.put("message", "trying out Elasticsearch");
		IndexRequest indexRequest = new IndexRequest("twitter")
				.id("1").source(jsonMap);

		try {
			client.index(indexRequest, RequestOptions.DEFAULT);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 利用阿里巴巴 JSON库  将对象转化为 json 插入
	 */
	@Test
	public void add1(){

		Twitter twitter = new Twitter();
		twitter.setId(2L);
		twitter.setMessage("hello twitter!");
		twitter.setPostDate(new Date());
		twitter.setUser("kimchy");

		IndexRequest request = new IndexRequest("twitter");
		request.id(String.valueOf(twitter.getId()));
		request.source(JSON.toJSONString(twitter), XContentType.JSON);
		try {
			client.index(request, RequestOptions.DEFAULT);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}


	/**
	 * 利用XContentBuilder 方式插入
	 * @throws IOException
	 */
	@Test
	public void add2() throws IOException {

		XContentBuilder builder = XContentFactory.jsonBuilder();
		builder.startObject();
		{
			builder.field("user", "kimchy");
			builder.timeField("postDate", new Date());
			builder.field("message", "trying out Elasticsearch");
		}
		builder.endObject();
		IndexRequest indexRequest = new IndexRequest("twitter")
				.id("3").source(builder);

		try {
			client.index(indexRequest, RequestOptions.DEFAULT);
		} catch (IOException e) {
			e.printStackTrace();
		}


	}

这里参照官网写了3种方式,map ,json ,利用XContentBuilder 的方式。

修改数据

	/**
	 *  UpdateRequest 第一个参数是 索引,第二个参数是 数据主键id ,表示修改id 为1 的 twitter 数据
	 */
	@Test
	public void update(){
		Map<String, Object> jsonMap = new HashMap<>();
		jsonMap.put("user", "kimchy1");
		jsonMap.put("postDate", new Date());
		jsonMap.put("message", "trying update Elasticsearch");
		UpdateRequest request = new UpdateRequest("twitter", "1")
				.doc(jsonMap);

		try {
			UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT);
			System.out.println(updateResponse);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}



	@Test
	public void update1(){
		Twitter twitter = new Twitter();
		twitter.setId(1L);
		twitter.setMessage("hello twitter update!");
		twitter.setPostDate(new Date());
		twitter.setUser("kimchy");

		UpdateRequest request = new UpdateRequest("twitter", String.valueOf(twitter.getId()))
				.doc(JSON.toJSONString(twitter), XContentType.JSON);

		try {
			UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT);
			System.out.println(updateResponse);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	@Test
	public void update2() throws IOException {
		XContentBuilder builder = XContentFactory.jsonBuilder();
		builder.startObject();
		{
			builder.field("user", "kimchy");
			builder.timeField("postDate", new Date());
			builder.field("message", "trying update Elasticsearch");
		}
		builder.endObject();
		UpdateRequest request = new UpdateRequest("twitter", "1")
				.doc(builder);

		try {
			UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT);
			System.out.println(updateResponse);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

这里update 方式也有3种,对应上面的新增方法,看心情使用即可了

删除数据

	/**
	 * 删除id 为1 的数据
	 */
	@Test
	public void deleteById() {

		DeleteRequest request = new DeleteRequest("twitter", "1");
		try {
			DeleteResponse deleteResponse = client.delete(request, RequestOptions.DEFAULT);

			System.out.println(deleteResponse);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

根据id 查询数据

	/**
	 * 获取id 为1 的数据
	 */
	@Test
	public void getById(){
		GetRequest getRequest = new GetRequest("twitter", "1");
		GetResponse getResponse = null;
		try {
			getResponse = client.get(getRequest, RequestOptions.DEFAULT);
			if (getResponse.isExists()) {

				Map<String,Object> map = getResponse.getSourceAsMap();

				Twitter twitter=JSON.parseObject(JSON.toJSONString(map), Twitter.class);

				System.out.println(twitter);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}

条件/分页 查询(SearchRequest)

	@Test
	public void search(){
		SearchRequest searchRequest = new SearchRequest("twitter");

		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

		//默认分词查询
		QueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("user", "你好企业")
				.fuzziness(Fuzziness.AUTO) //模糊查询
				.prefixLength(3) // 在匹配查询上设置前缀长度选项,指明区分词项的共同前缀长度,默认是0
				.maxExpansions(10); //设置最大扩展选项以控制查询的模糊过程

		//查询条件 添加,user = kimchy
		//sourceBuilder.query(QueryBuilders.termQuery("user", "kimchy"));
		sourceBuilder.query(matchQueryBuilder);


		//查询开始-结束 。可以用来分页使用
		sourceBuilder.from(0);
		sourceBuilder.size(5);

		//设置一个可选的超时,控制允许搜索的时间。
		sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

		//排序
		sourceBuilder.sort(new FieldSortBuilder("id").order(SortOrder.ASC));

		searchRequest.source(sourceBuilder);

		try {
			SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
			//处理搜索结果
			RestStatus restStatus = searchResponse.status();
			if (restStatus != RestStatus.OK){
				System.out.println("搜索错误");
			}
			List<Twitter> list = new ArrayList<>();
			SearchHits hits = searchResponse.getHits();
			hits.forEach(item -> list.add(JSON.parseObject(item.getSourceAsString(), Twitter.class)));
			System.out.println(list);


		} catch (IOException e) {
			e.printStackTrace();
		}

	}

QueryBuilders.termQuery(“key”, “vaule”); // 完全匹配
QueryBuilders.termsQuery(“key”, “vaule1”, “vaule2”) ; //一次匹配多个值
QueryBuilders.matchQuery(“key”, “vaule”) //单个匹配, field不支持通配符, 前缀具高级特性
QueryBuilders.multiMatchQuery(“text”, “field1”, “field2”); //匹配多个字段, field有通配符忒行
QueryBuilders.matchAllQuery(); // 匹配所有文件
组合查询
// Bool Query 用于组合多个叶子或复合查询子句的默认查询
// must 相当于 与 & =
// must not 相当于 非 ~ !=
// should 相当于 或 | or
// filter 过滤
QueryBuilders.boolQuery()
.must(QueryBuilders.termQuery(“key”, “value1”))
.must(QueryBuilders.termQuery(“key”, “value2”))
.mustNot(QueryBuilders.termQuery(“key”, “value3”))
.should(QueryBuilders.termQuery(“key”, “value4”))
.filter(QueryBuilders.termQuery(“key”, “value5”));

高亮查询

	/**
	 * 高亮搜索
	 * @param indexName 索引名称
	 * @param queryBuilder 查询条件
	 * @param highligtFiled 高亮字段
	 * @return
	 */
	public SearchResponse searcherHighlight(String indexName,QueryBuilder queryBuilder, String highligtFiled) {
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();//构造搜索对象
		searchSourceBuilder.query(queryBuilder);//设置查询条件
		//设置高亮
		String preTags = "<strong>";
		String postTags = "</strong>";
		HighlightBuilder highlightBuilder = new HighlightBuilder();
		highlightBuilder.preTags(preTags);//设置前缀
		highlightBuilder.postTags(postTags);//设置后缀
		highlightBuilder.field(highligtFiled);//设置高亮字段
		searchSourceBuilder.highlighter(highlightBuilder);//设置高亮信息

		SearchRequest searchRequest = new SearchRequest(indexName);//创建查询请求对象
		searchRequest.source(searchSourceBuilder);//设置searchSourceBuilder

		SearchResponse searchResponse = null;//执行查询
		try {
			searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return searchResponse;
	}



	@Test
	public void highlighting(){
		String indexName = "twitter";//索引名称
		String highligtFiled = "message";//设置高亮的字段,此处查询的是interest中含有basketball的文档,因此高亮字段设为interest
		QueryBuilder queryBuilder = QueryBuilders.matchQuery("message",
				"Elasticsearch");//查询message中含有Elasticsearch的文档
		SearchResponse searchResponse = searcherHighlight(indexName,
				 queryBuilder, highligtFiled);

		//处理搜索结果
		RestStatus restStatus = searchResponse.status();
		if (restStatus != RestStatus.OK){
			System.out.println("搜索错误");
		}
		List<Twitter> list = new ArrayList<>();
		SearchHits hits = searchResponse.getHits();
		hits.forEach(item -> {
				Twitter twitter = JSON.parseObject(item.getSourceAsString(), Twitter.class);
				Map<String, HighlightField> map = item.getHighlightFields()  ;
				System.out.println(map.toString());
				twitter.setHighlight(map);
				list.add(twitter);
			}
		);
		System.out.println(list);

	}

结束

本次实例代码地址
链接

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值