背景
在电商业务场景下,我们为加快查询效率。一般会使用ES对数据进行存储,ES中的数据通常由数据库中的数据导入。
导入进ES进行存储时,主要使用以下两种数据类型,当然,我们也不可忽略了IK分词器:
- text: 分词,索引,模糊精确查询,不支持聚合
- keyword: 不分词,索引,精确查询,支持聚合
数据导入到ES之后再到ES中进行查询,查询时主要考虑以下三点:
- 分页
- 高亮
- 排序
编码
public SearchGoodsRes search(Integer page, Integer size, SearchGoodsParam param){
SearchGoodsRes res = new SearchGoodsRes();
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
//分组汇总 类目 品牌 规格
//select category_name from goods where name "%key%" group by category_name
//类目聚合List
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("goodsCategory").field("categoryName.keyword").size(100));
//品牌聚合List
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("goodsBrand").field("brandName").size(100));
//规格
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("goodsSpecs").field("specsJson"));
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
if (param.getKey() != null) {
boolQueryBuilder.must(QueryBuilders.multiMatchQuery(param.getKey(), "name", "category_name"));
}
if (!StringUtils.isEmpty(param.getCategory())){
res.setCategory(param.getCategory());
boolQueryBuilder.filter(QueryBuilders.termQuery("categoryName", param.getCategory()));
}
if (!StringUtils.isEmpty(param.getBrand())){
res.setCategory(param.getCategory());
boolQueryBuilder.filter(QueryBuilders.termQuery("brandName", param.getBrand()));
}
if (param.getSpecsValueMap() != null){
res.setSpecsValueMap(param.getSpecsValueMap());
for (Map.Entry<String, String> entry : param.getSpecsValueMap().entrySet()) {
boolQueryBuilder.filter(QueryBuilders.termQuery("specsMap." + entry.getKey() + ".keyword", entry.getValue()));
}
}
RangeQueryBuilder rangeQueryBuilder = new RangeQueryBuilder("price");
rangeQueryBuilder.gte(param.getMinPrice());
if (param.getMaxPrice() > 0){
rangeQueryBuilder.lte(param.getMaxPrice());
}
boolQueryBuilder.must(rangeQueryBuilder);
FieldSortBuilder scoreSortBuilder = null;
if (StringUtils.isEmpty(param.getOrderField()) && StringUtils.isEmpty(param.getOrderType())
&& param.getOrderType().equalsIgnoreCase("asc")
|| param.getOrderType().equalsIgnoreCase("desc")){
scoreSortBuilder = SortBuilders.fieldSort(param.getOrderField());
scoreSortBuilder.order(SortOrder.fromString(param.getOrderType()));
}
HighlightBuilder hignlightBuilder = new HighlightBuilder();
hignlightBuilder
.field("name").preTags("<font color='red'>").postTags("</font>")
.field("brandName").preTags("<font color='red'>").postTags("</font>")
.field("categoryName").preTags("<font color='red'>").postTags("</font>");
PageRequest pageRequest = PageRequest.of(page - 1, size);
NativeSearchQuery searchQuery = nativeSearchQueryBuilder
.withQuery(boolQueryBuilder)
.withPageable(pageRequest)
.withSort(scoreSortBuilder)
.withHighlightBuilder(hignlightBuilder)
.build();
SearchHits<GoodsESInfo> goodsESInfoSearchHits = elasticsearchRestTemplate.search(searchQuery, GoodsESInfo.class);
//结果构造
List<String> categoryNames = null;
if (StringUtils.isNotEmpty(param.getCategory())){
categoryNames = new ArrayList<>();
ParsedStringTerms goodsCategoryAggregation = goodsESInfoSearchHits.getAggregations().get("goodsCategory");
for (Terms.Bucket bucket : goodsCategoryAggregation.getBuckets()){
categoryNames.add(bucket.getKeyAsString());
}
}
List<String> brandNames = null;
if (StringUtils.isEmpty(param.getBrand())){
brandNames = new ArrayList<>();
ParsedStringTerms brandAggregation = goodsESInfoSearchHits.getAggregations().get("goodsBrand");
for (Terms.Bucket bucket : brandAggregation.getBuckets()){
brandNames.add(bucket.getKeyAsString());
}
}
ParsedStringTerms goodsSpecs = goodsESInfoSearchHits.getAggregations().get("goodsSpecs");
Map<String, Set<String>> specsRes = new HashMap<>();
for (Terms.Bucket bucket : goodsSpecs.getBuckets()){
JSONObject specsJsonObj = JSONObject.parseObject(bucket.getKeyAsString());
for (Map.Entry<String, Object> specsEntry : specsJsonObj.entrySet()){
if (param.getSpecsValueMap() != null && param.getSpecsValueMap().containsKey(specsEntry.getKey())){
continue;
}
Set<String> specOptions = specsRes.get(specsEntry.getKey());
if (specOptions == null){
specOptions = new HashSet<>();
}
specOptions.add((String) specsEntry.getValue());
specsRes.put(specsEntry.getKey(), specOptions);
}
}
List<GoodsESInfo> rows = new ArrayList<>();
for (SearchHit<GoodsESInfo> searchHit : goodsESInfoSearchHits){
GoodsESInfo goodsESInfo = searchHit.getContent();
List<String> nameList = searchHit.getHighlightField("name");
if (nameList.size() > 0){
goodsESInfo.setName(nameList.get(0));
}
List<String> categoryNameList = searchHit.getHighlightField("categoryName");
if (categoryNameList.size() > 0){
goodsESInfo.setCategoryName(categoryNameList.get(0));
}
List<String> brandNameList = searchHit.getHighlightField("brandName");
if (brandNameList.size() > 0){
goodsESInfo.setBrandName(brandNameList.get(0));
}
rows.add(goodsESInfo);
}
long totalSize = goodsESInfoSearchHits.getTotalHits();
long pages = totalSize / size + (totalSize % size > 0 ? 1 : 0);
res.setPage(page);
res.setTotal(totalSize);
res.setGoodsESInfoList(rows);
res.setTotalPages(pages);
res.setBrandList(brandNames);
res.setSpecsList(specsRes);
return res;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/202470.html