今天咱们就来聊一聊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;
}









