elasticsearch8.x高亮和分页
今天咱们就来聊一聊elasticsearch8.x版本如何设置搜索关键词高亮并且分页,因为es7.x和es8.x版本差异比较大,导致了很多es用户在使用时出现了很多问题,es7和es8的高亮就非常不一样,话不多说,直接上代码解释。
如果大家遇到了版本问题或者Java连接不上elasticsearch8.x,可以查看我的这一篇博客elasticsearch 8.7.0的Java API详解教程(一)_不败顽童博主的博客-CSDN博客
@Service
@Slf4j
public class ArticleServiceImpl implements IArticleService {
@Autowired
private ElasticSearchArticleMapper elasticSearchArticleMapper;
@Autowired
private ElasticsearchClient elasticsearchClient;
@Autowired
private KeyWordApi keywordApi;
@Transactional(rollbackFor = Exception.class)
@Override
public Page<ArticleIndex> search(PageQueryParam<ArticleDTO> pageQueryParam) {
//根据一个值查询多个字段 并高亮显示 这里的查询是取并集,即多个字段只需要有一个字段满足即可
//需要查询的字段
List<ArticleIndex> result = new ArrayList<>();
SearchResponse<Map> searchResponse = null;
try {
searchResponse = elasticsearchClient.search(srBuilder -> srBuilder
.index("article")
// MultiMatch 查找:对输入内容先分词再查询。
.query(queryBuilder -> queryBuilder
.multiMatch(multiMatchQueryBuilder -> multiMatchQueryBuilder
.fields("title", "summary", "titleEn","plainTextBody")
.query(pageQueryParam.getParam().getKeywords())
.operator(Operator.Or))
)
// 高亮查询
.highlight(highlightBuilder -> highlightBuilder
.preTags("<font color='red'>")
.postTags("</font>")
.requireFieldMatch(true) //多字段时,需要设置为false
// .fields("title", highlightFieldBuilder -> highlightFieldBuilder)
.fields("title", highlightFieldBuilder -> highlightFieldBuilder)
.fields("titleEn", highlightFieldBuilder -> highlightFieldBuilder)
.fields("summary", highlightFieldBuilder -> highlightFieldBuilder)
.fields("plainTextBody", highlightFieldBuilder -> highlightFieldBuilder)
)
.from(pageQueryParam.getPageNo())
.size(pageQueryParam.getPageSize())
.sort(sortOptionsBuilder -> sortOptionsBuilder
.field(fieldSortBuilder -> fieldSortBuilder
.field("_score").order(SortOrder.Desc)
/*.field("publishedAt").order(SortOrder.Desc)*/))
, Map.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
// 高亮并且分页
List<Hit<Map>> hits = searchResponse.hits().hits();
for (Hit<Map> hit : hits) {
Map<String, Object> docMap = hit.source();
String json = JSON.toJSONString(docMap);
ArticleIndex articleIndex = JSON.parseObject(json, ArticleIndex.class);
Map<String, List<String>> highlight = hit.highlight();
articleIndex.setTitle(highlight.get("title") == null ? articleIndex.getTitle() : highlight.get("title").get(0));
articleIndex.setTitleEn(highlight.get("titleEn") == null ? articleIndex.getTitleEn() : highlight.get("titleEn").get(0));
articleIndex.setSummary(highlight.get("summary") == null ? articleIndex.getSummary() : highlight.get("summary").get(0));
articleIndex.setPlainTextBody(highlight.get("plainTextBody") == null ? articleIndex.getPlainTextBody() : highlight.get("plainTextBody").get(0));
result.add(articleIndex);
}
Page<ArticleIndex> page = new Page<ArticleIndex>();
page.setRows(result);
page.setPageNum(pageQueryParam.getPageNo());
page.setPageSize(pageQueryParam.getPageSize());
page.setTotalCount(searchResponse.hits().total().value());
page.setTotalPages((page.getTotalCount() + page.getPageSize() - 1) / page.getPageSize());
return page;
}
当中page分页是作者自己编写的一个简单的分页
@Data
public class Page<T> {
/**
* 当前页数
*/
private Integer pageNum = 1;
/**
* 当前显示行数
*/
private Integer pageSize = 10;
/**
* 总页数
*/
private Long totalPages = 0L;
/**
* 总行数
*/
private Long totalCount = 0L;
/**
* 是否为最后一页
*/
private boolean last = false;
/**
* 判断第一页
*/
private boolean first = true;
private List<T> rows = new ArrayList<T>();
}
下面是article索引实体类
@Data
@Document(indexName = "article")
public class ArticleIndex {
private static final long serialVersionUID = 132913819042348092L;
/**
* 主键
*/
@Id
private Long id;
/**
* 作者
*/
@Field(store = true, type = FieldType.Keyword)
private Long userId;
/**
* 文章標題
*/
@Field(store = true, type = FieldType.Text, analyzer = "ik_smart")
private String title;
/**
* 英文文章標題
*/
@Field(store = true, type = FieldType.Text, analyzer = "ik_smart")
private String titleEn;
/**
* 文章原始详情
*/
@Field(store = true, type = FieldType.Text, analyzer = "ik_smart")
private String plainTextBody;
/**
* 會員限定
*/
@Field(store = true, type = FieldType.Keyword)
private Boolean memberOnly;
/**
* 申請首頁輪播圖
*/
@Field(store = true, type = FieldType.Keyword)
private Boolean applyHomepageCarousel;
/**
*
*/
@Field(store = true, type = FieldType.Text, analyzer = "ik_smart")
private String ogTitle;
/**
* SEO用的主前綴
*/
@Field(store = true, type = FieldType.Text, analyzer = "ik_smart")
private String parentPath;
/**
* SEO用的副前綴
*/
@Field(store = true, type = FieldType.Text, analyzer = "ik_smart")
private String childPath;
/**
*
*/
@Field(store = true, type = FieldType.Keyword)
private String slug;
/**
* 點擊數
*/
@Field(store = true, type = FieldType.Keyword)
private Long clicksCount;
/**
* 留言數
*/
@Field(store = true, type = FieldType.Keyword)
private Object commentsCount;
/**
* 完成文章時間 (待審核)
*/
@Field(index = false, store = true, type = FieldType.Date, format = DateFormat.date_optional_time,ignoreMalformed = true)
private Date completedAt;
/**
* 通過審核時間
*/
@Field(index = false, store = true, type = FieldType.Date, format = DateFormat.date_optional_time,ignoreMalformed = true)
private Date verifiedAt;
/**
* 發佈時間
*/
@Field(index = false, store = true, type = FieldType.Date, format = DateFormat.date_optional_time,ignoreMalformed = true)
private Date publishedAt;
/**
* 下架時間
*/
@Field(index = false, store = true, type = FieldType.Date, format = DateFormat.date_optional_time,ignoreMalformed = true)
private Date expiredAt;
/**
* 刪除時間
*/
@Field(index = false, store = true, type = FieldType.Date, format = DateFormat.date_optional_time,ignoreMalformed = true)
private Date deletedAt;
/**
*
*/
@Field(index = false, store = true, type = FieldType.Date, format = DateFormat.date_optional_time,ignoreMalformed = true)
private Date createdAt;
/**
*
*/
@Field(index = false, store = true, type = FieldType.Date, format = DateFormat.date_optional_time,ignoreMalformed = true)
private Date updatedAt;
/**
* 註冊人數
*/
@Field(store = true, type = FieldType.Keyword)
private Long viaCount;
/**
* 特派員
*/
@Field(store = true, type = FieldType.Keyword)
private Long reporterId;
/**
* 預覽密碼
*/
@Field(store = false, type = FieldType.Keyword)
private String previewPasscode;
/**
* 內容摘要
*/
@Field(store = true, type = FieldType.Text, analyzer = "ik_smart")
private String summary;
/**
* Optimistic Lock
*/
@Field(store = false, type = FieldType.Keyword)
private Object lockVersion;
/**
* 作者
*/
@Field(store = true, type = FieldType.Keyword)
private String authorName;
/**
* author_url
*/
@Field(store = true, type = FieldType.Keyword)
private String authorUrl;
/**
* categories
*/
@Field(store = true, type = FieldType.Keyword)
private String categories;
/**
* json格式类别
*/
@Field(store = true, type = FieldType.Object)
private List<CategoryVO> category;
/**
* 图片链接
*/
@Field(store = true)
private String imageUrl;
/**
* 类型
*/
@Field(store = true, type = FieldType.Keyword)
private String type;
}