一、Java REST Client介绍
Java Low Level REST Client: 低级别的REST客户端,通过http与集群交互,用户需自己编组请求JSON串,及解析响应JSON串。兼容所有ES版本。
Java High Level REST Client: 高级别的REST客户端,基于低级别的REST客户端,增加了编组请求JSON串、解析响应JSON串等相关api。使用的版本需要保持和ES服务端的版本一致,否则会有版本问题。
二、maven中引入依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.4.3</version>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.4.3</version>
</dependency>
三、Java High Level REST Client 初始化
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;
@Configuration
public class ElasticsearchConfig {
@Value("${restClient.elasticsearch.hostlist}")
private String hostlist;
@Bean
public RestHighLevelClient restHighLevelClient() {
//解析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");
}
//创建RestHighLevelClient客户端
return new RestHighLevelClient(RestClient.builder(httpHostArray));
}
//项目主要使用RestHighLevelClient,对于低级的客户端暂时不用 @Bean
public RestClient restClient() {
//解析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 RestClient.builder(httpHostArray).build();
}
}
四、试用事例
- 创建索引
@Autowired
private RestHighLevelClient client;
@Test
public void testCreateIndex() throws IOException {
//创建索引请求对象
CreateIndexRequest createIndexRequest = new CreateIndexRequest("hello_es");
createIndexRequest.settings(Settings.builder().put("number_of_shards", 1)
.put("number_of_replicas", 0).build());
createIndexRequest.mapping("doc", "{\n" +
"\t\"properties\": {\n" +
"\t\t\"name\": {\n" +
"\t\t\t\"type\": \"text\"\n" +
"\t\t},\n" +
"\t\t\"description\": {\n" +
"\t\t\t\"type\": \"text\"\n" +
"\t\t},\n" +
"\t\t\"studymodel\": {\n" +
"\t\t\t\"type\": \"keyword\"\n" +
"\t\t}\n" +
"\t}\n" +
"}", XContentType.JSON);
//创建索引客户端
IndicesClient indices = client.indices();
CreateIndexResponse createIndexResponse = indices.create(createIndexRequest,RequestOptions.DEFAULT);
boolean acknowledged = createIndexResponse.isAcknowledged();
log.info("isAcknowledged:{}", acknowledged);
}
- 删除索引
@Test
public void testDeleteIndex() throws IOException {
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("hello_es");
DeleteIndexResponse deleteIndexResponse = client.indices().delete(deleteIndexRequest);
boolean acknowledged = deleteIndexResponse.isAcknowledged();
log.info("isAcknowledged:{}", acknowledged);
}
- 添加文档
@Test
public void testAddDoc() throws IOException {
IndexRequest indexRequest = new IndexRequest("hello_es", "doc");
//一、给json格式
// indexRequest.source("{\n" +
// "\t\"name\": \"Bootstrap开发框架\",\n" +
// "\n" +
// "\t\"description\": \"Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现一个不受浏览器限制的 精美界面效果。\",\n" +
// "\n" +
// "\t\"studymodel\": \"201001\"\n" +
// "}", XContentType.JSON);
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("name", "spring cloud实战");
jsonMap.put("description", "本课程主要从四个章节进行讲解: 1.微服务架构入门 2.spring cloud基础入门3.实战SpringBoot4.注册中心eureka");
jsonMap.put("studymodel", "201001");
indexRequest.source(jsonMap);
client.index(indexRequest, RequestOptions.DEFAULT);
}
- 获取文档
@Test
public void getDoc() throws IOException {
GetRequest getRequest = new GetRequest(
"hello_es",
"doc",
"gdbSpW4BXv1xyLWLmtrS");
//选择返回的字段
String[] includes = new String[]{"name", "description", "studymodel"};
String[] excludes = Strings.EMPTY_ARRAY;
FetchSourceContext fetchSourceContext = new FetchSourceContext(true, includes, excludes);
getRequest.fetchSourceContext(fetchSourceContext);
GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
Map<String, Object> sourceAsMap = getResponse.getSourceAsMap();
System.out.println(sourceAsMap);
}
- 更新文档
//更新文档
@Test
public void updateDoc() throws IOException {
UpdateRequest updateRequest = new UpdateRequest("hello_es", "doc",
"dda3pW4BXv1xyLWLjNpZ");
Map<String, String> map = new HashMap<>();
map.put("name", "Spring Cloud实战");
updateRequest.doc(map);
UpdateResponse update = client.update(updateRequest, RequestOptions.DEFAULT);
RestStatus status = update.status();
System.out.println(status);
}
- 批量插入
@Test
public void testBulkAdd() throws IOException {
Map<String, Object> jsonMap = new HashMap<>();
jsonMap.put("name", "spring cloud实战");
jsonMap.put("description", "本课程主要从四个章节进行讲解: 1.微服务架构入门 2.spring cloud基础入门3.实战SpringBoot4.注册中心eureka");
jsonMap.put("studymodel", "201001");
BulkRequest request = new BulkRequest();
request.add(new IndexRequest("hello_es", "doc")
.source(jsonMap));
request.add(new IndexRequest("hello_es", "doc")
.source(jsonMap));
request.add(new IndexRequest("hello_es", "doc")
.source(jsonMap));
BulkResponse bulkResponse = client.bulk(request, RequestOptions.DEFAULT);
Stream.of(bulkResponse.getItems()).forEach(model -> log.info("index:{},response:{}",
model.getIndex(), model.getResponse()));
}
- 查询所有,包含分页以及排序
//查询搜索记录
@Test
public void testSearchAll() throws IOException {
SearchRequest searchRequest = new SearchRequest("hello_es");
searchRequest.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
searchRequest.source(searchSourceBuilder);
//设置需要显示的字段
searchSourceBuilder.fetchSource(new String[]{"name", "description", "studymodel"}, Strings.EMPTY_ARRAY);
//分页查询,设置起始下标,从0开始
searchSourceBuilder.from(0);
//每页显示个数
searchSourceBuilder.size(2);
//指定排序
searchSourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
// searchSourceBuilder.sort(new FieldSortBuilder("name").order(SortOrder.ASC));
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
Stream.of(searchHits).forEach(model -> {
String sourceAsString = model.getSourceAsString();
log.info("sourceAsString:{}", sourceAsString);
});
}
- 包含查询team query
//Term Query
@Test
public void testTermQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest("hello_es");
searchRequest.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
searchRequest.source(searchSourceBuilder);
//查询包括spring的结果
TermQueryBuilder termQueryBuilder = new TermQueryBuilder("name", "spring");
searchSourceBuilder.query(termQueryBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
Stream.of(searchHits).forEach(model -> {
String sourceAsString = model.getSourceAsString();
log.info("sourceAsString:{}", sourceAsString);
});
}
- 根据id精确查询
//根据id精确匹配
@Test
public void testQueryId() throws IOException {
SearchRequest searchRequest = new SearchRequest("hello_es");
searchRequest.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
String[] ids = new String[]{"gdbSpW4BXv1xyLWLmtrS"};
List<String> idList = Arrays.asList(ids);
searchSourceBuilder.query(QueryBuilders.termsQuery("_id", idList));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
Stream.of(searchHits).forEach(model -> {
String sourceAsString = model.getSourceAsString();
log.info("sourceAsString:{}", sourceAsString);
});
}
- match query
match Query即全文检索,它的搜索方式是先将搜索字符串分词,再使用各各词条从索引中搜索。
match query与Term query区别是match query在搜索前先将搜索关键字分词,再拿各各词语去索引中搜索。
下面代码查询流程分析:
1、将“spring开发”分词,分为spring、开发两个词
2、再使用spring和开发两个词去匹配索引中搜索。
3、由于设置了operator为or,只要有一个词匹配成功则就返回该文档。
//matchQuery
@Test
public void testMatchQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest("hello_es");
searchRequest.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("name", "spring开发").operator(Operator.OR));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
Stream.of(searchHits).forEach(model -> {
String sourceAsString = model.getSourceAsString();
log.info("sourceAsString:{}", sourceAsString);
});
}
- minimum_should_match
上边使用的operator = or表示只要有一个词匹配上就得分,如果实现三个词至少有两个词匹配如何实现? 使用minimum_should_match可以指定文档匹配词的占比。
下面代码查询流程分析:
“spring开发框架”会被分为三个词:spring、开发、框架
设置"minimum_should_match": "80%"表示,三个词在文档的匹配占比为80%,即3*0.8=2.4,向上取整得2,表示至少有两个词在文档中要匹配成功。
@Test
public void testMinimumShouldMatch() throws IOException {
SearchRequest searchRequest = new SearchRequest("hello_es");
searchRequest.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchQuery("description", "基础入门你好").minimumShouldMatch("80%"));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
Stream.of(searchHits).forEach(model -> {
String sourceAsString = model.getSourceAsString();
log.info("sourceAsString:{}", sourceAsString);
});
}
- multi Query and boost
单项匹配是在一个field中去匹配,多项匹配是拿关键字去多个Field中匹配,并且给某个字段提高分数
//multi Query and boost
@Test
public void testMultiQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest("hello_es");
searchRequest.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
MultiMatchQueryBuilder multiMatchQueryBuilder =
QueryBuilders.multiMatchQuery("实战", "description", "name");
multiMatchQueryBuilder.field("name", 10);
searchSourceBuilder.query(multiMatchQueryBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
Stream.of(searchHits).forEach(model -> {
String sourceAsString = model.getSourceAsString();
log.info("sourceAsString:{}", sourceAsString);
});
}
- bool query
三个参数:
must:文档必须匹配must所包括的查询条件,相当于 “AND”
should:文档应该匹配should所包括的查询条件其 中的一个或多个,相当于 “OR”
must_not:文档不能匹配must_not所包括的该查询条件,相当于“NOT”
@Test
public void testBoolQuery() throws IOException {
SearchRequest searchRequest = new SearchRequest("hello_es");
searchRequest.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
MultiMatchQueryBuilder multiMatchQueryBuilder =
QueryBuilders.multiMatchQuery("实战", "description", "name");
multiMatchQueryBuilder.field("name", 10);
TermQueryBuilder termQueryBuilder = new TermQueryBuilder("studymodel", 201001);
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
boolQueryBuilder.must(termQueryBuilder).must(multiMatchQueryBuilder);
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
Stream.of(searchHits).forEach(model -> {
String sourceAsString = model.getSourceAsString();
log.info("sourceAsString:{}", sourceAsString);
});
}
- filter
过滤是针对搜索的结果进行过虑,过虑器主要判断的是文档是否匹配,不去计算和判断文档的匹配度得分,所以过虑器性能比查询要高,且方便缓存,推荐尽量使用过虑器去实现查询或者过虑器和查询共同使用。
@Test
public void testFilter() throws IOException {
SearchRequest searchRequest = new SearchRequest("hello_es");
searchRequest.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
MultiMatchQueryBuilder multiMatchQueryBuilder =
QueryBuilders.multiMatchQuery("实战", "description", "name");
multiMatchQueryBuilder.field("name", 10);
TermQueryBuilder termQueryBuilder = new TermQueryBuilder("studymodel", 201001);
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
boolQueryBuilder.must(termQueryBuilder).must(multiMatchQueryBuilder);
searchSourceBuilder.query(boolQueryBuilder);
boolQueryBuilder.filter(QueryBuilders.termQuery("studymodel", 201001));
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
Stream.of(searchHits).forEach(model -> {
String sourceAsString = model.getSourceAsString();
log.info("sourceAsString:{}", sourceAsString);
});
}
15、高亮显示
@Test
public void testHeightLight() throws IOException {
SearchRequest searchRequest = new SearchRequest("hello_es");
searchRequest.types("doc");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
searchSourceBuilder.fetchSource(new String[]{"name", "description", "studymodel"}, Strings.EMPTY_ARRAY);
// 设置高亮字段
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.requireFieldMatch(true).field("name")
.preTags("<strong>").postTags("</strong>");
searchSourceBuilder.highlighter(highlightBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
Stream.of(searchHits).forEach(model -> {
String sourceAsString = model.getSourceAsString();
Map<String, HighlightField> highlightFields = model.getHighlightFields();
String name = (String) model.getSourceAsMap().get("name");
if (highlightFields != null) {
HighlightField nameField = highlightFields.get("name");
if (nameField != null) {
Text[] fragments = nameField.getFragments();
StringBuffer stringBuffer = new StringBuffer();
for (Text str : fragments) {
stringBuffer.append(str.string());
}
name = stringBuffer.toString();
}
}
log.info("name:{}=====sourceAsString:{}", name, sourceAsString);
});
}
以上代码附上github地址: https://github.com/fafeidou/fast-cloud-nacos/tree/master/fast-common-examples/fast-common-es-example/fast-common-es-rest-client-example