Elasticsearch:驾驭数据浪潮,利用Java API与Elasticsearch DSL构建智能搜索
在当今数据驱动的企业环境中,利用Java API与Elasticsearch DSL构建的智能搜索应用扮演着至关重要的角色。它不仅能够高效处理和分析海量数据,还能提供精准、即时的搜索结果,极大地提升了信息检索的效率和准确性。通过灵活运用DSL查询,企业可以实现复杂的搜索需求,支持决策制定。
目录
查询步骤
RestClient查询
准备基础代码
代码示例与解读
叶子查询
全文检索查询
match查询
multi_match查询
精确查询
range查询
term查询
复杂查询
bool查询
排序和分页
查询步骤
之前说过,由于Elasticsearch对外暴露的接口都是Restful风格的接口,因此JavaAPI调用就是在发送Http请求
查询的基本步骤如下:
- 创建
request
对象,这次是搜索,所以是SearchRequest
- 准备请求参数,也就是查询DSL对应的JSON参数
- 发起请求
- 解析响应,响应结果相对复杂,需要逐层解析
事实上,我们必须明白使用Java API 实现DSL的过程是:根据DSL语句拼接条件。
RestClient查询
新建一个ElasticSearchTest测试类
准备基础代码
private RestHighLevelClient client;
/**
* 创建ES客户端
*/
@BeforeEach
void setUp() {
client = new RestHighLevelClient(RestClient.builder(
HttpHost.create("http://你自己的虚拟机地址:9200")
));
}
/**
* 关闭ES客户端
* @throws IOException
*/
@AfterEach
void tearDown() throws IOException {
if (client != null) {
client.close();
}
}
/**
* 测试连接
*/
@Test
void testConnection() {
System.out.println("client = " + client);
}
代码示例与解读
/**
* 测试查询所有
* @throws IOException
*/
@Test
void testMatchAll() throws IOException {
// 1.创建Request
SearchRequest request = new SearchRequest("items");
// 2.组织请求参数
request.source().query(QueryBuilders.matchAllQuery());
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
}
解读:
- 第一步,创建SearchRequest对象,指定索引库名
- 第二步,利用request.source()构建DSL,DSL中可以包含查询、分页、排序、高亮
- 第三步,利用client.search()发送请求,得到响应
- 第四步,解析请求
这里关键的API有两个,一个是request.source()
,它构建的就是DSL中的完整JSON参数。
另一个是QueryBuilders
,其中包含了我们学习过的各种叶子查询、复合查询等。
现在通过解析请求的方法:
/**
* 处理响应
* @param response
*/
private void handleResponse(SearchResponse response) {
SearchHits searchHits = response.getHits();
// 1.获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到" + total + "条数据");
// 2.遍历结果数组
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
// 3.得到_source,也就是原始json文档
String source = hit.getSourceAsString();
// 4.反序列化并打印
ItemDoc item = JSONUtil.toBean(source, ItemDoc.class);
System.out.println(item);
}
}
叶子查询
全文检索查询
match
查询
/**
* 测试查询所有
* @throws IOException
*/
@Test
void testMatchAll() throws IOException {
// 1.创建Request
SearchRequest request = new SearchRequest("items");
// 2.组织请求参数
request.source().query(QueryBuilders.matchAllQuery());
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
}
实现效果如下:
multi_match
查询
/**
* 测试多字段查询
* @throws IOException
*/
@Test
void testMultiMatch() throws IOException {
// 1.创建Request
SearchRequest request = new SearchRequest("items");
// 2.组织请求参数
request.source().query(QueryBuilders.multiMatchQuery("Apple", "name", "category"));
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
}
实现效果如下:(即必须name和category中都带有“Apple”)
精确查询
range
查询
/**
* 测试范围查询
* @throws IOException
*/
@Test
void testRange() throws IOException {
// 1.创建Request
SearchRequest request = new SearchRequest("items");
// 2.组织请求参数
request.source().query(QueryBuilders.rangeQuery("price").gte(100000).lte(300000));
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
实现效果如下:
term
查询
/**
* 测试精确查询
* @throws IOException
*/
@Test
void testTerm() throws IOException {
// 1.创建Request
SearchRequest request = new SearchRequest("items");
// 2.组织请求参数
request.source().query(QueryBuilders.termQuery("brand", "Huawei"));
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
}
实现效果如下:
复杂查询
bool查询
/**
* 测试复杂条件查询
* @throws IOException
*/
@Test
void testSearch() throws IOException {
// 1.创建Request
SearchRequest request = new SearchRequest("items");
// 2.组织请求参数
request.source().query(
QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("name", "手机"))
.filter(QueryBuilders.termQuery("brand", "Huawei"))
.filter(QueryBuilders.rangeQuery("price").lt(1000000))
);
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
}
实现效果如下:
排序和分页
/**
* 分页和排序
* @throws IOException
*/
@Test
void testPageAndSort() throws IOException {
int pageNo = 1, pageSize = 5;
// 1.创建Request
SearchRequest request = new SearchRequest("items");
// 2.组织请求参数
// 2.1.搜索条件参数
request.source().query(QueryBuilders.matchQuery("name", "电脑"));
// 2.2.排序参数
request.source().
sort("sold", SortOrder.DESC).
sort("price", SortOrder.ASC);
// 2.3.分页参数
request.source().from((pageNo - 1) * pageSize).size(pageSize);
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleResponse(response);
}
实现效果如下:(name中包含“电脑”,现役sold降序排序,sold相同,以price升序排序,展示第一页,展示五条)
高亮
/**
* 高亮
* @throws IOException
*/
@Test
void testHighlight() throws IOException {
// 1.创建Request
SearchRequest request = new SearchRequest("items");
// 2.组织请求参数
// 2.1.query条件
request.source().query(QueryBuilders.matchQuery("name", "手机"));
// 2.2.高亮条件
request.source().highlighter(
SearchSourceBuilder.highlight()
.field("name")
.preTags("<em>")
.postTags("</em>")
);
// 3.发送请求
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
// 4.解析响应
handleHighResponse(response);
}
/**
* 处理高亮响应
* @param response
*/
private void handleHighResponse(SearchResponse response) {
SearchHits searchHits = response.getHits();
// 1.获取总条数
long total = searchHits.getTotalHits().value;
System.out.println("共搜索到" + total + "条数据");
// 2.遍历结果数组
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
// 3.得到_source,也就是原始json文档
String source = hit.getSourceAsString();
// 4.反序列化
ItemDoc item = JSONUtil.toBean(source, ItemDoc.class);
// 5.获取高亮结果
Map<String, HighlightField> hfs = hit.getHighlightFields();
if (CollUtil.isNotEmpty(hfs)) {
// 5.1.有高亮结果,获取name的高亮结果
HighlightField hf = hfs.get("name");
if (hf != null) {
// 5.2.获取第一个高亮结果片段,就是商品名称的高亮值
String hfName = hf.getFragments()[0].string();
item.setName(hfName);
}
}
System.out.println(item);
}
}
实现效果如下: