快速上手使用Elasticsearch实现高亮查询

1. 引入依赖

高版本Elasticsearch的json解析需2.0.1版本,需手动修改jakarta.json版本.

 <!--es-->
        <dependency>
            <groupId>co.elastic.clients</groupId>
            <artifactId>elasticsearch-java</artifactId>
            <version>8.1.0</version>
            <exclusions>
                <exclusion>
                    <groupId>jakarta.json</groupId>
                    <artifactId>jakarta.json-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>jakarta.json</groupId>
            <artifactId>jakarta.json-api</artifactId>
            <version>2.0.1</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>

2.创建Elasticsearch客户端并加入到bean中

@Component
public class BeanUtils {
    @Bean
    public ElasticsearchClient client(){
        RestClient restClient = RestClient.builder(new HttpHost(ES_HOST, 9200)).build();
        // 使用Jackson映射器创建传输层
        ElasticsearchTransport transport = new RestClientTransport(
                restClient, new JacksonJsonpMapper()
        );
        return new ElasticsearchClient(transport);
    }


}

3. 在Elasticsearch中创建索引

PUT /essay_show
{
   "mappings": {
      "properties": {
        "all": {
          "type": "text",
          "analyzer": "ik_smart"
        },
        "createTime": {
          "type": "keyword",
          "copy_to": [
            "all"
          ]
        },
        "description": {
          "type": "text",
          "analyzer": "ik_smart",
          "copy_to": "all"
        },
        "id": {
          "type": "keyword",
          "copy_to": [
            "all"
          ]
        },
        "image": {
          "type": "keyword",
          "index": false
        },
        "title": {
          "type": "text",
          "copy_to": [
            "all"
          ],
          "analyzer": "ik_smart"
        },
        "traffic": {
          "type": "integer",
          "copy_to": [
            "all"
          ]
        },
        "userId": {
          "type": "keyword",
          "index": false
        },
        "nickName":{
          "type": "keyword"
        },
        "avatar":{
          "type": "keyword",
          "index": false
        },
        "giveLike":{
          "type": "integer",
          "index": false
        },
        "favorites":{
          "type": "integer",
          "index": false
        },
        "comments":{
          "type": "integer",
          "index": false
        },
        "categories":{
          "properties": {
            "category":{
              "properties":{
                "id":{
                  "type":"keyword",
                  "index":false
                },
                "categoryName":{
                  "type":"keyword"
                }
              }
            }
          }
        }
      }
    }
}

4.定时跟新索引库内容

注入客户端
  @Resource
    private ElasticsearchClient client;


	 //定时任务每两分钟更新一次
    @Scheduled(cron = "0 */1 * * * ?")
    public void updateESEssayByTitle() throws IOException {

        List<Essay> subEssay = essayMapper.getShowEssay();
        List<EssayShowDTO> essays = subEssay.stream().map((item)->{
            EssayShowDTO essayShowDTO = new EssayShowDTO();
            BeanUtil.copyProperties(item, essayShowDTO);
            essayShowDTO.setImage(JSONUtil.toList(item.getImages(), String.class));
            return essayShowDTO;
        }).collect(Collectors.toList());
        for (EssayShowDTO essay : essays) {

            LambdaQueryWrapper<Member> memberWrapper = new LambdaQueryWrapper<>();
            memberWrapper.select(Member::getAvatar, Member::getNickName).eq(Member::getId, essay.getUserId());
            Member member = userService.getOne(memberWrapper);
            essay.setNickName(member.getNickName());
            essay.setAvatar(member.getAvatar());

            //TODO 查询点赞量
            LambdaQueryWrapper<GiveLike> giveLikeWrapper = new LambdaQueryWrapper<>();
            giveLikeWrapper.eq(GiveLike::getEssayId, essay.getId());
            int giveLike = giveLikeService.count(giveLikeWrapper);
            essay.setGiveLike(giveLike);

            //TODO 查询评论量
            LambdaQueryWrapper<Comments> commentsWrapper = new LambdaQueryWrapper<>();
            commentsWrapper.eq(Comments::getFlag, 0);
            commentsWrapper.eq(Comments::getEssayId, essay.getId());
            int comments = commentsService.count(commentsWrapper);
            essay.setComments(comments);

            //TODO 查询分类
            List<Long> categoryIds = categoryRelationMapper.getCategoryId(essay.getId());
            List<Category> categories = new ArrayList<>();
            for (Long categoryId : categoryIds) {
                Category category = categoryService.getById(categoryId);
                categories.add(category);
            }
            essay.setCategories(categories);

        }


        //删除旧的
        List<BulkOperation> oldList = essays.stream().map((item) -> {
            return new BulkOperation.Builder().delete(
                    d -> d.index(ES_ESSAY_SHOW_INDEX).id(item.getId().toString())).build();
        }).collect(Collectors.toList());
        client.bulk(e -> e.index(ES_ESSAY_SHOW_INDEX).operations(oldList));

        //加入新的
        List<BulkOperation> list = essays.stream().map((item) -> {
            return new BulkOperation.Builder().create(
                    d -> d.document(item).id(item.getId().toString()).index(ES_ESSAY_SHOW_INDEX)).build();
        }).collect(Collectors.toList());
        client.bulk(e -> e.index(ES_ESSAY_SHOW_INDEX).operations(list));

    }

5.高亮搜索

 @Override
    @Transactional//事务控制,保证多表操作一致性
    public R<List<EssayShowDTO>> findEssayByTitle(String title, int flag) throws IOException {

        String sort = SORT_BY_TIME;
        if (flag == 1) {
            sort = SORT_BY_TRAFFIC;
        }

        //设置高亮条件
        Map<String, HighlightField> highlightFieldMap = new HashMap<>();
        highlightFieldMap.put("title", new HighlightField.Builder().requireFieldMatch(false).preTags("<h3 style='color:red;'>").postTags("</h3>").build());
        highlightFieldMap.put("description", new HighlightField.Builder().requireFieldMatch(false).preTags("<h3 style='color:red;'>").postTags("</h3>").requireFieldMatch(false).build());

        //TODO 高亮查询
        String finalSort = sort;
        SearchResponse<EssayShowDTO> searchResponse = client.search(s -> s.index(ES_ESSAY_SHOW_INDEX)
                        .query(q -> q.term(t -> t.field("title").value(title)))
                        .sort(o -> o.field(f -> f.field(finalSort).order(SortOrder.Desc)))
                        .highlight(h -> h.fields(highlightFieldMap))
                , EssayShowDTO.class);

        for (Hit<EssayShowDTO> hit : searchResponse.hits().hits()) {
            //判断题目和描述是否存在高亮词
            try {
                hit.highlight().get("title").get(0);
            } catch (Exception e) {
//                 e.printStackTrace();
                //不存在,跳过本条记录
                continue;
            }
            //TODO 将搜索的高亮标题设置到实体对象中
            hit.source().setTitle(hit.highlight().get("title").get(0));
            try {
                hit.highlight().get("description").get(0);
            } catch (Exception e) {
//                 e.printStackTrace();
                continue;
            }
            //TODO 将搜索的高亮描述设置到实体对象中
            hit.source().setDescription(hit.highlight().get("description").get(0));
        }


        List<EssayShowDTO> essayShowDTOS = searchResponse.hits().hits().stream().map((item) -> {
            EssayShowDTO essayShowDTO = item.source();
            return essayShowDTO;
        }).collect(Collectors.toList());

        return R.success(essayShowDTOS);
    }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值