ElasticSearch 7.0.0 已经对Transport client 方式弃用了,且在8.0版本中完全移除它。而且springboot yml 的 Transport配置 也过期了。虽然之前用Transport 的方式特别好用,但是没办法,既然官方说弃用了,那我们就用另外一种方式:RestHighLevelClient。
SpringBoot 2.X 以上 start.spring.io链接
es 下载地址 链接
RestHighLevelClient API文档 链接
maven中央仓库地址 链接
注意
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
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 客户端了
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 为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();
}
}
@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 = "";
String postTags = "";
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);
}
本次实例代码地址:
链接