资讯 小学 初中 高中 语言 会计职称 学历提升 法考 计算机考试 医护考试 建工考试 教育百科
栏目分类:
子分类:
返回
空麓网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
空麓网 > 计算机考试 > 软件开发 > 后端开发 > Java

用ES搜索关键字并且返回模糊字段高亮

Java 更新时间: 发布时间: 计算机考试归档 最新发布

用ES搜索关键字并且返回模糊字段高亮

   一般来说,各个网站,首页的搜索,都会有进行全文搜索的示例,并且把模糊匹配的多个数据进行标记(高亮),这样便于全局检索关键的数据,便于客户进行浏览。基于此,本文简单介绍这种功能基本java 的 实现

   由于公司页面此功能隐藏了,本文就以接口调用返回看具体实现了

   下面是最终的想要的结果,搜索内容代码 1, type 是 类型  
    类型ID: 1 线索、2 客户、3 商机、4 联系人、5 售前、6 订单、7 合同,

   每一种类型代表一张表的数据

控制层 controller 
@ApiOperation("关键字搜索结果页聚合")@PostMapping("/pageListAgg")public R pageListAgg(@RequestBody @Valid GlobalSearchDataReqDTO globalSearchDataReqDTO) { return success(globalSearchService.pageListAgg(globalSearchDataReqDTO));}
逻辑层 service
public Map pageListAgg(GlobalSearchDataReqDTO globalSearchDataReqDTO) {        Map resultMap = new HashMap<>();        if (Objects.isNull(globalSearchDataReqDTO.getType())) {            globalSearchDataReqDTO.setType(1);        }        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();        // 构建查询条件 & 高亮        this.searchConditionBuild(globalSearchDataReqDTO, nativeSearchQueryBuilder);        // 排序        nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort());        nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("type").order(SortOrder.ASC));        nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));        // terms 指定分组的别名, field 指定要分组的字段名, size 指定查询结果的数量 默认是10个        TermsAggregationBuilder aggregation = AggregationBuilders.terms("typeGroup").field("type").size(10);        // 分页        if (Objects.isNull(globalSearchDataReqDTO.getType())) {            globalSearchDataReqDTO.setType(1);        }        TopHitsAggregationBuilder topHitsAggregationBuilder = AggregationBuilders.topHits(globalSearchDataReqDTO.getType().toString());        if (globalSearchDataReqDTO.getPageNum() >= 1) {            topHitsAggregationBuilder.from((globalSearchDataReqDTO.getPageNum() - 1) * globalSearchDataReqDTO.getPageSize());        }        topHitsAggregationBuilder.size(globalSearchDataReqDTO.getPageSize());        aggregation.subAggregation(topHitsAggregationBuilder);        nativeSearchQueryBuilder.addAggregation(aggregation);        // 构建并查询        NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();        SearchHits search = elasticsearchTemplate.search(nativeSearchQuery, GlobalSearchData.class);        // 聚合结果        ParsedStringTerms typeAgg = Objects.requireNonNull(search.getAggregations()).get("typeGroup");        Map typeMap = getStringsTypeList(typeAgg, globalSearchDataReqDTO.getType());        List globalSearchDataList = JSONObject.parseArray(JSON.toJSONString(typeMap.get("dataList")), GlobalSearchData.class);        List resultList = Lists.newArrayList();        if (CollectionUtils.isNotEmpty(globalSearchDataList)) {            // 高亮            List> searchHits = search.getSearchHits();            List dataList = getHighLightData(searchHits, globalSearchDataList);            // 返回数据处理            resultList = globalSyncDataService.resultDataHandle(dataList, globalSearchDataReqDTO);        }        //resultMap.put("total", Objects.nonNull(typeMap.get("typeTotal")) ? typeMap.get("typeTotal") : 0); //总记录数        resultMap.put("total", resultList.size()); //记录数        resultMap.put("resultList", resultList); //结果数据        typeMap.remove("typeTotal");        typeMap.remove("dataList");        resultMap.put("typeMap", typeMap); //聚合数据        return resultMap;    }
// 构建查询条件 & 高亮
private void searchConditionBuild(GlobalSearchDataReqDTO globalSearchDataReqDTO, NativeSearchQueryBuilder nativeSearchQueryBuilder) {        BoolQueryBuilder builder = QueryBuilders.boolQuery();        String searchContent = globalSearchDataReqDTO.getSearchContent();        builder.must(QueryBuilders.matchQuery("accountId", globalSearchDataReqDTO.getAccountId()));        // 其他条件 模糊搜索 OR        BoolQueryBuilder shouldBuilder = QueryBuilders.boolQuery();        shouldBuilder.should(QueryBuilders.matchPhrasePrefixQuery("customerName", searchContent).boost(5).slop(25));        shouldBuilder.should(QueryBuilders.matchPhrasePrefixQuery("contactName", searchContent).boost(5).slop(25));        shouldBuilder.should(QueryBuilders.matchPhrasePrefixQuery("companyName", searchContent).boost(5).slop(25));        shouldBuilder.should(QueryBuilders.matchPhrasePrefixQuery("title", searchContent).boost(5).slop(25));        shouldBuilder.should(QueryBuilders.matchPhrasePrefixQuery("code", searchContent).boost(5).slop(25));        if (!judgeContainsStr(searchContent) && searchContent.length() < 13) {            shouldBuilder.should(QueryBuilders.matchPhrasePrefixQuery("mobile", searchContent).boost(5).slop(25));            shouldBuilder.should(QueryBuilders.termQuery("phone", searchContent).boost(5));            shouldBuilder.should(QueryBuilders.matchPhrasePrefixQuery("phone", searchContent).boost(5).slop(25));            shouldBuilder.should(QueryBuilders.matchPhrasePrefixQuery("companyTelephone", searchContent).boost(5).slop(25));        }//        BoolQueryBuilder shouldBuilder1 = QueryBuilders.boolQuery();//        shouldBuilder1.should(QueryBuilders.matchPhraseQuery("title", searchContent).slop(25));//        builder.must(shouldBuilder1);        builder.must(shouldBuilder);        if (!tokenManager.getBase().isMain()) {            // 当前登录人userId在 canSeeUserId中 或者 canSeeUserId = 1            BoolQueryBuilder userIdShouldBuild = QueryBuilders.boolQuery();            userIdShouldBuild.should(QueryBuilders.termQuery("canSeeUserId", globalSearchDataReqDTO.getUserId()));            userIdShouldBuild.should(QueryBuilders.termQuery("canSeeUserId", -1));            builder.must(userIdShouldBuild);        }        nativeSearchQueryBuilder.withFilter(builder);        nativeSearchQueryBuilder.withQuery(builder);        //设置高亮的字段        nativeSearchQueryBuilder.withHighlightFields(                new HighlightBuilder.Field("customerName"),                new HighlightBuilder.Field("contactName"),                new HighlightBuilder.Field("companyName"),                new HighlightBuilder.Field("title"),                new HighlightBuilder.Field("code"),                new HighlightBuilder.Field("mobile"),                new HighlightBuilder.Field("phone"),                new HighlightBuilder.Field("companyTelephone")        );        nativeSearchQueryBuilder.withHighlightBuilder(new HighlightBuilder()                .preTags("").postTags("")                .fragmentSize(800000) //最大高亮分片数                .numOfFragments(0)); //从第一个分片获取高亮片段    }
获取分组结果
  private Map getStringsTypeList(ParsedStringTerms typeAgg, Integer type) {        Map retMap = new HashMap<>();        if (Objects.nonNull(typeAgg)) {            List buckets = typeAgg.getBuckets();            buckets.forEach(bucket -> {                if (type.toString().equals(bucket.getKeyAsString())) {                    retMap.put("typeTotal", bucket.getDocCount());                }                retMap.put(bucket.getKeyAsString(), bucket.getDocCount() > 2000 ? 2000 : bucket.getDocCount()); //记录数 最大限制2000条                if (type.toString().equals(bucket.getKeyAsString())) {                    ParsedTopHits topHits = bucket.getAggregations().get(bucket.getKeyAsString());                    if (Objects.nonNull(topHits.getHits())) {                        org.elasticsearch.search.SearchHit[] hits = topHits.getHits().getHits();                        List dataList = Lists.newArrayList();                        for (org.elasticsearch.search.SearchHit hit : hits) {                            dataList.add(JSONObject.parseObject(JSONObject.toJSONString(hit.getSourceAsMap()), GlobalSearchData.class));                        }                        retMap.put("dataList", dataList);                    }                }            });        }        return retMap;    }

处理结果返回字段
 

public List resultDataHandle(List globalSearchDataList, GlobalSearchDataReqDTO globalSearchDataReqDTO) {        Long accountId = globalSearchDataReqDTO.getAccountId();        List list = Lists.newArrayList();        if (CollectionUtils.isEmpty(globalSearchDataList)) {            return list;        }        List ids = globalSearchDataList.stream().map(GlobalSearchData::getSystemId).collect(Collectors.toList());        switch (globalSearchDataReqDTO.getType()) {            case ESGlobalTypeConstant.LEAD:                list = leadsMapper.selectGlobalResultData(accountId, ids);                list.forEach(item -> item.setStatusName(Objects.isNull(item.getStatus()) ? ConstantsEnum.LeadsStatus.FOLLOW_UP.title : ConstantsEnum.LeadsStatus.getTitle(item.getStatus())));                break;            case ESGlobalTypeConstant.CUSTOMER:                list = customerMapper.selectGlobalResultData(accountId, ids);                list.forEach(item -> item.setLevel(dictionaryService.getTitleByTypeAndCode(DictTypeEnum.CUSTOMER_LEVEL, Optional.ofNullable(item.getLevel()).map(Object::toString).orElse(""))));                break;            case ESGlobalTypeConstant.BUSINESS:                list = businessMapper.selectGlobalResultData(accountId, ids);                list.forEach(item -> {                    item.setStatusName(String.valueOf(BusinessStatusEnum.getDesc(item.getStatus().byteValue())));                });                break;            case ESGlobalTypeConstant.CONTACT:                list = contactMapper.selectGlobalResultData(accountId, ids);                break;            case ESGlobalTypeConstant.PRESALE:                list = presaleMapper.selectGlobalResultData(accountId, ids);                list.forEach(item -> {                    item.setStatusName(PresaleStatusEnum.getByCode(item.getStatus()).getDesc());                    if (StringUtils.equals(item.getStatusName(), PresaleStatusEnum.PENDING_APPROVAL.getDesc())) {                        item.setPresaleStage("--");                        return;                    }                    if (StringUtils.isBlank(item.getPresaleStage())) {                        item.setPresaleStage(presaleStageService.getFirstStageName(accountId, item.getSystemId()));                    }                });                break;            case ESGlobalTypeConstant.ORDER:                list = orderMapper.selectGlobalResultData(accountId, ids);                list.forEach(item -> item.setStatusName(String.valueOf(OrderStatusEnum.getDesc(item.getStatus().byteValue()))));                break;            case ESGlobalTypeConstant.CONTRACT:                list = contractMapper.selectGlobalResultData(accountId, ids);                list.forEach(item -> item.setStatusName(ConstantsEnum.ContractStatus.getTitle(item.getStatus())));                break;        }        return listCover(globalSearchDataList, list, globalSearchDataReqDTO.getSearchContent());    }
   private List getHighLightData(List> searchHits, List dataList) {        List globalSearchDataList = Lists.newArrayList();        if (CollectionUtils.isNotEmpty(dataList)) {            List ids = dataList.stream().map(GlobalSearchData::getId).collect(Collectors.toList());            for (SearchHit searchHit : searchHits) {                if (ids.contains(searchHit.getContent().getId())) {                    highLightHandle(searchHit, globalSearchDataList);                }            }        } else {            for (SearchHit searchHit : searchHits) {                highLightHandle(searchHit, globalSearchDataList);            }        }        return globalSearchDataList;    }
 private void highLightHandle(SearchHit searchHit, List globalSearchDataList) {        //高亮的内容        Map> highlightFields = searchHit.getHighlightFields();        //将高亮的内容填充到content中        searchHit.getContent().setCustomerName(highlightFields.get("customerName") == null ? searchHit.getContent().getCustomerName() : highlightFields.get("customerName").get(0));        searchHit.getContent().setContactName(highlightFields.get("contactName") == null ? searchHit.getContent().getContactName() : highlightFields.get("contactName").get(0));        searchHit.getContent().setCompanyName(highlightFields.get("companyName") == null ? searchHit.getContent().getCompanyName() : highlightFields.get("companyName").get(0));        searchHit.getContent().setTitle(highlightFields.get("title") == null ? searchHit.getContent().getTitle() : highlightFields.get("title").get(0));        searchHit.getContent().setCode(highlightFields.get("code") == null ? searchHit.getContent().getCode() : highlightFields.get("code").get(0));        searchHit.getContent().setMobile(highlightFields.get("mobile") == null ? searchHit.getContent().getMobile() : highlightFields.get("mobile").get(0));        searchHit.getContent().setPhone(highlightFields.get("phone") == null ? searchHit.getContent().getPhone() : highlightFields.get("phone").get(0));        searchHit.getContent().setCompanyTelephone(highlightFields.get("companyTelephone") == null ? searchHit.getContent().getCompanyTelephone() : highlightFields.get("companyTelephone").get(0));        globalSearchDataList.add(searchHit.getContent());    }

入参
 

@Datapublic class GlobalSearchDataReqDTO extends BasePage {        //@NotNull(message = "搜索内容不能为空")    private String searchContent;        private Integer type;    @ApiModelProperty(value = "归属人", hidden = true)    private List ownerIds;    @ApiModelProperty(value = "池归属", hidden = true)    private List pools;    @ApiModelProperty(value = "当前用户的部门", hidden = true)    private List deptIds;    @ApiModelProperty(value = "跟随客户的归属人", hidden = true)    private List customerOwnerIds;    @ApiModelProperty(value = "池管理员的池", hidden = true)    private List adminPool;    @ApiModelProperty(value = "池成员的池", hidden = true)    private List partPool;}


返回值参数
 

@Datapublic class GlobalSearchResultDTO {    @ApiModelProperty(value = "对应主键ID")    private Long systemId;        @ApiModelProperty(value = "类型")    private Integer type;    @ApiModelProperty(value = "类型名称")    private String typeName;    @ApiModelProperty(value = "标题")    private String title;    @ApiModelProperty(value = "编号")    private String code;    @ApiModelProperty(value = "客户id")    private Long customerId;    @ApiModelProperty(value = "客户名称")    private String customerName;    @ApiModelProperty(value = "联系人姓名")    private String contactName;    @ApiModelProperty(value = "公司名称")    private String companyName;    @ApiModelProperty(value = "联系人手机")    private String mobile;    @ApiModelProperty(value = "联系人电话")    private String phone;    @ApiModelProperty(value = "公司电话")    private String companyTelephone;    @ApiModelProperty(value = "池id")    private Long poolId;    @ApiModelProperty(value = "池名称")    private String poolName;    @ApiModelProperty(value = "状态")    private Integer status;    @ApiModelProperty(value = "状态名")    private String statusName;    @ApiModelProperty(value = "关联数据id")    private Long relationId;    @ApiModelProperty(value = "来源")    private String source;    //    @ApiModelProperty(value = "所在区域")//    private String location;    @ApiModelProperty("客户等级")    private String level;    //    @ApiModelProperty(value = "协销人员")//    private Long assistUserId;////    @ApiModelProperty(value = "协助人员,逗号分隔")//    private String assistUser;    @ApiModelProperty(value = "商机意向度")    private String stageDesc;        @ApiModelProperty("售前负责人id")    private Long presaleSalesmanId;    @ApiModelProperty(value = "售前负责人")    private String presaleSalesman;    @ApiModelProperty(value = "售前阶段")    private String presaleStage;    //    @ApiModelProperty(value = "商品名称")//    private String productName;    @ApiModelProperty(value = "金额")    private BigDecimal money;    @ApiModelProperty("签订日期")    private LocalDate signDate;    @ApiModelProperty(value = "归属人姓名")    private String ownerName;    @ApiModelProperty(value = "数据创建人姓名")    private String createByName;    @ApiModelProperty(value = "创建时间")    private String createTime;    @ApiModelProperty(value = "联系人手机数组")    private List mobileList;    public void convertEmptyValue() {        this.setTitle(StringUtils.originalOrEmpty(this.getTitle()));        this.setCode(StringUtils.originalOrEmpty(this.getCode()));        this.setCustomerName(StringUtils.originalOrEmpty(this.getCustomerName()));        this.setContactName(StringUtils.originalOrEmpty(this.getContactName()));        this.setCompanyName(StringUtils.originalOrEmpty(this.getCompanyName()));        this.setPhone(StringUtils.originalOrEmpty(this.getPhone()));        this.setMobile(StringUtils.originalOrEmpty(this.getMobile()));        this.setCompanyTelephone(StringUtils.originalOrEmpty(this.getCompanyTelephone()));        this.setPoolName(StringUtils.originalOrEmpty(this.getPoolName()));        this.setStatusName(StringUtils.originalOrEmpty(this.getStatusName()));        this.setSource(StringUtils.originalOrEmpty(this.getSource()));        this.setLevel(StringUtils.originalOrEmpty(this.getLevel()));        this.setStageDesc(StringUtils.originalOrEmpty(this.getStageDesc()));        this.setPresaleSalesman(StringUtils.originalOrEmpty(this.getPresaleSalesman()));        this.setPresaleStage(StringUtils.originalOrEmpty(this.getPresaleStage()));        this.setOwnerName(StringUtils.originalOrEmpty(this.getOwnerName()));        this.setCreateByName(StringUtils.originalOrEmpty(this.getCreateByName()));    }}
转载请注明:文章转载自 http://www.konglu.com/
本文地址:http://www.konglu.com/it/1096368.html
免责声明:

我们致力于保护作者版权,注重分享,被刊用文章【用ES搜索关键字并且返回模糊字段高亮】因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理,本文部分文字与图片资源来自于网络,转载此文是出于传递更多信息之目的,若有来源标注错误或侵犯了您的合法权益,请立即通知我们,情况属实,我们会第一时间予以删除,并同时向您表示歉意,谢谢!

我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2023 成都空麓科技有限公司

ICP备案号:蜀ICP备2023000828号-2