微服务解决方案 – 高效搜索Elastic Search
7.6.2 (下)
前言
上一篇ES
是我在4周前写的,由于工作原因,一直没有发布,现在我们公司已经开始使用了ES
,刚好就把这个一起写了。
微服务解决方案 – 高效搜索 Elastic Search 7.6.2 (上)
先说一下为什么我们公司要使用ES
,因为我们公司有一个表大概在20W+,我们希望能够快速的查找相似数据,进行对比。MySQL
虽然能使用like
进行查找,但是分词等技术还得想办法解决。于是我们本来是打算使用MySQL
+Drools
,进行查询使用规则引擎给每一个查询结果进行打分去实现(不过我一直觉得加上Drools
好像没什么意义)。
然后经过一段时间的讨论,最终决定还是使用ES
去 实现这种查找,20W 虽然不多,但相对于MySQL
的模糊查找来说,ES
显得更加合适。
SpringBoot
首先创建一个springboot
项目,查看一下我们的版本,因为我们公司的小伙伴使用的是2.1.8.RELEASE
,所以我得和他们保持统一。
点开parent
项目
然后点开spring-boot-start-parent
的parent
项目(葫芦娃找爷爷)
最后我们查找一下elasticsearch
的依赖
到时候得手动修改他的版本号,因为我们装的ES
是7.6.2
的版本。
我们只需要在自己的项目里的<properties></properties>
加上和他一样的标签就行。
<properties>
<!-- springboot 2.1.8.RELEASE 默认是6.4.3 手动修改版本-->
<elasticsearch.version>7.6.2</elasticsearch.version>
</properties>
<dependencies>
<!-- springboot start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
</dependencies>
这样我们的版本就被替换成正确的了
接下来就是配置springboot
,这里只贴关键代码
首先得配置es search
的配置类,
package com.laoshiren.hello.elasticsearch.provider.configure;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* ProjectName: hello-elasticsearch
* Package: com.laoshiren.hello.elasticsearch.provider.configure
* ClassName: ElasticSearchClientConfiguration
* Author: laoshiren
* Date: 2020/7/9 16:21
* Version: 1.0.0
*/
@Configuration
public class ElasticSearchClientConfiguration {
@Value("${laoshiren.elastic.hostname}")
private String hostname;
@Value("${laoshiren.elastic.port}")
private int port;
@Value("${laoshiren.elastic.scheme}")
private String scheme;
@Bean
public RestHighLevelClient restHighLevelClient(){
return new RestHighLevelClient(
RestClient.builder(
new HttpHost(hostname, port, scheme)));
}
}
包名叫configure
吧,类名应该叫XXXConfiguration
吧,配置就配置了一个RestHighLeveClient
,就相当于有了xxxTemplate
的感觉,我们拿这个东西去访问我们的ES
,这里需要3个参数scheme
,hostname
,port
,分别是协议,地址,端口。写在配置文件里。
laoshiren:
elastic:
hostname: 120.26.114.23
port: 9200
scheme: http
然后去测试类获取Client
去写一个空方法调用吧(TDD
编程嘛)
@SpringBootTest
@RunWith(SpringRunner.class)
public class ESClient {
@Test
public void runEmpty(){
}
@Resource
private RestHighLevelClient client;
@Resource
private ObjectMapper objectMapper;
@Test
public void initClient(){
System.out.println(client);
}
}
等这2个方法都不报错,我们就可以继续学习了。
API
希望大家可以使用debug的方式查看每次请求完成后的response
创建索引
@Test
public void createIndex() throws IOException {
// 索引请求
CreateIndexRequest request = new CreateIndexRequest("organization");
// 执行
CreateIndexResponse response = client.indices()
.create(request, RequestOptions.DEFAULT);
System.out.println(response.index());
}
判断索引存不存在
@Test
public void existsIndex() throws IOException {
GetIndexRequest request = new GetIndexRequest("organization");
boolean exists = client.indices()
.exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
删除索引
@Test
public void deleteIndex() throws IOException{
DeleteIndexRequest request = new DeleteIndexRequest("tb_user");
AcknowledgedResponse delete = client.indices()
.delete(request, RequestOptions.DEFAULT);
System.out.println(delete.isAcknowledged());
}
创建文档
@Test
public void createDoc() throws Exception {
TbUser tbUser = new TbUser();
tbUser.setCustomerNo("0001")
.setGrpContNo("2020")
.setFirstName("laoshiren1207")
.setTransAmt(900)
.setCreateDate(new Date());
// 指定索引
IndexRequest request = new IndexRequest("tb_user");
// 设置规则
request.id("1")
.timeout(TimeValue.timeValueSeconds(5));
// 对象转换json
request.source(objectMapper.writeValueAsString(tbUser), XContentType.JSON);
// 发送请求
IndexResponse index = client.index(request, RequestOptions.DEFAULT);
System.out.println(index.toString());
// 命令返回的状态
System.out.println(index.status());
}
文档存不存在
@Test
public void existsDoc()throws Exception{
GetRequest request = new GetRequest("tb_user","1");
boolean exists = client.exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
获取文档
@Test
public void getDoc() throws Exception{
GetRequest request = new GetRequest("tb_user","1");
GetResponse response = client.get(request, RequestOptions.DEFAULT);
// 所有信息
System.out.println(response.toString());
// 获取doc
System.out.println(response.getSourceAsString());
}
更新文档
@Test
public void postDocForUpdate() throws Exception {
UpdateRequest request = new UpdateRequest("tb_user","1");
request.timeout(TimeValue.timeValueSeconds(5));
// 新对象
TbUser tbUser = new TbUser();
// 202007111030
tbUser.setCreateDate(new Date());
// 文档类型 XContentType
request.doc(objectMapper.writeValueAsString(tbUser),XContentType.JSON);
UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
System.out.println(update.status());
}
删除文档
@Test
public void deleteDoc() throws Exception{
DeleteRequest request = new DeleteRequest("tb_user","1");
request.timeout(TimeValue.timeValueSeconds(5));
DeleteResponse delete = client.delete(request,RequestOptions.DEFAULT);
System.out.println(delete.status());
}
批量insert
操作
@Test
public void bulkInsert()throws Exception{
BulkRequest bulkRequest = new BulkRequest();
// 批量操作
bulkRequest.timeout(TimeValue.timeValueSeconds(30));
List<TbUser> list = new ArrayList<>();
TbUser tbUser =new TbUser();
tbUser.setCreateDate(new Date())
.setTransAmt(23)
.setFirstName("laoshiren")
.setGrpContNo("00001")
.setCustomerNo("00003");
list.add(tbUser);
TbUser tbUser2 =new TbUser();
tbUser2.setCreateDate(new Date())
.setTransAmt(23)
.setFirstName("周杰伦")
.setGrpContNo("00001")
.setCustomerNo("00003");
list.add(tbUser2);
// 获取索引
for (int i = 0; i< list.size(); i++) {
//批处理请求
IndexRequest index = new IndexRequest("tb_user")
.id("" + (i + 2))
// 转换json string
.source(objectMapper.writeValueAsString(list.get(i)), XContentType.JSON);
bulkRequest.add(index);
}
BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(bulk.status());
System.out.println(bulk.hasFailures());
}
搜索
@Test
public void search() throws Exception{
SearchRequest request = new SearchRequest("tb_user");
// 构造
SearchSourceBuilder builder = new SearchSourceBuilder();
// 中文或者自定义字符串就要加上 field.keyword
MatchQueryBuilder query= QueryBuilders.MatchQuery("firstName", "a");
// 构建所需查询
builder.query(query);
builder.from(0);
builder.size(5);
builder.timeout(new TimeValue(60,TimeUnit.SECONDS));
request.source(builder);
SearchResponse search = client.search(request, RequestOptions.DEFAULT);
System.out.println(search.toString());
// 所需数据
System.out.println(search.getHits());
for (SearchHit hit : search.getHits().getHits()) {
String s = objectMapper.writeValueAsString(hit);
System.out.println(s);
}
}
搜索不仅仅只有这一个他的QueryBuilders
提供了大量的条件查询比如boolQuery
,termQuery
等。像我在工作中我就会用MatchQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
map.keySet().forEach(it -> {
if (!StringUtils.isBlank(map.get(it).toString())) {
boolQuery.must(
QueryBuilders.matchQuery(it, map.get(it).toString())
// 指定分词
.analyzer(analyzer));
}
});
更多的API
可以参考其他的博主或者B站
的一些up
主,比如三太子敖丙,狂神说,lusifer
(撸帝)还有什么很多的培训机构的一些文章视频都可以看看,一些新技术他们肯定会知道了解。
熟读唐诗三百首,不会吟诗也会吟嘛
Bug
java.io.IOException: 远程主机强迫关闭了一个现有的连接。
at org.elasticsearch.client.RestClient.extractAndWrapCause(RestClient.java:828) ~[elasticsearch-rest-client-7.6.2.jar:7.6.2]
最近两天在准备测试,发现这个client
长时间连接不使用会报异常,第一次请求报错,再一次请求就恢复正常了。所以修改了一下代码
@Bean(name = "restSearchClient")
public RestHighLevelClient restHighLevelClient(){
return new RestHighLevelClient(
RestClient.builder(new HttpHost(host,port,scheme))
.setRequestConfigCallback(requestConfigBuilder -> {
requestConfigBuilder.setConnectTimeout(-1);
requestConfigBuilder.setSocketTimeout(30000);
requestConfigBuilder.setConnectionRequestTimeout(30000);
return requestConfigBuilder;
})
);
}
隔了一晚,发现加上了好像也没什么用处,所以我就打算既然连接会死,那就每个一段时间请求一下ES
服务器的的信息,即使死了,那再下次一请求这个客户端一定是可以。
@Scheduled(cron = "0 0 * * * ? ")
public void restClientKeepAlive() {
try {
log.info("schedule 保持ES客户端存活 start");
MainResponse response = restClient.info(RequestOptions.DEFAULT);
log.info("schedule 保持ES客户端存活 end");
} catch (IOException ignore) {
}
}
不知道有没有大佬还有其他的解决方法没有,可以指点一下,
联系方式 | 联系方式 |
---|---|
1027575422 | |
[email protected] |