Java连接ElasticSearch的2种方式
有两种方式:
一种 是9200端口(RestClient)rest 接口,基于http协议;
另一种是用 节点的9300端口(TransportClient),基于Tcp协议;(不推荐使用,理由如下)
es7.X 版本的改变
简单点说就是 TransportClient 在es7后不支持了,所以你要用 java high level rest client,这个是用http的请求)
所以 ,后面都 是采用9200端口的方式!!!
es6.X 以下的版本
elasticsearch 官网推荐是使用基于http协议的restClient去充当客户端连接ES,
如果想基于TCP协议,9300端口从传输层获取es文档数据也是可以的;但es7以上版本不支持
SpringBoot整合ES的三种方式(API、REST Client、Data-ES)
这种方式,官方已经明确表示在ES 7.0版本中将弃用TransportClient客户端,且在8.0版本中完全移除它。
参考:
Java连接ElasticSearch(springboot2.X配置ES连接的方式)
springboot整合elasticsearch7.2(基于官方high level client)
————————————————
版本搭配:
SpringBoot 2.1.8,ES 7.6.0
代码部分
1 maven依赖(springboot等忽略)
7.6.0
org.elasticsearch.client
elasticsearch-rest-high-level-client
${elasticsearch.version}
2 配置文件
es.host=127.0.0.1
es.port=9200,9201,9202
es.scheme=http
3 EsUtil
import com.alibaba.fastjson.JSON;
import com.trs.data.es.EsEntity;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Component
public class EsUtil {
@Value("${es.host}")
public String host;
@Value("${es.port}")
public String port;
@Value("${es.scheme}")
public String scheme;
/**
* 创建es连接
*/
@PostConstruct
public void initClient() {
try {
if (client != null) {
client.close();
}
String[] ports = port.split(",");
HttpHost[] httpHosts = new HttpHost[ports.length];
for (int i = 0; i < ports.length; i++) {
httpHosts[i] = new HttpHost(host, Integer.parseInt(ports[i]), scheme);
}
client = new RestHighLevelClient(RestClient.builder(httpHosts));
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
/**
* Description: 插入/更新一条记录
*
* @param index index
* @param entity 对象
* @author fanxb
* @date 2019/7/24 15:02
*/
public void insertOrUpdateOne(String index, EsEntity entity) {
IndexRequest request = new IndexRequest(index);
request.id(entity.getId());
request.source(JSON.toJSONString(entity.getData()), XContentType.JSON);
try {
client.index(request, RequestOptions.DEFAULT);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Description: 批量插入数据
*
* @param index index
* @param list 带插入列表
* @author fanxb
* @date 2019/7/24 17:38
*/
public void insertBatch(String index, List list) {
BulkRequest request = new BulkRequest();
list.forEach(item -> request.add(new IndexRequest(index).id(item.getId())
.source(JSON.toJSONString(item.getData()), XContentType.JSON)));
try {
client.bulk(request, RequestOptions.DEFAULT);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Description: 批量删除
*
* @param index index
* @param idList 待删除列表
* @author fanxb
* @date 2019/7/25 14:24
*/
public void deleteBatch(String index, Collection idList) {
BulkRequest request = new BulkRequest();
idList.forEach(item -> request.add(new DeleteRequest(index, item.toString())));
try {
client.bulk(request, RequestOptions.DEFAULT);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Description: 搜索
*
* @param index index
* @param builder 查询参数
* @param c 结果类对象
* @return java.util.ArrayList
* @author fanxb
* @date 2019/7/25 13:46
*/
public List search(String index, SearchSourceBuilder builder, Class c) {
SearchRequest request = new SearchRequest(index);
request.source(builder);
try {
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHit[] hits = response.getHits().getHits();
List res = new ArrayList<>(hits.length);
for (SearchHit hit : hits) {
res.add(JSON.parseObject(hit.getSourceAsString(), c));
}
return res;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Description: 删除index
*
* @param index index
* @return void
* @author fanxb
* @date 2019/7/26 11:30
*/
public void deleteIndex(String index) {
try {
client.indices().delete(new DeleteIndexRequest(index), RequestOptions.DEFAULT);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Description: delete by query
*
* @param index index
* @param builder builder
* @author fanxb
* @date 2019/7/26 15:16
*/
public void deleteByQuery(String index, QueryBuilder builder) {
DeleteByQueryRequest request = new DeleteByQueryRequest(index);
request.setQuery(builder);
//设置批量操作数量,最大为10000
request.setBatchSize(10000);
request.setConflicts("proceed");
try {
client.deleteByQuery(request, RequestOptions.DEFAULT);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static final String INDEX_NAME = "book-index";
public static final String CREATE_INDEX = "{\n" +
" \"properties\": {\n" +
" \"id\":{\n" +
" \"type\":\"integer\"\n" +
" },\n" +
" \"userId\":{\n" +
" \"type\":\"integer\"\n" +
" },\n" +
" \"name\":{\n" +
" \"type\":\"text\",\n" +
" \"analyzer\": \"ik_max_word\",\n" +
" \"search_analyzer\": \"ik_smart\"\n" +
" },\n" +
" \"url\":{\n" +
" \"type\":\"text\",\n" +
" \"index\": true,\n" +
" \"analyzer\": \"ik_max_word\",\n" +
" \"search_analyzer\": \"ik_smart\"\n" +
" }\n" +
" }\n" +
" }";
public static RestHighLevelClient client = null;
/**
* 初始化索引
*/
public void initIndex() {
try {
if (this.indexExist(INDEX_NAME)) {
return;
}
CreateIndexRequest request = new CreateIndexRequest(INDEX_NAME);
request.settings(Settings.builder().put("index.number_of_shards", 3).put("index.number_of_replicas", 2));
request.mapping(CREATE_INDEX, XContentType.JSON);
CreateIndexResponse res = client.indices().create(request, RequestOptions.DEFAULT);
if (!res.isAcknowledged()) {
throw new RuntimeException("初始化失败");
}
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
/**
* Description: 判断某个index是否存在
*
* @param index index名
* @return boolean
* @author fanxb
* @date 2019/7/24 14:57
*/
public boolean indexExist(String index) throws Exception {
GetIndexRequest request = new GetIndexRequest(index);
request.local(false);
request.humanReadable(true);
request.includeDefaults(false);
return client.indices().exists(request, RequestOptions.DEFAULT);
}
}
实体和样例接口
Book.java
public class Book {
private Integer id;
private Integer userId;
private String name;
public Book() {
}
public Book(Integer id, Integer userId, String name) {
this.id = id;
this.userId = userId;
this.name = name;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", userId=" + userId +
", name='" + name + '\'' +
'}';
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
EsEntity.java
public final class EsEntity {
private String id;
private T data;
public EsEntity() {
}
public EsEntity(String id, T data) {
this.data = data;
this.id = id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
BookController
import com.trs.data.task.util.EsUtil;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/book")
public class BookController {
@Autowired
private EsUtil esUtil;
/**
* @param id 获取某一个
*/
@GetMapping("/{id}")
public Book getById(@PathVariable("id") int id) {
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.query(new TermQueryBuilder("id", id));
List res = esUtil.search(EsUtil.INDEX_NAME, builder, Book.class);
if (res.size() > 0) {
return res.get(0);
} else {
return null;
}
}
/**
* 获取全部
*/
@GetMapping("/")
public List getAll() {
return esUtil.search(EsUtil.INDEX_NAME, new SearchSourceBuilder(), Book.class);
}
/**
* 根据关键词搜索某用户下的书
*
* @param content 关键词
*/
@GetMapping("/search")
public List searchByUserIdAndName(int userId, String content) {
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
boolQueryBuilder.must(QueryBuilders.termQuery("userId", userId));
boolQueryBuilder.must(QueryBuilders.matchQuery("name", content));
SearchSourceBuilder builder = new SearchSourceBuilder();
builder.size(10).query(boolQueryBuilder);
return esUtil.search(EsUtil.INDEX_NAME, builder, Book.class);
}
/**
* 单个插入
*
* @param book book
*/
@PutMapping("/")
public void putOne(@RequestBody Book book) {
EsEntity entity = new EsEntity<>(book.getId().toString(), book);
esUtil.insertOrUpdateOne(EsUtil.INDEX_NAME, entity);
}
/**
* 批量插入
*
* @param books books
*/
@PutMapping("/many")
public void putList(@RequestBody List books) {
List list = new ArrayList<>();
books.forEach(item -> list.add(new EsEntity<>(item.getId().toString(), item)));
esUtil.insertBatch(EsUtil.INDEX_NAME, list);
}
/**
* 批量删除
*
* @param list list
*/
@DeleteMapping("/deleteBatch")
public void deleteBatch(List list) {
esUtil.deleteBatch(EsUtil.INDEX_NAME, list);
}
/**
* delete by query 根据用户id删除数据
*
* @param userId userId
*/
@DeleteMapping("/userId/{userId}")
public void deleteByUserId(@PathVariable("userId") int userId) {
esUtil.deleteByQuery(EsUtil.INDEX_NAME, new TermQueryBuilder("userId", userId));
}
}
最后补充一下我遇到的小坑:NoSuchFieldError: LUCENE_7_0_0
问题找了挺久的,结果是jar冲突,lucene-core.jar冲突了,解决以后就行了
还学到个小知识
可变参数的接口,当不确定参数个数调用时,可以用传入数组。反之则不行
接口:public static RestClientBuilder builder(HttpHost... hosts);
调用:
HttpHost[] httpHosts = new HttpHost[3];
builder(httpHosts);