实现得分的PrefixQuery

本文介绍如何在 Lucene 中实现一个可以计算得分的 PrefixQuery。通过重写 MultiTermQuery 的重写方法,使用 SCORING_BOOLEAN_QUERY_REWRITE 以确保搜索结果能够根据相关性进行排序。此外,还调整了 BooleanQuery 的最大子查询数量限制,以避免 TooManyClauses 异常。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(先声明一下,我使用的lucene的版本是lucene4.7.2)

在lucene中,有一种类型的query叫做MultiTermQuery,故名思议,他是要涉及到很多个term的query,比如我们常用的WildcardQuery、FuzzyQuery、PrefixQuery、TermRangeQuery、NumericRangeQuery等,他们都是需要按照一个或者多个term按照一定的逻辑找到多个term,然后再重写由找到的这些term形成的TermQuery进入一个新的Query(比如BooleanQuery、或者ConstantScoreQuery),但是有个一指的注意的地方是:有些MultiTermQuery是不得分的,也就是在返回的时候不会按照得分排序,比如PrefixQuery,的不得分是由每个MultiTermQuery使用的rewriteMethod指定,也就是由重写规则指定。本文的目的不在于讨论重写规则,而是想实现一个可以得分的PrefixQuery(业务场景是我们要使用PrefixQuery做搜索框中提示词的排序,所以必须实现得分)。

 

实现原理很简单,在指定重写规则的时候将重写规则指定为得分的规则(当然这里涉及到重写规则的实现,这里本文不讨论),在org.apache.lucene.search.MultiTermQuery类中含有SCORING_BOOLEAN_QUERY_REWRITE这个重写规则从他的名字中就可以理解是封装为一个BooleanQuery,并且计算分数。他的逻辑很简单,将搜索到的多个termQuery封装成一个booleanQuery,每一个termQuery都是optional的,也就是对多个termQuery取并集。但是Booleanquery有个需要注意的地方,他不能有太多的clause,不然会报错,默认是1024个,所以我们需要修改这个值,做到这里就算是完成了。我的代码如下:

/**
 * 由于solr自带的PrefixQuery是不得分的,不能满足提示词的排序要求,所以重写这个query.
 */
public class ScoredPrefixQuery extends PrefixQuery {

	//从词典表中得到的term的限制,用于做测试的,实际中不用
	private int limit = -1; 
	
	static{
		BooleanQuery.setMaxClauseCount(Integer.MAX_VALUE);//设置BooleanQuery的最多的子query的个数为Integer.MAX_VALUE。
	}
	
	public ScoredPrefixQuery(Term prefix) {
		super(prefix);
		//重置重写规则,使用得分的booleanQuery,此处存在的问题是可能会发生BooleanQuery.TooManyClauses,所以要在得到term的时候需要做限制
		setRewriteMethod(org.apache.lucene.search.MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE);
	}
	/**
         * 从词典表中得到前缀匹配的term的方法
         */
	@Override
	public TermsEnum getTermsEnum(Terms terms, AttributeSource atts) throws IOException {
		 TermsEnum tenum = terms.iterator(null);
		 if (getPrefix().bytes().length == 0) {
		      // no prefix -- match all terms for this field:
		     return tenum;
		 }
		 return new PrefixTermsEnum(tenum, getPrefix().bytes()) {
			 int already = 0;
			 final int termLimit =  limit==-1?BooleanQuery.getMaxClauseCount():limit;//设置limit只是用于做测试的。
			 
			 @Override
			public BytesRef next() throws IOException {
				
				BytesRef ref = super.next();//先调用父类方法,即从词典表中读取,
				if(ref == null){//如果真的读完了,就返回null。
					return null;
				}else{//没有读取完,则判断是否已经读取了太多的term
					//最多的BooleanClause的个数
					if(already++ < termLimit){//一个前缀最多从词典表中得到booleanquery的MaxClause个,这样就不会报错了。
						return ref;
					}
					return null;
				}
			}
		 };
	}
	
	public int getLimit() {
		return limit;
	}
	
