前面我们已经实现利用DSL实现文档查询和后续结果处理,下面我们利用Java RestClient实现前面的功能
一、快速入门
1.1.基本案例演示
我们通过match_all来演示下基本的APl,先看请求DSL的组织:查询所有的信息如下:
@SpringBootTest
public class HotelSearchTests {
//创建成员变量,保存初始化的对象
private RestHighLevelClient client;
@BeforeEach
void setUp(){
this.client = new RestHighLevelClient(
RestClient.builder(HttpHost.create("http://192.168.42.150:9200")
));
}
@AfterEach
void testDown() throws IOException {
this.client.close();
}
/**
* 查询所有的数据
* @throws IOException
*/
@Test
void testMatchAll() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.matchAllQuery());
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
System.out.println(response);
}
}
执行后结果如下:
1.2.结果解析
上面的操作完成后,我们需要对于返回的结果进行解析,通过解析拿出我们需要的信息:
代码如下:
/**
* 查询所有的数据
* @throws IOException
*/
@Test
void testMatchAll() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.matchAllQuery());
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4.解析结果
SearchHits searchHits = response.getHits();
//4.1.查询总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到:"+total+"条数据");
//4.2.查询的结果数组
for (SearchHit hit : searchHits.getHits()) {
//4.3.获取文档source
String json = hit.getSourceAsString();
//4.4.打印输出
System.out.println(json);
//4.5.反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println("hotelDoc = "+hotelDoc);
}
}
执行后结果如下:
1.3.Query Builders的工具类
Rest API中其中构建查询条件的核心部分是由一个名为Query Builders的工具类提供的,其中包含了各种查询方法:
在 Elasticsearch Java 客户端中,Query Builders 提供了一系列用于构建查询的工具类。这些工具类通常位于 org.elasticsearch.index.query
包中。以下是一些常用的 Query Builders 工具类及其方法:
QueryBuilders.termQuery(String name, Object value)
:创建一个精确匹配的项查询。QueryBuilders.matchQuery(String name, Object value)
:创建一个全文匹配查询。QueryBuilders.boolQuery()
:创建一个布尔查询,用于组合多个查询条件。QueryBuilders.rangeQuery(String name)
:创建一个范围查询,用于匹配指定范围内的值。QueryBuilders.existsQuery(String name)
:创建一个存在性查询,用于匹配指定字段存在的文档。QueryBuilders.prefixQuery(String name, String prefix)
:创建一个前缀查询,用于匹配指定前缀的项。
这些方法通常用于构建查询条件,并且可以与其他查询条件组合使用。在使用这些方法时,通常需要将返回的查询对象添加到查询构建器中,然后将构建器用于执行搜索操作。
二、match查询
2.1.语法说明
全文检索的match和multi_match查询与match_all的APl基本一致,差别是查询条件,也就是query的部分。语法如下:
//单字段查询
QueryBuilders.matchQuery("all","如家");
//多字段查询
QueryBuilders.multiMatchQuery("如家","name","business");
2.2.单字段查询
利用QueryBuilders.matchQuery("all","如家")完成单个字段查询
/**
* 单字段查询
* @throws IOException
*/
@Test
void testMatchQuery() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.matchQuery("all","如家"));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4.解析结果
SearchHits searchHits = response.getHits();
//4.1.查询总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到:"+total+"条数据");
//4.2.查询的结果数组
for (SearchHit hit : searchHits.getHits()) {
//4.3.获取文档source
String json = hit.getSourceAsString();
//4.4.打印输出
System.out.println(json);
//4.5.反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println("hotelDoc = "+hotelDoc);
}
}
执行后结果如下:
解析结果的代码是重复的代码,我们可以把它抽取出来,如下:
/**
* 单字段查询
* @throws IOException
*/
@Test
void testMatchQuery() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.matchQuery("all","如家"));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//调用方法解析结构
handleResponse(response);
}
private void handleResponse(SearchResponse response){
//4.解析结果
SearchHits searchHits = response.getHits();
//4.1.查询总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到:"+total+"条数据");
//4.2.查询的结果数组
for (SearchHit hit : searchHits.getHits()) {
//4.3.获取文档source
String json = hit.getSourceAsString();
//4.4.打印输出
System.out.println(json);
//4.5.反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println("hotelDoc = "+hotelDoc);
}
}
2.2.多字段查询
多字段查询利用,QueryBuilders.multiMatchQuery("如家","name","business");完成
/**
* 多字段查询
* @throws IOException
*/
@Test
void testMultiMatchQuery() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.multiMatchQuery("如家", "name", "business"));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//调用方法解析结构
handleResponse(response);
}
三、精确查询
3.1.语法说明
精确查询常见的有term查询和range查询,同样利用QueryBuilders实现,语法如下:
//词条查询
QueryBuilders.termQuery("city","杭州");
//范围查询
QueryBuilders.rangeQuery("price").gte(100).lte(150);
3.2.精确查询:词条查询
案例如下:
@Test
void testTermQuery() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.termQuery("city","上海"));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//解析结构
handleResponse(response);
}
3.3.精确查询:范围查询
案例如下:查询价格在100到200之间的酒店信息
@Test
void testRangeQuery() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
request.source().query(QueryBuilders.rangeQuery("price").gte(100).lte(200));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//解析结构
handleResponse(response);
}
执行后结果如下:
四、复合查询
4.1.语法说明
复合查询,也就是组合查询,利用精确查询常见的有term查询和range查询,同样利用Query Builders实现:
//创建布尔查询
BoolQueryBuilder boolQuery=QueryBuilders.boolQuery();
//添加must条件
boolQuery.must(QueryBuilders.term Query("city","杭州"));
//添加filter条件
boolQuery.filter(QueryBuilders.range Query("price").lte(250));
4.2.案例
代码如下:
@Test
void testBool() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
//2.1.准备BooleanQuery
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
//2.2.添加term
boolQuery.must(QueryBuilders.termQuery("city", "上海"));
//2.3.添加range 价格小于等于400的
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(400));
request.source().query(boolQuery);
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//解析结构
handleResponse(response);
}
执行后如下:
五、排序、分页、高亮
5.1.排序和分页
搜索结果的排序和分页是与query同级的参数,对应的API如下:
代码如下:
@Test
void testPageAndSort() throws IOException {
//页码和每页大小
int page=1;
int size=5;
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
//2.1.准备Query
request.source().query(QueryBuilders.matchAllQuery());
//2.2.排序
request.source().sort("price", SortOrder.ASC);
//2.3.分页
request.source().from((page-1)*size).size(size);
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//解析结构
handleResponse(response);
}
执行后结果如下:
5.2.高亮
高亮API包括请求DSL和结果解析两部分
5.2.1.高亮请求DSL构建
语法如下:
代码如下:
@Test
void testHighlight() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
//2.1.准备Query
request.source().query(QueryBuilders.matchQuery("all", "如家"));
//2.2.高亮: 由于上面查询的拷贝字段all,下面高亮显示的指定的是name字段,不一致,则需设置requireFieldMatch(false)
request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//解析结构
handleResponse(response);
}
查看结果并没有高亮显示的部分,因为这里我们只是做了高亮的构建部分,结果解析部分还没有做,如下:
5.2.2.高亮结果解析
语法如下:
代码如下:
@Test
void testHighlight() throws IOException {
//1.准备request
SearchRequest request = new SearchRequest("hotel");
//2.准备DSL
//2.1.准备Query
request.source().query(QueryBuilders.matchQuery("all", "如家"));
//2.2.高亮: 由于上面查询的拷贝字段all,下面高亮显示的指定的是name字段,不一致,则需设置requireFieldMatch(false)
request.source().highlighter(
new HighlightBuilder()
.field("name")
.requireFieldMatch(false));
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4.解析响应
SearchHits searchHits = response.getHits();
//4.1.获取总条数
TotalHits total = searchHits.getTotalHits();
System.out.println("获取的消息的条数:"+total);
//4.2.文档数组
SearchHit[] hits = searchHits.getHits();
//4.3.遍历
for (SearchHit hit : hits) {
//获取文档source
String json = hit.getSourceAsString();
//反序列化
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
//获取高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
//Spring给我们提供了一个工具类,为我们判断是否为空:CollectionUtils.isEmpty()
if(!CollectionUtils.isEmpty(highlightFields)){
//根据字段名获取高亮结果
HighlightField highlightField = highlightFields.get("name");
if(highlightField != null){
//获取高亮的值
String name = highlightField.getFragments()[0].string();
//覆盖非高亮结果
hotelDoc.setName(name);
}
}
System.out.println("hotelDoc = "+hotelDoc);
}
}
执行后结果如下: