mirror of
https://github.com/201206030/novel.git
synced 2025-04-27 07:30:50 +00:00
feat: 设置 Elasticsearch 搜索关键词高亮显示
This commit is contained in:
parent
23fa646cd6
commit
a8e2e2d5c9
@ -1,7 +1,5 @@
|
|||||||
package io.github.xxyopen.novel.core.constant;
|
package io.github.xxyopen.novel.core.constant;
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* elasticsearch 相关常量
|
* elasticsearch 相关常量
|
||||||
*
|
*
|
||||||
@ -10,19 +8,109 @@ import lombok.Getter;
|
|||||||
*/
|
*/
|
||||||
public class EsConsts {
|
public class EsConsts {
|
||||||
|
|
||||||
|
private EsConsts() {
|
||||||
|
throw new IllegalStateException(SystemConfigConsts.CONST_INSTANCE_EXCEPTION_MSG);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ES 索引枚举类
|
* 小说索引
|
||||||
*/
|
* */
|
||||||
@Getter
|
public static class BookIndex{
|
||||||
public enum IndexEnum {
|
|
||||||
|
|
||||||
BOOK("book");
|
private BookIndex() {
|
||||||
|
throw new IllegalStateException(SystemConfigConsts.CONST_INSTANCE_EXCEPTION_MSG);
|
||||||
IndexEnum(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String name;
|
/**
|
||||||
|
* 索引名
|
||||||
|
* */
|
||||||
|
public static final String INDEX_NAME = "book";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
public static final String FIELD_ID = "id";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作品方向;0-男频 1-女频
|
||||||
|
*/
|
||||||
|
public static final String FIELD_WORK_DIRECTION = "workDirection";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类别ID
|
||||||
|
*/
|
||||||
|
public static final String FIELD_CATEGORY_ID = "categoryId";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类别名
|
||||||
|
*/
|
||||||
|
public static final String FIELD_CATEGORY_NAME = "categoryName";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小说名
|
||||||
|
*/
|
||||||
|
public static final String FIELD_BOOK_NAME = "bookName";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作家id
|
||||||
|
*/
|
||||||
|
public static final String FIELD_AUTHOR_ID = "authorId";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 作家名
|
||||||
|
*/
|
||||||
|
public static final String FIELD_AUTHOR_NAME = "authorName";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 书籍描述
|
||||||
|
*/
|
||||||
|
public static final String FIELD_BOOK_DESC = "bookDesc";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评分;总分:10 ,真实评分 = score/10
|
||||||
|
*/
|
||||||
|
public static final String FIELD_SCORE = "score";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 书籍状态;0-连载中 1-已完结
|
||||||
|
*/
|
||||||
|
public static final String FIELD_BOOK_STATUS = "bookStatus";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 点击量
|
||||||
|
*/
|
||||||
|
public static final String FIELD_VISIT_COUNT = "visitCount";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 总字数
|
||||||
|
*/
|
||||||
|
public static final String FIELD_WORD_COUNT = "wordCount";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论数
|
||||||
|
*/
|
||||||
|
public static final String FIELD_COMMENT_COUNT = "commentCount";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最新章节ID
|
||||||
|
*/
|
||||||
|
public static final String FIELD_LAST_CHAPTER_ID = "lastChapterId";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最新章节名
|
||||||
|
*/
|
||||||
|
public static final String FIELD_LAST_CHAPTER_NAME = "lastChapterName";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最新章节更新时间
|
||||||
|
*/
|
||||||
|
public static final String FIELD_LAST_CHAPTER_UPDATE_TIME = "lastChapterUpdateTime";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否收费;1-收费 0-免费
|
||||||
|
*/
|
||||||
|
public static final String FIELD_IS_VIP = "isVip";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ public class BookToEsTask {
|
|||||||
EsBookDto esBook = buildEsBook(book);
|
EsBookDto esBook = buildEsBook(book);
|
||||||
br.operations(op -> op
|
br.operations(op -> op
|
||||||
.index(idx -> idx
|
.index(idx -> idx
|
||||||
.index(EsConsts.IndexEnum.BOOK.getName())
|
.index(EsConsts.BookIndex.INDEX_NAME)
|
||||||
.id(book.getId().toString())
|
.id(book.getId().toString())
|
||||||
.document(esBook)
|
.document(esBook)
|
||||||
)
|
)
|
||||||
|
@ -10,6 +10,7 @@ import co.elastic.clients.elasticsearch.core.SearchResponse;
|
|||||||
import co.elastic.clients.elasticsearch.core.search.Hit;
|
import co.elastic.clients.elasticsearch.core.search.Hit;
|
||||||
import co.elastic.clients.elasticsearch.core.search.TotalHits;
|
import co.elastic.clients.elasticsearch.core.search.TotalHits;
|
||||||
import co.elastic.clients.json.JsonData;
|
import co.elastic.clients.json.JsonData;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||||
import io.github.xxyopen.novel.core.common.resp.PageRespDto;
|
import io.github.xxyopen.novel.core.common.resp.PageRespDto;
|
||||||
import io.github.xxyopen.novel.core.common.resp.RestResp;
|
import io.github.xxyopen.novel.core.common.resp.RestResp;
|
||||||
@ -48,7 +49,8 @@ public class EsSearchServiceImpl implements SearchService {
|
|||||||
|
|
||||||
SearchResponse<EsBookDto> response = esClient.search(s -> {
|
SearchResponse<EsBookDto> response = esClient.search(s -> {
|
||||||
|
|
||||||
SearchRequest.Builder searchBuilder = s.index(EsConsts.IndexEnum.BOOK.getName());
|
SearchRequest.Builder searchBuilder = s.index(EsConsts.BookIndex.INDEX_NAME);
|
||||||
|
// 构建检索条件
|
||||||
buildSearchCondition(condition, searchBuilder);
|
buildSearchCondition(condition, searchBuilder);
|
||||||
// 排序
|
// 排序
|
||||||
if (!StringUtils.isBlank(condition.getSort())) {
|
if (!StringUtils.isBlank(condition.getSort())) {
|
||||||
@ -61,6 +63,11 @@ public class EsSearchServiceImpl implements SearchService {
|
|||||||
// 分页
|
// 分页
|
||||||
searchBuilder.from((condition.getPageNum() - 1) * condition.getPageSize())
|
searchBuilder.from((condition.getPageNum() - 1) * condition.getPageSize())
|
||||||
.size(condition.getPageSize());
|
.size(condition.getPageSize());
|
||||||
|
// 设置高亮显示
|
||||||
|
searchBuilder.highlight(h -> h.fields(EsConsts.BookIndex.FIELD_BOOK_NAME
|
||||||
|
, t -> t.preTags("<em style='color:red'>").postTags("</em>"))
|
||||||
|
.fields(EsConsts.BookIndex.FIELD_AUTHOR_NAME
|
||||||
|
, t -> t.preTags("<em style='color:red'>").postTags("</em>")));
|
||||||
|
|
||||||
return searchBuilder;
|
return searchBuilder;
|
||||||
},
|
},
|
||||||
@ -74,6 +81,12 @@ public class EsSearchServiceImpl implements SearchService {
|
|||||||
for (Hit<EsBookDto> hit : hits) {
|
for (Hit<EsBookDto> hit : hits) {
|
||||||
EsBookDto book = hit.source();
|
EsBookDto book = hit.source();
|
||||||
assert book != null;
|
assert book != null;
|
||||||
|
if (!CollectionUtils.isEmpty(hit.highlight().get(EsConsts.BookIndex.FIELD_BOOK_NAME))) {
|
||||||
|
book.setBookName(hit.highlight().get(EsConsts.BookIndex.FIELD_BOOK_NAME).get(0));
|
||||||
|
}
|
||||||
|
if (!CollectionUtils.isEmpty(hit.highlight().get(EsConsts.BookIndex.FIELD_AUTHOR_NAME))) {
|
||||||
|
book.setAuthorName(hit.highlight().get(EsConsts.BookIndex.FIELD_AUTHOR_NAME).get(0));
|
||||||
|
}
|
||||||
list.add(BookInfoRespDto.builder()
|
list.add(BookInfoRespDto.builder()
|
||||||
.id(book.getId())
|
.id(book.getId())
|
||||||
.bookName(book.getBookName())
|
.bookName(book.getBookName())
|
||||||
@ -87,8 +100,12 @@ public class EsSearchServiceImpl implements SearchService {
|
|||||||
}
|
}
|
||||||
assert total != null;
|
assert total != null;
|
||||||
return RestResp.ok(PageRespDto.of(condition.getPageNum(), condition.getPageSize(), total.value(), list));
|
return RestResp.ok(PageRespDto.of(condition.getPageNum(), condition.getPageSize(), total.value(), list));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建检索条件
|
||||||
|
*/
|
||||||
private void buildSearchCondition(BookSearchReqDto condition, SearchRequest.Builder searchBuilder) {
|
private void buildSearchCondition(BookSearchReqDto condition, SearchRequest.Builder searchBuilder) {
|
||||||
|
|
||||||
BoolQuery boolQuery = BoolQuery.of(b -> {
|
BoolQuery boolQuery = BoolQuery.of(b -> {
|
||||||
@ -96,7 +113,9 @@ public class EsSearchServiceImpl implements SearchService {
|
|||||||
if (!StringUtils.isBlank(condition.getKeyword())) {
|
if (!StringUtils.isBlank(condition.getKeyword())) {
|
||||||
// 关键词匹配
|
// 关键词匹配
|
||||||
b.must((q -> q.multiMatch(t -> t
|
b.must((q -> q.multiMatch(t -> t
|
||||||
.fields("bookName^2","authorName^1.8","bookDesc^0.1")
|
.fields(EsConsts.BookIndex.FIELD_BOOK_NAME + "^2"
|
||||||
|
, EsConsts.BookIndex.FIELD_AUTHOR_NAME + "^1.8"
|
||||||
|
, EsConsts.BookIndex.FIELD_BOOK_DESC + "^0.1")
|
||||||
.query(condition.getKeyword())
|
.query(condition.getKeyword())
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
@ -105,14 +124,14 @@ public class EsSearchServiceImpl implements SearchService {
|
|||||||
// 精确查询
|
// 精确查询
|
||||||
if (Objects.nonNull(condition.getWorkDirection())) {
|
if (Objects.nonNull(condition.getWorkDirection())) {
|
||||||
b.must(TermQuery.of(m -> m
|
b.must(TermQuery.of(m -> m
|
||||||
.field("workDirection")
|
.field(EsConsts.BookIndex.FIELD_WORK_DIRECTION)
|
||||||
.value(condition.getWorkDirection())
|
.value(condition.getWorkDirection())
|
||||||
)._toQuery());
|
)._toQuery());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Objects.nonNull(condition.getCategoryId())) {
|
if (Objects.nonNull(condition.getCategoryId())) {
|
||||||
b.must(TermQuery.of(m -> m
|
b.must(TermQuery.of(m -> m
|
||||||
.field("categoryId")
|
.field(EsConsts.BookIndex.FIELD_CATEGORY_ID)
|
||||||
.value(condition.getCategoryId())
|
.value(condition.getCategoryId())
|
||||||
)._toQuery());
|
)._toQuery());
|
||||||
}
|
}
|
||||||
@ -120,21 +139,21 @@ public class EsSearchServiceImpl implements SearchService {
|
|||||||
// 范围查询
|
// 范围查询
|
||||||
if (Objects.nonNull(condition.getWordCountMin())) {
|
if (Objects.nonNull(condition.getWordCountMin())) {
|
||||||
b.must(RangeQuery.of(m -> m
|
b.must(RangeQuery.of(m -> m
|
||||||
.field("wordCount")
|
.field(EsConsts.BookIndex.FIELD_WORD_COUNT)
|
||||||
.gte(JsonData.of(condition.getWordCountMin()))
|
.gte(JsonData.of(condition.getWordCountMin()))
|
||||||
)._toQuery());
|
)._toQuery());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Objects.nonNull(condition.getWordCountMax())) {
|
if (Objects.nonNull(condition.getWordCountMax())) {
|
||||||
b.must(RangeQuery.of(m -> m
|
b.must(RangeQuery.of(m -> m
|
||||||
.field("wordCount")
|
.field(EsConsts.BookIndex.FIELD_WORD_COUNT)
|
||||||
.lt(JsonData.of(condition.getWordCountMax()))
|
.lt(JsonData.of(condition.getWordCountMax()))
|
||||||
)._toQuery());
|
)._toQuery());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Objects.nonNull(condition.getUpdateTimeMin())) {
|
if (Objects.nonNull(condition.getUpdateTimeMin())) {
|
||||||
b.must(RangeQuery.of(m -> m
|
b.must(RangeQuery.of(m -> m
|
||||||
.field("lastChapterUpdateTime")
|
.field(EsConsts.BookIndex.FIELD_LAST_CHAPTER_UPDATE_TIME)
|
||||||
.gte(JsonData.of(condition.getUpdateTimeMin().getTime()))
|
.gte(JsonData.of(condition.getUpdateTimeMin().getTime()))
|
||||||
)._toQuery());
|
)._toQuery());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user