	//做测试用的
	public void setLimit(int limit) {
		this.limit = limit;
	}
	
//这个测试的前提是我们在索引中仅仅保存了只有id域的100个document,id为从0-99,省略了建立索引的代码。
	public static void main(String[] args) throws IOException {
		
		IndexReader reader = DirectoryReader.open(getDirectory());
		
		IndexSearcher search = new IndexSearcher(reader);
		ScoredPrefixQuery q = new ScoredPrefixQuery(new Term("id","1"));//这一行和下面的PrefixQuery q 这一行是区分的,如果使用这一行则只会搜到3个,并且得分不是1.0f,也就是是得分的。
		q.setLimit(3);//设置最多为3个。
		
//		PrefixQuery q = new PrefixQuery(new Term("id", "1"));//如果使用lucene中默认使用的PrefixQuery则会搜到11个,并且得分都是1.0f,也就是没有得分。
		
		TopDocs td = search.search(q, 100);
		for(ScoreDoc sd:td.scoreDocs){
			System.out.println(sd.score);
		}
		System.out.println(td.scoreDocs.length);
		
	}	
}

 

这样就完成了得分的前缀匹配的query,如果要在solr中使用,还需要自己定义queryparser的插件,这个留在以后再写博客。

 

 

 

@Verify @Override public ResponseVo<List<GoodsSpuPageEsVo>> pageEs(EsPageParamPo pageParam, int page, int size) { if (page < 1) { throw new OSPException(OSPError.PARAM_ERROR, "page必须大于1"); } if (size < 1 || size > 500) { throw new OSPException(OSPError.PARAM_ERROR, "size范围1~100"); } //Integer cusOrgId1 = sysConfigService.getName("SET_DEFAULT_USER_ENTERPRISE_INFO", Integer.class); Pageable pageable = Pageable.newInstance(page, size, pageParam); CustomerEnterprise customerEnterprise = null; String cusEsPathPrefix = null; if (null != pageParam.getCusOrgId()) { customerEnterprise = customerEnterpriseMapper.selectById(pageParam.getCusOrgId()); if (customerEnterprise == null) { log.error("商品使用客群属性es搜索,客群id不存在 {}", pageParam.getCusOrgId()); return ResponseVo.empty(pageable); } cusEsPathPrefix = "cusInfo." + customerEnterprise.getId() + "."; } List<String> cusEsPathPrefixs = new ArrayList<>(); if (CollectionUtils.isNotEmpty(pageParam.getCusOrgIds())) { List<CustomerEnterprise> customerEnterprises = customerEnterpriseMapper.selectList(MCustomerEnterprise.in(MCustomerEnterprise.id, pageParam.getCusOrgIds())); if (CollectionUtils.isEmpty(customerEnterprises)) { log.error("商品使用客群属性es搜索,客群id不存在 {}", pageParam.getCusOrgId()); return ResponseVo.empty(pageable); } customerEnterprises.forEach(enterprise -> { cusEsPathPrefixs.add("cusInfo." + enterprise.getId() + "."); }); } String indexName = sysConfigService.getName(Constants.ES_GOODS_TO_ELASTICSEARCH_INDEX_KEY, String.class, Constants.ES_GOODS_TO_ELASTICSEARCH_INDEX_DEFUALT_VALUE); String minimumShouldMatch = sysConfigService.getName(Constants.ES_MINIMUM_SHOULD_MATCH_KEY, String.class, Constants.ES_MINIMUM_SHOULD_MATCH_DEFUALT_VALUE); HighlightBuilder highlightBuilder = new HighlightBuilder(); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); if (StringUtils.isNotBlank(pageParam.getGoodsName())) { boolQuery.must(QueryBuilders.multiMatchQuery(pageParam.getGoodsName(), "author", "masterName", "publishYear", "searchTags", "name", "typeName", "publishingHouse") .field("name", 2.0f).operator(Operator.OR).minimumShouldMatch(minimumShouldMatch)); // 配置高亮显示 highlightBuilder.field("name"); highlightBuilder.field("author"); // 设置高亮标签 highlightBuilder.preTags("<span style=\"color:#FF0000;\">"); highlightBuilder.postTags("</span>"); /** 相似度搜索,提高全文搜索的_score评分 */ boolQuery.should(QueryBuilders.matchPhraseQuery("name", pageParam.getGoodsName()).slop(6)); boolQuery.should(QueryBuilders.matchPhraseQuery("isbn", pageParam.getGoodsName()).slop(4)); boolQuery.should(QueryBuilders.matchPhraseQuery("author", pageParam.getGoodsName()).slop(2)); boolQuery.should(QueryBuilders.matchPhraseQuery("searchTags", pageParam.getGoodsName()).slop(2)); boolQuery.should(QueryBuilders.matchPhraseQuery("typeName", pageParam.getGoodsName()).slop(2)); boolQuery.should(QueryBuilders.matchPhraseQuery("masterName", pageParam.getGoodsName()).slop(3)); boolQuery.should(QueryBuilders.matchPhraseQuery("publishYear", pageParam.getGoodsName()).slop(3)); boolQuery.should(QueryBuilders.matchPhraseQuery("publishingHouse", pageParam.getGoodsName()).slop(3)); // 设置minimum_should_match参数 boolQuery.minimumShouldMatch(1); } if (StringUtils.isNotBlank(pageParam.getSearchInfo())) { boolQuery.must(QueryBuilders.multiMatchQuery(pageParam.getSearchInfo(), "name", "isbn", "spuId") //TODO 这里重设了 字段的得分权重 .field("name", (float) 2.0).operator(Operator.OR).minimumShouldMatch(minimumShouldMatch)); highlightBuilder.field("name"); /**相似度搜索,提高全文搜索的_score的评分*/ boolQuery.should(QueryBuilders.matchPhraseQuery("name", pageParam.getSearchInfo()).slop(6)); boolQuery.should(QueryBuilders.matchPhraseQuery("isbn", pageParam.getSearchInfo()).slop(2)); boolQuery.should(QueryBuilders.matchPhraseQuery("spuId", pageParam.getSearchInfo()).slop(2)); } if (StringUtils.isNotBlank(pageParam.getLeftName())) { // 配置高亮显示 highlightBuilder.field("name"); // 设置高亮标签 highlightBuilder.preTags("<span style=\"color:#FF0000;\">"); highlightBuilder.postTags("</span>"); boolQuery.must(QueryBuilders.matchQuery("name", pageParam.getLeftName())); // 可选:添加模糊匹配提高召回率 //boolQuery.should(QueryBuilders.matchQuery("name", pageParam.getLeftName())); // 设置minimum_should_match //boolQuery.minimumShouldMatch(0); } String productClassCode = pageParam.getProductClassCode(); if (customerEnterprise != null) { boolQuery.must(QueryBuilders.termQuery(cusEsPathPrefix + "canGoods", "true")); boolQuery.must(QueryBuilders.termQuery(cusEsPathPrefix + "canSupplierCode", "true")); if (!productClassCode.equals(ProductClassCodeEnum.VIRTUAL.code)) { boolQuery.must(QueryBuilders.termQuery(cusEsPathPrefix + "canType", "true")); } } if (CollectionUtils.isNotEmpty(cusEsPathPrefixs)) { BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery(); cusEsPathPrefixs.forEach(prefix -> { // 为每个前缀创建一个必须满足所有条件的布尔查询 BoolQueryBuilder prefixQuery = QueryBuilders.boolQuery(); prefixQuery.must(QueryBuilders.termQuery(prefix + "canGoods", "true")); prefixQuery.must(QueryBuilders.termQuery(prefix + "canSupplierCode", "true")); if (!productClassCode.equals(ProductClassCodeEnum.VIRTUAL.code)) { prefixQuery.must(QueryBuilders.termQuery(prefix + "canType", "true")); } // 将每个前缀的查询添加到主查询中作为 should 条件 subBoolQuery.should(prefixQuery); }); // 设置 minimum_should_match 为 1,表示只需满足任意一个前缀的所有条件即可 subBoolQuery.minimumShouldMatch(1); boolQuery.must(subBoolQuery); } if (null != pageParam.getLowPrice() || null != pageParam.getHighPrice()) { RangeQueryBuilder rangeQueryBuilder = null; if (customerEnterprise != null) { rangeQueryBuilder = QueryBuilders.rangeQuery(cusEsPathPrefix + "price"); } else { rangeQueryBuilder = QueryBuilders.rangeQuery("sellPrice"); } if (null != pageParam.getLowPrice()) { rangeQueryBuilder.gte(pageParam.getLowPrice()); } if (null != pageParam.getHighPrice()) { rangeQueryBuilder.lte(pageParam.getHighPrice()); } boolQuery.must(rangeQueryBuilder); } if (null != pageParam.getCreateTimeStart() || null != pageParam.getCreateTimeEnd()) { RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("createTimeMillis"); if (null != pageParam.getCreateTimeStart()) { rangeQueryBuilder.gte(pageParam.getCreateTimeStart()); } if (null != pageParam.getCreateTimeEnd()) { rangeQueryBuilder.lte(pageParam.getCreateTimeEnd()); } boolQuery.must(rangeQueryBuilder); } if (null != pageParam.getUpdateTimeStart() || null != pageParam.getUpdateTimeEnd()) { RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("updateTimeMillis"); if (null != pageParam.getUpdateTimeStart()) { rangeQueryBuilder.gte(pageParam.getUpdateTimeStart()); } if (null != pageParam.getUpdateTimeEnd()) { rangeQueryBuilder.lte(pageParam.getUpdateTimeEnd()); } boolQuery.must(rangeQueryBuilder); } if (null != pageParam.getUpTimeStart() || null != pageParam.getUpTimeEnd()) { RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("upTimeMillis"); if (null != pageParam.getUpTimeStart()) { rangeQueryBuilder.gte(pageParam.getUpTimeStart()); } if (null != pageParam.getUpTimeEnd()) { rangeQueryBuilder.lte(pageParam.getUpTimeEnd()); } boolQuery.must(rangeQueryBuilder); } if (null != pageParam.getStockStart() || null != pageParam.getStockEnd()) { RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("stock"); if (null != pageParam.getStockStart()) { rangeQueryBuilder.gte(pageParam.getStockStart()); } if (null != pageParam.getStockEnd()) { rangeQueryBuilder.lte(pageParam.getStockEnd()); } boolQuery.must(rangeQueryBuilder); } if (null != pageParam.getOnTop()) { boolQuery.must(QueryBuilders.termQuery("onTop", pageParam.getOnTop())); } if (null != pageParam.getSupplierCodeList() && !pageParam.getSupplierCodeList().isEmpty()) { BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery(); pageParam.getSupplierCodeList().forEach(one -> { subBoolQuery.should(QueryBuilders.termQuery("supplierCode", one)); }); boolQuery.must(subBoolQuery); } if (null != pageParam.getProductClassCodeList() && !pageParam.getProductClassCodeList().isEmpty()) { BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery(); pageParam.getProductClassCodeList().forEach(one -> { subBoolQuery.should(QueryBuilders.termQuery("productClassCode.keyword", one)); }); boolQuery.must(subBoolQuery); } if (StringUtils.isNotBlank(pageParam.getProductClassCode())) { boolQuery.must(QueryBuilders.termQuery("productClassCode.keyword", pageParam.getProductClassCode())); // boolQuery.must(QueryBuilders.termQuery("label.count", pageParam.getProductClassCode())); }/* else { boolQuery.must(QueryBuilders.termQuery("productClassCode.keyword", ProductClassCodeEnum.BOOK.code)); }*/ if (null != pageParam.getGoodsTypeIdList() && !pageParam.getGoodsTypeIdList().isEmpty()) { MGoodsType.in(MGoodsType.code, pageParam.getGoodsTypeIdList()).eq(MGoodsType.onDel, DeleteEnum.NO_DELETE.code).eq(MGoodsType.channelId, "3106").eq(MGoodsType.status, YESOrNOEnum.STATUS_1.code); if (StringUtils.isNotBlank(pageParam.getProductClassCode())) { MGoodsType.eq(MGoodsType.productClassCode, pageParam.getProductClassCode()); } else { MGoodsType.eq(MGoodsType.productClassCode, ProductClassCodeEnum.BOOK.code); } List<GoodsType> typeList = goodsTypeMapper.selectList(MGoodsType.build()); Stream<String> typePathList = typeList.stream().map(GoodsType::getPath); BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery(); typePathList.forEach(one -> { subBoolQuery.should(QueryBuilders.prefixQuery("typePath", one)); }); boolQuery.must(subBoolQuery); } if (null != pageParam.getSpuIds() && !pageParam.getSpuIds().isEmpty()) { BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery(); pageParam.getSpuIds().forEach(one -> { subBoolQuery.should(QueryBuilders.termQuery("spuId", one)); }); boolQuery.must(subBoolQuery); } if (CollectionUtils.isNotEmpty(pageParam.getBanSpuIds())) { BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery(); pageParam.getBanSpuIds().forEach(one -> { subBoolQuery.should(QueryBuilders.termQuery("spuId", one)); }); boolQuery.mustNot(subBoolQuery); } if (null != pageParam.getTags() && !pageParam.getTags().isEmpty()) { // boolQuery.must(QueryBuilders.matchQuery(channelKey + "tag", pageParam.getTags().stream().collect(Collectors.joining(" "))).minimumShouldMatch("60%")); Map<String, Object> params = Maps.newHashMap(); String scriptStr = ""; for (int i = 0; i < pageParam.getTags().size(); i++) { params.put("to_tag" + i, pageParam.getTags().get(i)); scriptStr += "doc['tags.keyword'].values.contains(params.to_tag" + i + ") "; if (i != (pageParam.getTags().size() - 1)) { scriptStr += "|| "; } } Script script = new Script(Script.DEFAULT_SCRIPT_TYPE, Script.DEFAULT_SCRIPT_LANG, scriptStr, params); boolQuery.must(QueryBuilders.scriptQuery(script)); } if (null != pageParam.getStatus()) { boolQuery.must(QueryBuilders.termQuery("status", pageParam.getStatus())); } if (null != pageParam.getMasterStatus()) { boolQuery.must(QueryBuilders.termQuery("masterStatus", pageParam.getMasterStatus())); } boolQuery.must(QueryBuilders.termQuery("onDel", DeleteEnum.NO_DELETE.code)); boolQuery.must(QueryBuilders.termQuery("masterOnDel", DeleteEnum.NO_DELETE.code)); searchSourceBuilder.query(boolQuery); if (!highlightBuilder.fields().isEmpty()) { searchSourceBuilder.highlighter(highlightBuilder); } searchSourceBuilder.from((page - 1) * size); searchSourceBuilder.size(size); //随机分页查询 放在排序前,否则无效 if (null != pageParam.getIsOpenRandomPage() && pageParam.getIsOpenRandomPage().equals(1)) { Script script = new Script("Math.random()"); ScriptSortBuilder sortBuilder = new ScriptSortBuilder(script, ScriptSortBuilder.ScriptSortType.NUMBER); searchSourceBuilder.sort(sortBuilder); } /**是否默认排序*/ boolean defaultSort = true; if (null != pageParam.getFixedPriceSort()) { defaultSort = false; searchSourceBuilder.sort("fixedPrice", SortTypeEnum.TYPE_1.code.equals(pageParam.getFixedPriceSort()) ? SortOrder.ASC : SortOrder.DESC); } if (null != pageParam.getUpTimeSort()) { defaultSort = false; searchSourceBuilder.sort("upTimeMillis", SortTypeEnum.TYPE_1.code.equals(pageParam.getUpTimeSort()) ? SortOrder.ASC : SortOrder.DESC); } if (null != pageParam.getCreateSort()) { defaultSort = false; searchSourceBuilder.sort("createTimeMillis", SortTypeEnum.TYPE_1.code.equals(pageParam.getCreateSort()) ? SortOrder.ASC : SortOrder.DESC); } if (null != pageParam.getUpdateSort()) { defaultSort = false; searchSourceBuilder.sort("updateTimeMillis", SortTypeEnum.TYPE_1.code.equals(pageParam.getUpdateSort()) ? SortOrder.ASC : SortOrder.DESC); } if (null != pageParam.getRecommendSort()) { defaultSort = false; Map<String, Object> params = Maps.newHashMap(); params.put("to_tag", "推荐"); // Script script=new Script(Script.DEFAULT_SCRIPT_TYPE,Script.DEFAULT_SCRIPT_LANG,"doc['"+channelKey+"tag.keyword'].value==params.to_tag?1:0",params); /**同时存在多个值时候,原来的== 判断就不起作用*/ Script script = new Script(Script.DEFAULT_SCRIPT_TYPE, Script.DEFAULT_SCRIPT_LANG, "doc['tags.keyword'].values.contains(params.to_tag)?1:0", params); ScriptSortBuilder scriptSortBuilder = SortBuilders.scriptSort(script, ScriptSortBuilder.ScriptSortType.NUMBER).order(SortTypeEnum.TYPE_1.code.equals(pageParam.getRecommendSort()) ? SortOrder.ASC : SortOrder.DESC); searchSourceBuilder.sort(scriptSortBuilder); searchSourceBuilder.sort(SortBuilders.fieldSort("onTop").order(SortOrder.DESC).unmappedType("integer")); searchSourceBuilder.sort(SortBuilders.fieldSort("sort").order(SortOrder.ASC).unmappedType("integer")); } if (null != pageParam.getPriceSort()) { defaultSort = false; if (customerEnterprise != null) { searchSourceBuilder.sort(cusEsPathPrefix + "price", SortTypeEnum.TYPE_1.code.equals(pageParam.getPriceSort()) ? SortOrder.ASC : SortOrder.DESC); } else { searchSourceBuilder.sort("sellPrice", SortTypeEnum.TYPE_1.code.equals(pageParam.getPriceSort()) ? SortOrder.ASC : SortOrder.DESC); } } if (null != pageParam.getSaleCntSort()) { defaultSort = false; searchSourceBuilder.sort("spuSaleCnt", SortTypeEnum.TYPE_1.code.equals(pageParam.getSaleCntSort()) ? SortOrder.ASC : SortOrder.DESC); } if (null != pageParam.getPublishTimeSort()) { // 根据出版时间排序 defaultSort = false; FieldSortBuilder fieldSortBuilder = SortBuilders.fieldSort("publishTimeMillis").order(SortTypeEnum.TYPE_1.code.equals(pageParam.getPublishTimeSort()) ? SortOrder.ASC : SortOrder.DESC).unmappedType("number"); searchSourceBuilder.sort(fieldSortBuilder); } if (StringUtils.isNotBlank(pageParam.getLeftName())) { searchSourceBuilder.sort("_score", SortOrder.DESC); } else { if (defaultSort) { if (StringUtils.isNotBlank(pageParam.getGoodsName())) { searchSourceBuilder.sort("_score", SortOrder.DESC); } /**当字段不存在的时候,排序需要指定 默认的字段数据类型 否则会报错*/ searchSourceBuilder.sort(SortBuilders.fieldSort("onTop").order(SortOrder.DESC).unmappedType("integer")); searchSourceBuilder.sort(SortBuilders.fieldSort("sort").order(SortOrder.ASC).unmappedType("integer")); } } log.info("搜索查询语句 index:{}:\n{}", indexName, searchSourceBuilder.toString()); Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex(indexName).addType(Constants.ES_TYPE_NAME).build(); try { SearchResult jr = null; jr = jestClient.execute(search); if (log.isDebugEnabled()) { log.debug("搜索查询返回:{}", jr == null ? "" : jr.getJsonString()); } List<SearchResult.Hit<NEsGoodsSpuVo, Void>> hits = jr.getHits(NEsGoodsSpuVo.class); log.info("搜索查询返回数据条数 ----> {}", hits.size()); List<GoodsSpuPageEsVo> goodsSpuPageEsVos = new ArrayList<>(); hits.forEach(hit -> { GoodsSpuPageEsVo goodsSpuPageEsVo = BeanUtil.copyProperties(hit.source, GoodsSpuPageEsVo.class); if (hit.highlight != null && !hit.highlight.isEmpty()) { hit.highlight.entrySet().forEach(highlight -> { if (highlight.getKey().equals("name") && !highlight.getValue().isEmpty()) { goodsSpuPageEsVo.setHighlightName(highlight.getValue().get(0)); } if (highlight.getKey().equals("author") && !highlight.getValue().isEmpty()) { goodsSpuPageEsVo.setHighlightAuthor(highlight.getValue().get(0)); } }); } goodsSpuPageEsVos.add(goodsSpuPageEsVo); }); pageable.setTotal(jr.getTotal()); return ResponseVo.sucess(goodsSpuPageEsVos, pageable); } catch (IOException e) { log.error("查询es异常", e); throw new OSPException(OSPError.RUNTIME_ERROR, "商品搜索引擎异常"); } }价格区间,营销分类类型编码,推荐标签,推荐关键词
最新发布
08-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值