SpringCloudAlibaba云商场-海量数据搜索实现(六)

90 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情

每日英语:

Sometimes a little discomfort in the beginning can save much pain down the road.

翻译:有时起初的隐忍可以避免一路的疼痛。 ——《怦然心动》

1. 商品搜索排序实现

1.1 排序搜索分析

排序搜索有多种排序方式,我们可以把排序升序、降序当做一个参数,把排序的域当做一个参数,无论是哪种排序方式,只需要把这两个参数传到后端服务即可。我们定义一下传参数规则:

1、排序域:sfield
2、排序方式:sm

例如:根据价格升序

sfield=price
sm=ASC

例如:新品排序

sfield=updateTime
sm=DESC

1.2 排序实现

com.xz.mall.search.service.impl.SkuSearchServiceImpl#queryBuilder方法中添加如下代码 即可:

//排序
Object sfield = searchMap.get("sfield");
Object sm = searchMap.get("sm");
if (!ObjectUtils.isEmpty(sfield) && !ObjectUtils.isEmpty(sm)) {
    queryBuilder.withSort(
            SortBuilders.fieldSort(sfield.toString())   //指定排序域
            .order(SortOrder.valueOf(sm.toString()))    //排序方式
    );
}

2. 商品搜索高亮显示

2.1 高亮原理分析

高亮是指当我们搜索商品的时候,商品列表中如何和你搜索的关键词相同,那么它会高亮展示,也就是变色展示,如下京东搜索,其实就是给关键词增加了样式,所以是红色,ES搜索引擎也是一样,也可以实现关键词高亮展示,原理和京东搜索高亮原理一样。

京东商品高亮展示.jpg

2.2 高亮实现

高亮搜索实现有2个步骤:

1、配置高亮域以及对应的样式
2、从结果集中取出高亮数据,并将非高亮数据换成高亮数据

2.2.1 设置高亮配置

com.xz.mall.search.service.impl.SkuSearchServiceImpl#search中添加如下高亮代码:

//1.设置高亮信息 关键词前(后)面的标签,设置高亮域
HighlightBuilder.Field field = new HighlightBuilder
        .Field("name")    //根据指定的域进行高亮查询
        .preTags("<span style="color:red">")      //关键词高亮前缀
        .postTags("</span>")    //关键词高亮后缀
        .fragmentSize(100);     //碎片长度
//2.添加高亮域
queryBuilder.withHighlightFields(field);

2.2.2 结果映射转换

创建一个结果映射转换对象com.xz.mall.search.util.HighlightResultMapper,其实主要是将非高亮转换成高亮数据,代码如下:

public class HighlightResultMapper extends DefaultResultMapper {

    /**
     * 映射转换,将非高亮数据替换成高亮数据
     * @param response
     * @param clazz
     * @param pageable
     * @param <T>
     * @return
     */
    @Override
    public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
        //1.获取所有非高亮数据
        SearchHits hits = response.getHits();
        //2.循环非高亮数据集合
        for (SearchHit hit : hits) {
            //非高亮数据
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            //3.获取高亮数据
            for (Map.Entry<String, HighlightField> entry : hit.getHighlightFields().entrySet()) {
                //4.将非高亮数据替换成高亮数据
                String key = entry.getKey();
                //如果当前非高亮对象中有该高亮数据对应的非高亮对象,则进行替换
                if (sourceAsMap.containsKey(key)){
                    //高亮碎片
                    String hlResult = transTxtToArrayToString(entry.getValue().getFragments());
                    if (!StringUtils.isEmpty(hlResult)) {
                        //替换高亮
                        sourceAsMap.put(key, hlResult);
                    }

                }
            }
            //更新hit的数据
            hit.sourceRef(new ByteBufferReference(ByteBuffer.wrap(JSONObject.toJSONString(sourceAsMap).getBytes())));
        }

        return super.mapResults(response, clazz, pageable);
    }

    /**
     * Text转成字符串
     * @param fragments
     * @return
     */
    private String transTxtToArrayToString(Text[] fragments) {
        if (fragments != null) {
            StringBuilder str = new StringBuilder();
            for (Text fragment : fragments) {
                str.append(fragment.toString());
            }
            return str.toString();
        }
        return null;
    }
}

com.xz.mall.search.service.impl.SkuSearchServiceImpl中注入对象ElasticsearchRestTemplate

@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;

替换之前的搜索为用elasticsearchRestTemplate来实现:

/**
 * 商品关键词搜索
 * @param searchMap
 * @return
 */
@Override
public Map<String, Object> search(Map<String, Object> searchMap) {
    //QueryBuilder->构建搜索条件
    NativeSearchQueryBuilder queryBuilder = queryBuilder(searchMap);
    //分组搜索调用
    group(queryBuilder, searchMap);

    //1.设置高亮信息 关键词前(后)面的标签,设置高亮域
    HighlightBuilder.Field field = new HighlightBuilder
            .Field("name")    //根据指定的域进行高亮查询
            .preTags("<span style="color:red">")      //关键词高亮前缀
            .postTags("</span>")    //关键词高亮后缀
            .fragmentSize(100);     //碎片长度
    queryBuilder.withHighlightFields(field);
    //2.并将非高亮数据替换成高亮数据

    //skuSearchMapper进行搜索
    //Page<SkuEs> page = skuSearchMapper.search(queryBuilder.build());
    //AggregatedPage<SkuEs> page = (AggregatedPage<SkuEs>) skuSearchMapper.search(queryBuilder.build());
    AggregatedPage<SkuEs> page = elasticsearchRestTemplate.queryForPage(queryBuilder.build(), SkuEs.class, new HighlightResultMapper());


    //获取结果集:集合列表、记录总数
    Map<String, Object> resultMap = new HashMap<>();
    //分组数据解析
    parseGroup(page.getAggregations(), resultMap);

    //动态属性解析
    attrParse(resultMap);

    List<SkuEs> list = page.getContent();
    resultMap.put("list", list);
    resultMap.put("totalElements", page.getTotalElements());
    return resultMap;
}

用postman测试关键词搜索,效果如下:

高亮显示测试.jpg

总结:

本篇主要介绍了一下商品搜索排序实现和商品搜索高亮显示实现。