文章目录
- 1、入门案例
- 2、全文检索
- 3、精确查询
- 4、复合查询-boolean query
- 5、排序和分页
- 6、高亮
1、入门案例
先初始化JavaRestClient对象:
@SpringBootTest
public class HotelSearchTest {
private RestHighLevelClient client;
@Test
void testInit() {
System.out.println(client);
}
@BeforeEach
void setUp() {
this.client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://10.4.130.220:9200")
));
}
@AfterEach
void tearDown() throws IOException {
this.client.close();
}
}
用match_all来演示基本的API使用:
代码和DSL对应上就是:
运行结果:
然后是对结果的解析,对照响应结果:
示例代码:
@Test
void testMatchAll() throws IOException {
SearchRequest request = new SearchRequest("hotel");
request.source()
.query(QueryBuilders.matchAllQuery());
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHits searchHits = response.getHits();
long total = searchHits.getTotalHits().value;
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
String json = hit.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println(hotelDoc);
}
}
运行结果:
总结:
-
构建DSL是通过HighLevelRestClient中的resource()方法来实现的,这里包含了查询、排序、分页、高亮等操作
-
构建查询条件的核心部分,即查询类型,是用一个名为
QueryBuilders的工具类
实现的,它包含了各种查询方法
-
查询的基本步骤总结:
2、全文检索
和match_all一样,不同的是在QueryBuildes工具类中选的方法不同:
// 单字段查询
QueryBuilders.matchQuery("all", "如家");
// 多字段查询
QueryBuilders.multiMatchQuery("如家", "name", "business");
对比下DSL语句:
@Test
void testMatch() throws IOException {
SearchRequest request = new SearchRequest("hotel");
request.source()
.query(QueryBuilders.matchQuery("all", "如家"));
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);//对响应的处理代码相同,做抽取
}
private void handleResponse(SearchResponse response) {
SearchHits searchHits = response.getHits();
long total = searchHits.getTotalHits().value;
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
String json = hit.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
System.out.println(hotelDoc);
}
}
对响应的处理代码相同,这里做个抽取,Ctrl + Alt +M(没用的话Ctrl + Alt + Shift + T,再选Extract Method), 再不行就Settings -> Keymap来打开快捷键设置对话框
运行:
3、精确查询
精确查询常见的有term查询和range查询,同样利用QueryBuilders实现
// 词条查询
QueryBuilders.termQuery("city", "杭州");
// 范围查询
QueryBuilders.rangeQuery("price").gte(100).lte(150);
与DSL对比:
@Test
void testRangeQuery() throws IOException {
SearchRequest request = new SearchRequest("hotel");
request.source()
.query(QueryBuilders.rangeQuery("price").gte(100).lte(300));
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
运行:
4、复合查询-boolean query
// 创建布尔查询
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 添加must条件
boolQuery.must(QueryBuilders.termQuery("city", "杭州"));
// 添加filter条件
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(250));
和DSL的对比:
@Test
void testBooleanQuery() throws IOException {
//准备Request
SearchRequest request = new SearchRequest("hotel");
//准备DSL
//2.1 准备BooleanQuery
BoolQueryBuilder booleanQuery = QueryBuilders.boolQuery();
//2.2 添加term,用must
booleanQuery.must(QueryBuilders.termQuery("city", "上海"));
//2.3 添加range,用filter
booleanQuery.filter(QueryBuilders.rangeQuery("price").gt(100)); //大于300,lt是小于,less than
//2.4 测试下mustNot
booleanQuery.mustNot(QueryBuilders.rangeQuery("price").gte(500)); //大于等于500取反,小于500
//2.5 玩玩should,或
booleanQuery.should(QueryBuilders.termQuery("name", "北京宝辰饭店"));
request.source().query(booleanQuery);
//3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
//4.调用上面抽取的方法解析响应
handleResponse(response);
}
运行:
5、排序和分页
// 查询
request.source().query(QueryBuilders.matchAllQuery());
// 分页
request.source().from(0).size(5);
// 价格排序
request.source().sort("price", SortOrder.ASC);
和DSL的对应关系:
//pageNum和pageSize从前端Dto获取,
//则起点为(pageNum-1)*pageSize
request.source().from((pageNum - 1)*pageSize).size(pageSize);
@Test
void testPage() throws IOException {
int pageNum = 2;
int pageSize = 3;
SearchRequest request = new SearchRequest("hotel");
request.source()
.query(QueryBuilders.matchQuery("name", "如家"));
request.source().from((pageNum - 1) * pageSize).size(pageSize);
request.source().sort("price", SortOrder.ASC);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
handleResponse(response);
}
运行:
6、高亮
高亮API包括请求DSL构建和结果解析两部分,DSL构建为:
request.source().highlighter(new HighlightBuilder()
.field("name")
// 是否需要与查询字段匹配
.requireFieldMatch(false)
);
不用默认标签的话也可以,继续链式编程,后面调postTags()等方法即可。
@Test
void testHighLighter() throws IOException {
SearchRequest request = new SearchRequest("hotel");
request.source()
.query(QueryBuilders.matchQuery("all","如家"))
.highlighter(new HighlightBuilder().field("name")
.requireFieldMatch(false)
.preTags("<strong>")
.postTags("</strong")
);
SearchResponse response = client.search(request,RequestOptions.DEFAULT);
handleResponse(response);
}
发现结果并未高亮,因为上面抽取的handleResponse方法是对_source下处理的,这里的数据是原数据,本就不会被修改,因此要继续拿highlight下的数据,即解析高亮结果
@Test
void testHighLighter() throws IOException {
SearchRequest request = new SearchRequest("hotel");
request.source()
.query(QueryBuilders.matchQuery("all","如家"))
.highlighter(new HighlightBuilder().field("name")
.requireFieldMatch(false)
.preTags("<strong>")
.postTags("</strong")
);
SearchResponse response = client.search(request,RequestOptions.DEFAULT);
SearchHits searchHits = response.getHits();
SearchHit[] hits = searchHits.getHits();
for(SearchHit hit : hits){
String hotelDocString = hit.getSourceAsString();
HotelDoc hotelDoc = JSON.parseObject(hotelDocString,HotelDoc.class);
Map<String, HighlightField> highlightFieldMap = hit.getHighlightFields();
if(! CollectionUtils.isEmpty(highlightFieldMap)){
HighlightField highlightField = highlightFieldMap.get("name");
if(highlightField != null){
String name = highlightField.getFragments()[0].string();
hotelDoc.setName(name);
System.out.println(hotelDoc);
}
}
}
}
运行: