在elasticsearch官网中提供了各种语言的客户端(也就是用来连接ES,用来操作ES的)
官方地址:https://www.elastic.co/guide/en/elasticsearch/client/index.html
我们接下来要学习的是JavaRestClient的客户端。注意点击进入后,选择版本到6.8
,和我们的es版本对应
Low Level Rest Client
是低级别封装,提供一些基础功能,但更灵活High Level Rest Client
,是在Low Level Rest Client基础上进行的高级别封装,功能更丰富和完善,而且API会变的简单创建springboot es项目
<!-- fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<!-- High-level-Rest-Client-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>6.8.3</version>
</dependency>
<!-- es 依赖 -->
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.8.3</version>
</dependency>
创建索引库的同时,我们也会创建type及其映射关系,但是这些操作不建议使用Java客户端完成,原因如下
因此,这些操作建议还是使用Rest风格API去实现,我们接下来以这样一个商品数据为例来创建索引库
/**
* @author BNTang
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Product {
private Long id;
/**
* 标题
*/
private String title;
/**
* 分类
*/
private String category;
/**
* 品牌
*/
private String brand;
/**
* 价格
*/
private Double price;
/**
* 图片地址
*/
private String images;
}
分析一下数据结构
我们可以编写这样的映射配置
PUT /bntang
{
"mappings": {
"product": {
"properties": {
"id": {
"type": "keyword"
},
"title": {
"type": "text",
"analyzer": "ik_max_word"
},
"category": {
"type": "keyword"
},
"brand": {
"type": "keyword"
},
"images": {
"type": "keyword",
"index": false
},
"price": {
"type": "double"
}
}
}
}
}
有了索引库,我们接下来看看如何新增索引数据
@Configuration
public class ESConfig {
@Bean
public RestHighLevelClient restHighLevelClient(){
return new RestHighLevelClient(
RestClient.builder(
new HttpHost("127.0.0.1", 9200, "http")));
}
}
接下来我们看看如何通过代码往es服务器新增一个文档。新增时,如果传递的id是已经存在的,则会完成修改操作,如果不存在,则是新增
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* 新增文档
*/
@Test
public void addDoc() {
// 1.准备需要保存到索引库的Json文档数据
Product product = new Product(1L, "小米手机", "手机", "小米", 2899.00, "http://www.baidu.com");
// 2.将对象转为Json字符串
String jsonString = JSON.toJSONString(product);
// 3.创建请求对象,指定索引库、类型、id(可选)
IndexRequest indexRequest = new IndexRequest("bntang", "product", "1");
// 4.调用source方法将请求数据封装到IndexRequest请求对象中
indexRequest.source(jsonString, XContentType.JSON);
try {
// 5.调用方法进行数据通信
IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
// 6.解析输出结果
System.out.println("结果:" + JSON.toJSONString(indexResponse));
} catch (IOException e) {
e.printStackTrace();
}
}
}
刚刚我们保存了一条数据进去,接下来我们根据REST风格,查看应该是根据id进行get查询,难点是对结果的解析
相关类
请求
参数响应
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* 根据id查看文档
*/
@Test
public void getDocById() {
// 1.构建GetRequest请求对象,指定索引库、类型、id
GetRequest getRequest = new GetRequest("bntang", "product", "1");
try {
// 2.调用方法进行数据通信
GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
// 3.解析输出结果
System.out.println("结果:" + JSON.toJSONString(getResponse));
} catch (IOException e) {
e.printStackTrace();
}
}
}
当需要新增的数据较多时,单个新增比较耗费性能,所以这时候批量新增功能就比较好用了
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* 批量新增文档
*/
@Test
public void bulkAddDoc() {
// 1.构建批量新增BulkRequest请求对象
BulkRequest bulkRequest = new BulkRequest();
// 2.准备需要保存到索引库的Json文档数据封装到IndexRequest请求对象中
for (long i = 2; i < 9; i++) {
// 2.1准备需要保存到索引库的Json文档数据
Product product = new Product(i, "小米手机" + i, "手机", "小米", 2899.00 + i, "http://www.baidu.com");
String jsonString = JSON.toJSONString(product);
// 2.2创建请求对象,指定索引库、类型、id(可选)
IndexRequest indexRequest = new IndexRequest("bntang", "product", "" + i);
// 2.3将请求数据封装到IndexRequest请求对象中
indexRequest.source(jsonString, XContentType.JSON);
// 3.添加IndexRequest请求对象至批量新增BulkRequest请求对象
bulkRequest.add(indexRequest);
}
try {
// 4.调用方法进行数据通信
client.bulk(bulkRequest, RequestOptions.DEFAULT);
} catch (IOException e) {
e.printStackTrace();
}
}
}
通过Kibana查询所有
关键点
restAPI只提供了按文档id进行修改的操作
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* 根据id修改文档
*/
@Test
public void bulkAddDoc() {
// 1.构建修改请求对象,指定索引库、类型、id
UpdateRequest updateRequest = new UpdateRequest("bntang", "product", "1");
// 2.准备需要修改的Json文档数据
Product product = new Product(1L, "大米手机", "手机", "大米", 2899.00, "http://www.baidu.com");
String jsonString = JSON.toJSONString(product);
// 3.将需要修改的Json文档数据封装到UpdateRequest请求对象中
updateRequest.doc(jsonString, XContentType.JSON);
try {
// 4.调用方法进行数据通信
UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);
// 5.解析输出结果
System.out.println("结果:" + JSON.toJSONString(updateResponse));
} catch (IOException e) {
e.printStackTrace();
}
}
}
resetApi只提供了根据id删除
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* 根据id删除文档
*/
@Test
public void delDocById() {
try{
// 1.构建删除请求对象,指定索引库、类型、id
DeleteRequest deleteRequest = new DeleteRequest("bntang", "product", "2");
// 2.调用方法进行数据通信
DeleteResponse deleteResponse = client.delete(deleteRequest, RequestOptions.DEFAULT);
// 3.解析输出结果
System.out.println("结果:" + JSON.toJSONString(deleteResponse));
}catch (IOException e){
e.printStackTrace();
}
}
}
步骤
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* 词匹配搜索
*/
@Test
public void matchDoc() {
// 1.构建SearchRequest请求对象,指定索引库
SearchRequest searchRequest = new SearchRequest("bntang");
// 2.构建SearchSourceBuilder查询对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3.构建QueryBuilder对象指定查询方式和查询条件
QueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "大米");
// 4.将QueryBuilder对象设置到SearchSourceBuilder中
sourceBuilder.query(queryBuilder);
// 5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
searchRequest.source(sourceBuilder);
try {
// 6.调用方法进行数据通信
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.解析输出结果
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
System.out.println("结果: " + sourceAsString);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意,上面的代码中,搜索条件是通过sourceBuilder.query(queryBuilder)
来添加的。这个query()
方法接受的参数是:QueryBuilder
接口类型
这个接口提供了很多实现类,分别对应我们在之前不同类型的查询,例如:term查询、match查询、range查询、boolean查询等,我们如果要使用各种不同查询,其实仅仅是传递给sourceBuilder.query()
方法的参数不同而已。而这些实现类不需要我们去new
,官方提供了QueryBuilders
工厂帮我们构建各种实现类
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* 查询所有
*/
@Test
public void matchDoc() {
// 1.构建SearchRequest请求对象,指定索引库
SearchRequest searchRequest = new SearchRequest("bntang");
// 2.构建SearchSourceBuilder查询对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 3.构建QueryBuilder对象指定查询方式和查询条件
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
// 4.将QueryBuilder对象设置到SearchSourceBuilder中
sourceBuilder.query(queryBuilder);
// 5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
searchRequest.source(sourceBuilder);
try {
// 6.调用方法进行数据通信
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.解析输出结果
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
System.out.println("结果: " + sourceAsString);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
其实搜索类型的变化,仅仅是利用QueryBuilders构建的查询对象不同而已,其他代码基本一致。因此,我们可以把这段代码封装,然后把查询条件作为参数传递
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* 公共查询方法
*/
@Test
public void commonSearch(QueryBuilder queryBuilder) {
// 1.构建SearchRequest请求对象,指定索引库
SearchRequest searchRequest = new SearchRequest("bntang");
// 2.构建SearchSourceBuilder查询对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 4.将QueryBuilder对象设置到SearchSourceBuilder中
sourceBuilder.query(queryBuilder);
// 5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
searchRequest.source(sourceBuilder);
try {
// 6.调用方法进行数据通信
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.解析输出结果
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
System.out.println("结果: " + sourceAsString);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
默认情况下,索引库中所有字段都会返回,如果我们想只返回部分字段,可以通过source filter来控制
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* source过滤查询,过滤掉不需要的字段
*/
@Test
public void testSourceSearch(){
commonSearch(QueryBuilders.matchAllQuery());
}
/**
* 公共查询方法
*/
@Test
public void commonSearch(QueryBuilder queryBuilder) {
// 1.构建SearchRequest请求对象,指定索引库
SearchRequest searchRequest = new SearchRequest("bntang");
// 2.构建SearchSourceBuilder查询对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 4.将QueryBuilder对象设置到SearchSourceBuilder中
sourceBuilder.query(queryBuilder);
// 使用fetchSource实现过滤
sourceBuilder.fetchSource(new String[]{"id", "title"}, null);
// 5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
searchRequest.source(sourceBuilder);
try {
// 6.调用方法进行数据通信
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.解析输出结果
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
System.out.println("结果: " + sourceAsString);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
依然是通过sourceBuilder来配置
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* source过滤查询,过滤掉不需要的字段
*/
@Test
public void testSourceSearch(){
commonSearch(QueryBuilders.matchAllQuery());
}
/**
* 公共查询方法
*/
@Test
public void commonSearch(QueryBuilder queryBuilder) {
// 1.构建SearchRequest请求对象,指定索引库
SearchRequest searchRequest = new SearchRequest("bntang");
// 2.构建SearchSourceBuilder查询对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 4.将QueryBuilder对象设置到SearchSourceBuilder中
sourceBuilder.query(queryBuilder);
/*
* 通过sort方法指定排序规则
* 第一个参数:排序字段
* 第二个参数:升序还是降序(可以不填写,默认升序)
*/
sourceBuilder.sort("id", SortOrder.DESC);
sourceBuilder.sort("price",SortOrder.DESC);
// 5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
searchRequest.source(sourceBuilder);
try {
// 6.调用方法进行数据通信
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.解析输出结果
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
System.out.println("结果: " + sourceAsString);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
备注:默认不能使用text
类型的字段进行排序。不然会报错
官网说明
解决方法:将需要进行排序的text类型的字段,设置fielddata=true
即可
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* source过滤查询,过滤掉不需要的字段
*/
@Test
public void testSourceSearch(){
commonSearch(QueryBuilders.matchAllQuery());
}
/**
* 公共查询方法
*/
@Test
public void commonSearch(QueryBuilder queryBuilder) {
// 1.构建SearchRequest请求对象,指定索引库
SearchRequest searchRequest = new SearchRequest("bntang");
// 2.构建SearchSourceBuilder查询对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 4.将QueryBuilder对象设置到SearchSourceBuilder中
sourceBuilder.query(queryBuilder);
/*
* 通过sort方法指定排序规则
* 第一个参数:排序字段
* 第二个参数:升序还是降序(可以不填写,默认升序)
*/
sourceBuilder.sort("id", SortOrder.DESC);
sourceBuilder.sort("price",SortOrder.DESC);
/*
from:当前页起始索引 int from = (pageNum - 1) * size;
size:每页显示多少条
*/
sourceBuilder.from(0);
sourceBuilder.size(4);
// 5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
searchRequest.source(sourceBuilder);
try {
// 6.调用方法进行数据通信
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 7.解析输出结果
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
System.out.println("结果: " + sourceAsString);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
高亮就是对匹配的内容里的关键词通过html+css进行加颜色处理显示
@SpringBootTest
class EsJavaClientApplicationTests {
@Autowired
@Qualifier(value = "restHighLevelClient")
private RestHighLevelClient client;
/**
* 高亮查询
*/
@Test
public void highLightMatch(){
// 1.构建QueryBuilder对象指定查询方式
QueryBuilder queryBuilder = QueryBuilders.matchQuery("title", "小米");
// 2.构建SearchRequest请求对象,指定索引库
SearchRequest searchRequest = new SearchRequest("bntang");
// 3.构建SearchSourceBuilder查询对象
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
// 4.将QueryBuilder对象设置到SearchSourceBuilder中
sourceBuilder.query(queryBuilder);
// 5构建HighlightBuilder高亮对象
HighlightBuilder highlightBuilder = new HighlightBuilder();
// 5.1设置要高亮的字段
highlightBuilder.field("title");
// 5.2设置高亮样式
highlightBuilder.preTags("<font color='pink' >");
highlightBuilder.postTags("</font>");
// 6.将高亮对象highlightBuilder设置到sourceBuilder中
sourceBuilder.highlighter(highlightBuilder);
// 7.将SearchSourceBuilder查询对象封装到请求对象SearchRequest中
searchRequest.source(sourceBuilder);
try {
// 8.调用方法进行数据通信
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
// 9.解析输出结果
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
String sourceAsString = hit.getSourceAsString();
System.out.println("结果:" + sourceAsString);
// 10.获取高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
HighlightField title = highlightFields.get("title");
Text[] fragments = title.getFragments();
for (Text fragment : fragments) {
System.err.println("高亮结果: " + fragment.toString());
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
关键代码
new HighlightBuilder()
:创建高亮构建器.field("title")
:指定高亮字段.preTags("")
和.postTags("")
:指定高亮的前置和后置标签解析高亮结果
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。