java
//1.检查参数
if(dto == null || StringUtils.isBlank(dto.getSearchWords())){
return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
}
//2.设置查询条件
SearchRequest searchRequest = new SearchRequest("app_info_article");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//布尔查询
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//关键字的分词之后查询
QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(dto.getSearchWords()).field("title").field("content").defaultOperator(Operator.OR);
boolQueryBuilder.must(queryStringQueryBuilder);
//查询小于mindate的数据
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime().getTime());
boolQueryBuilder.filter(rangeQueryBuilder);
//分页查询
searchSourceBuilder.from(0);
searchSourceBuilder.size(dto.getPageSize());
//按照发布时间倒序查询
searchSourceBuilder.sort("publishTime", SortOrder.DESC);
//设置高亮 title
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("<font style='color: red; font-size: inherit;'>");
highlightBuilder.postTags("</font>");
searchSourceBuilder.highlighter(highlightBuilder);
searchSourceBuilder.query(boolQueryBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
//2.结果封装返回
List<Map> list = new ArrayList<>();
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
String json = hit.getSourceAsString();
Map map = JSON.parseObject(json, Map.class);
//处理高亮
if(hit.getHighlightFields() != null && hit.getHighlightFields().size() > 0){
Text[] titles = hit.getHighlightFields().get("title").getFragments();
String title = StringUtils.join(titles);
//高亮标题
map.put("h_title",title);
}else {
//原始标题
map.put("h_title",map.get("title"));
}
list.add(map);
}
return ResponseResult.okResult(list);
1. 设置查询条件
java
SearchRequest searchRequest = new SearchRequest("app_info_article");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
app_info_article
是传了个索引库名称。
searchRequest
是一个请求对象,真正的条件不会放在这里面。
我们调用 是source ()
函数,searchRequest.source()
中的参数为 SearchSourceBuilder
类型。我们所有的条件都是通过这个对象创建。
1.1 设置布尔查询
java
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
因为我们的查询条件不止一个,不能写完一个就把查询放进 builder 里。所以我们构建了一个布尔查询的构建器。
注意: 布尔只是多条件查询 具体逻辑必须或者可以那要看后续的调用是must还是should。
1.2 关键词分词之后再去查询
java
QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders
.queryStringQuery(dto.getSearchWords())
.field("title")
.field("content")
.defaultOperator(Operator.OR);
boolQueryBuilder.must(queryStringQueryBuilder);
- 我们设置
queryStringQuery()
,就是分词之后再去查询。 - 我们在两个域中去查询,一个是 title,一个是 content。
- 然后设置了一个逻辑关系or。
- 最后放进布尔查询器,
must
是指 and 关系.
1.3查询小于min date的数据
java
RangeQueryBuilder rangeQueryBuilder = QueryBuilders
.rangeQuery("publishTime")
.lt(dto.getMinBehotTime()
.getTime());
boolQueryBuilder.filter(rangeQueryBuilder);
rangeQuery
是指我们按照范围去查询,域的名称为"publishTime"。
小于dto.getMinBehotTime()
getTime()是一个方法,它返回Date对象的毫秒数表示。
这里的最后为什么要加.getTime()呢?因为这样可以让Elasticsearch知道要比较的值是一个日期类型的数值,而不是一个日期类型本身 。这样可以避免出现类型转换错误或者精度损失。
如果不加.getTime(),那么Elasticsearch会认为最小被动时间是一个日期类型本身,而不是一个日期类型的数值。这样可能会导致以下问题:
- 如果最小被动时间不在当前时间之前或者之后,那么Elasticsearch可能无法正确地计算出匹配范围。
- 如果最小被动时间在当前时间之前或者之后,并且有多个文档满足条件(例如同时发布了多篇文章),那么Elasticsearch可能无法正确地排序或过滤文档。
- 如果最小被动时间在当前时间之前或者之后,并且有多个文档满足条件(例如同时发布了多篇文章),那么Elasticsearch可能无法正确地评分或分数文档。
1.4 分页查询
java
searchSourceBuilder.from(0);
searchSourceBuilder.size(dto.getPageSize());
因为是滚动页面,我们 from 设置为 0 即可。
1.5 设置高亮 title
java
HighlightBuilder highlightBuilder = new HighlightBuilder();
highlightBuilder.field("title");
highlightBuilder.preTags("<font style='color: red; font-size: inherit;'>");
highlightBuilder.postTags("</font>");
searchSourceBuilder.highlighter(highlightBuilder);
go
` highlightBuilder.preTags();`设置高亮前缀
go
` highlightBuilder.postTags();`设置高亮后缀
2.结果封装返回
java
List<Map> list = new ArrayList<>();
SearchHit[] hits = searchResponse.getHits().getHits();
for (SearchHit hit : hits) {
String json = hit.getSourceAsString();
Map map = JSON.parseObject(json, Map.class);
//处理高亮
if(hit.getHighlightFields() != null && hit.getHighlightFields().size() > 0){
Text[] titles = hit.getHighlightFields()
.get("title")
.getFragments();
String title = StringUtils.join(titles);
//高亮标题
map.put("h_title",title);
}else {
//原始标题
map.put("h_title",map.get("title"));
}
list.add(map);
}
return ResponseResult.okResult(list);
java
SearchHit[] hits = searchResponse.getHits().getHits();
hits 是我们的命中数,因为包装了两层所以要调用两次getHits
- 在Elasticsearch中,
SearchResponse
对象包含了搜索请求的响应。getHits()
方法返回一个SearchHits
对象,它包含了所有匹配搜索条件的文档(称为"hits")。 - **SearchHits对象有一个getHits()方法,它返回一个SearchHit数组。**每个SearchHit对象代表一个匹配的文档,包含了文档的元数据(如索引名、类型、id等)和源数据(即原始的文档内容)。
- 因此,
**SearchHit[] hits = searchResponse.getHits().getHits();**
这行代码的作用是获取所有匹配的文档,并将它们存储在**SearchHit**
数组中。
java
String json = hit.getSourceAsString();
Map map = JSON.parseObject(json, Map.class);
hit 是我们的某一个结果,因为是 JASON 格式,所以我们要将他转成 map 结果。
java
Text[] titles = hit.getHighlightFields()
.get("title")
.getFragments();
String title = StringUtils.join(titles);
如果您不调用**getFragments()**
方法,那么您将无法获取到高亮片段的具体内容。这意味着,您无法在结果中看到哪些部分的内容匹配了搜索条件,也就无法突出显示这些部分。
最后将 titles 连成字符串。