import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.SearchPage;
import org.springframework.data.elasticsearch.core.SearchScrollHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
public class YourElasticsearchService {
private final ElasticsearchOperations elasticsearchOperations;
@Autowired
public YourElasticsearchService(ElasticsearchOperations elasticsearchOperations) {
this.elasticsearchOperations = elasticsearchOperations;
}
public Page<YourEntity> searchWithHighlight(String keyword, int pageNumber, int pageSize) {
NativeSearchQueryBuilder searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.matchQuery("field_name", keyword))
.withHighlightFields(new HighlightBuilder.Field("field_name").preTags("<span style='color:red'>").postTags("</span>"))
.withPageable(PageRequest.of(pageNumber - 1, pageSize));
SearchPage<YourEntity> searchPage = elasticsearchOperations.search(searchQuery.build(), YourEntity.class);
SearchHits<YourEntity> searchHits = searchPage.getSearchHits();
List<YourEntity> resultList = new ArrayList<>();
for (SearchHit<YourEntity> searchHit : searchHits) {
YourEntity result = searchHit.getContent();
Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
if (highlightFields.containsKey("field_name")) {
List<String> highlightedContent = highlightFields.get("field_name");
if (!highlightedContent.isEmpty()) {
result.setHighlightedContent(highlightedContent.get(0));
}
}
resultList.add(result);
}
return new PageImpl<>(resultList, searchPage.getPageable(), searchPage.getTotalHits());
}
}在上述代码中,YourElasticsearchService是一个使用Spring Data Elasticsearch的示例服务类。在构造函数中,我们注入了ElasticsearchOperations,用于获取ES的操作对象。
searchWithHighlight方法接收关键词、页码和页面大小作为参数,并使用NativeSearchQueryBuilder构建搜索查询。通过调用QueryBuilders.matchQuery方法设置匹配查询的字段和关键词,并使用HighlightBuilder.Field类设置需要高亮的字段和高亮标签。
然后,使用elasticsearchOperations.search方法执行搜索查询,并使用SearchPage对象接收搜索结果。
在遍历搜索结果时,我们提取实体对象,并检查是否存在高亮字段。如果存在,我们取出第一个高亮内容,将其设置到实体对象中的highlightedContent属性中。
最后,使用PageImpl类构建一个包含实体列表、分页信息和搜索结果总数的Page对象,作为结果返回。
你可以根据需要,将其他逻辑和查询条件添加到代码中。
在前端页面中,可以使用适当的HTML渲染方式来将高亮内容显示为红色。例如,使用Thymeleaf模板引擎:
<p th:utext="${entity.highlightedContent}"></p>
查询条件如何带多个字段
可以使用Elasticsearch的多字段查询(multi-field query)来实现。以下是一个示例代码,展示如何在Spring Data Elasticsearch中使用多字段查询:
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.SearchPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
public class YourElasticsearchService {
private final ElasticsearchOperations elasticsearchOperations;
@Autowired
public YourElasticsearchService(ElasticsearchOperations elasticsearchOperations) {
this.elasticsearchOperations = elasticsearchOperations;
}
public Page<YourEntity> searchWithHighlight(String keyword, int pageNumber, int pageSize) {
NativeSearchQueryBuilder searchQuery = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.multiMatchQuery(keyword, "field1", "field2", "field3"))
.withHighlightFields(
new HighlightBuilder.Field("field1").preTags("<span style='color:red'>").postTags("</span>"),
new HighlightBuilder.Field("field2").preTags("<span style='color:red'>").postTags("</span>"),
new HighlightBuilder.Field("field3").preTags("<span style='color:red'>").postTags("</span>")
)
.withPageable(PageRequest.of(pageNumber - 1, pageSize));
SearchPage<YourEntity> searchPage = elasticsearchOperations.search(searchQuery.build(), YourEntity.class);
SearchHits<YourEntity> searchHits = searchPage.getSearchHits();
List<YourEntity> resultList = new ArrayList<>();
for (SearchHit<YourEntity> searchHit : searchHits) {
YourEntity result = searchHit.getContent();
Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
if (highlightFields.containsKey("field1")) {
List<String> highlightedContent = highlightFields.get("field1");
if (!highlightedContent.isEmpty()) {
result.setHighlightedField1(highlightedContent.get(0));
}
}
if (highlightFields.containsKey("field2")) {
List<String> highlightedContent = highlightFields.get("field2");
if (!highlightedContent.isEmpty()) {
result.setHighlightedField2(highlightedContent.get(0));
}
}
if (highlightFields.containsKey("field3")) {
List<String> highlightedContent = highlightFields.get("field3");
if (!highlightedContent.isEmpty()) {
result.setHighlightedField3(highlightedContent.get(0));
}
}
resultList.add(result);
}
return new PageImpl<>(resultList, searchPage.getPageable(), searchPage.getTotalHits());
}
}在上述代码中,我们使用QueryBuilders.multiMatchQuery方法来创建一个多字段查询,指定了要在field1、field2和field3中进行搜索匹配。
通过调用withHighlightFields方法,我们将每个字段都配置为需要高亮显示,使用相应的高亮标签。
在搜索结果的遍历中,对每个字段执行类似的处理,检查是否存在高亮字段,如果存在,取出第一个高亮内容,并将其设置到对应的实体属性中。
最后,使用PageImpl构造一个Page对象,包含实体列表、分页信息和搜索结果总数。
条件能加个必须的字段
在搜索条件中同时包含多个字段查询和必须的字段查询,可以使用Elasticsearch的布尔查询来实现。以下是修改后的示例代码
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.SearchPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
public class YourElasticsearchService {
private final ElasticsearchOperations elasticsearchOperations;
@Autowired
public YourElasticsearchService(ElasticsearchOperations elasticsearchOperations) {
this.elasticsearchOperations = elasticsearchOperations;
}
public Page<YourEntity> searchWithHighlight(String keyword, String requiredField, int pageNumber, int pageSize) {
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.multiMatchQuery(keyword, "field1", "field2", "field3"))
.must(QueryBuilders.matchQuery("required_field", requiredField));
NativeSearchQueryBuilder searchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder)
.withHighlightFields(
new HighlightBuilder.Field("field1").preTags("<span style='color:red'>").postTags("</span>"),
new HighlightBuilder.Field("field2").preTags("<span style='color:red'>").postTags("</span>"),
new HighlightBuilder.Field("field3").preTags("<span style='color:red'>").postTags("</span>")
)
.withPageable(PageRequest.of(pageNumber - 1, pageSize));
SearchPage<YourEntity> searchPage = elasticsearchOperations.search(searchQuery.build(), YourEntity.class);
SearchHits<YourEntity> searchHits = searchPage.getSearchHits();
List<YourEntity> resultList = new ArrayList<>();
for (SearchHit<YourEntity> searchHit : searchHits) {
YourEntity result = searchHit.getContent();
Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
if (highlightFields.containsKey("field1")) {
List<String> highlightedContent = highlightFields.get("field1");
if (!highlightedContent.isEmpty()) {
result.setHighlightedField1(highlightedContent.get(0));
}
}
if (highlightFields.containsKey("field2")) {
List<String> highlightedContent = highlightFields.get("field2");
if (!highlightedContent.isEmpty()) {
result.setHighlightedField2(highlightedContent.get(0));
}
}
if (highlightFields.containsKey("field3")) {
List<String> highlightedContent = highlightFields.get("field3");
if (!highlightedContent.isEmpty()) {
result.setHighlightedField3(highlightedContent.get(0));
}
}
resultList.add(result);
}
return new PageImpl<>(resultList, searchPage.getPageable(), searchPage.getTotalHits());
}
}在上述代码中,我们创建了一个BoolQueryBuilder对象,并使用must方法将多字段查询和必须的字段查询都添加到其中。
然后,在NativeSearchQueryBuilder中使用withQuery方法将这个布尔查询作为搜索查询的一部分。
最后,搜索结果的遍历和高亮处理方式与之前的示例相同。
请注意,在创建布尔查询时,你还可以使用其他方法,如should(或者shoulds)来添加可选的字段查询,或者使用mustNot方法来添加排除条件

