Solr - SpringDataSolr应用高亮查询/过滤查询

本文前端传递的参数: 

 searchMap:{
     'keywords':'',          // 搜索关键字
     'category':'',          // 分类
     'brand':'',             // 品牌
     'spec':{},              // 规格
     'price':'',             // 价格
     'pageNo':1,             // 当前页
     'pageSize':40,          // 每页展示多少条数据
     'sort':'',              // 排序
     'sortField':''          // 排序的字段
},

本文Solr域的设置:

<!-- 普通域:商品id、标题、价格、图片、分类、卖家、品牌、修改时间 -->
<!-- 是否索引、是否存储 -->
<field name="item_goodsid" type="long" indexed="true" stored="true"/>
<field name="item_title" type="text_ik" indexed="true" stored="true"/>
<field name="item_price" type="double" indexed="true" stored="true"/>
<field name="item_image" type="string" indexed="false" stored="true" />
<field name="item_category" type="string" indexed="true" stored="true" />
<field name="item_seller" type="text_ik" indexed="true" stored="true" />
<field name="item_brand" type="string" indexed="true" stored="true" />
<field name="item_updatetime" type="date" indexed="true" stored="true" />

<!-- 可以根据哪些关键字来搜索 -->
<!-- 暴露在外面的keywords无需存储 -->
<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>
<!-- keywrods来源 -->
<copyField source="item_title" dest="item_keywords"/>
<copyField source="item_category" dest="item_keywords"/>
<copyField source="item_seller" dest="item_keywords"/>
<copyField source="item_brand" dest="item_keywords"/>


<!-- 商品规格是什么:选择版本、颜色等  不确定,实际运行才确定 -->
<dynamicField name="item_spec_*" type="string" indexed="true" stored="true" />

本文存入到Solr的Java对象:

/**
     * 商品id,同时也是商品编号
     */
    @Field
    private Long id;

    /**
     * 商品标题
     */
    @Field("item_title")
    private String title;

    // 商品图片
    @Field("item_image")
    private String image;

    // 商品价格,单位为:元
    @Field("item_price")
    private BigDecimal price;

    // 更新时间
    @Field("item_updatetime")
    private Date updateTime;

    @Field("item_goodsid")
    private Long goodsId;

    @Field("item_category")
    private String category;

    @Field("item_brand")
    private String brand;

    @Field("item_seller")
    private String seller;

    @Dynamic
    @Field("item_spec_*")
    private Map<String,String> specMap;

普通分页查询

概述:使用Solr查询,首先需要注入solrTemplate对象。然后创建SimpleQuery对象,设置查询条件Criteria,把查询条件放到查询对象中。分页查询,还需在查询对象中设置查询数据开始的下标及搜索多少条数据。通过queryForPage方法获取查询结果。但是你真实的数据集合还需通过getContent获取,总共有多少页可以通过getTotalPages获取,总共有多少条数据可以通过getTotalElement获取。

public Map<String, Object> search(Map paramMap){
    // 获取keywords(搜索的关键词)
    String keywords = String.valueOf(paramMap.get("keywords"));
    // 获取当前页
    Integer pageNo = Integer.parseInt(String.valueOf(paramMap.get("pageNo")));
    // 获取每页数据多少
    Integer pageSize = Integer.parseInt(String.valueOf(paramMap.get("pageSize")));

    // 创建Solr查询对象
    SimpleQuery query = new SimpleQuery();
    // 创建查询条件 - 根据搜索关键词来查
    // item_keywords是Solr暴露在外的关键字,用于搜索
    Criteria item_keywords = new Criteria("item_keywords").is(keywords);
    // 把查询条件添加到查询对象中去
    query.addCriteria(item_keywords);
    // 添加分页
    if(pageNo == null || pageNo <= 0){
        pageNo = 1;
    }
    // 设置 - 从哪条记录开始查询
    Integer start = (pageNo - 1) * pageSize;
    query.setOffset(start);
    // 设置 - 查询多少条记录
    query.setRows(pageSize);
    // 获取查询结果 - 将查询结果封装成Items类型
    // 注入Solr的模板对象solrTemplate
    ScoredPage<Item> items = solrTemplate.queryForPage(query,Item.class);
    // 返回结果
    Map resMap = new HashMap();
    // 设置查询到的数据集合
    resMap.put("rows",items.getContent());
    // 设置总共有多少页
    resMap.put("totalPage",items.getTotalPages());
    // 设置总记录数
    resMap.put("total",items.getTotalElements());
    return resMap;
}

 

高亮分页查询

有时候我们需要做这样一个需求,就是查询的部分需要在前端高亮显示出来,如下图。Solr给我们提供了一个高亮查询的解决方案,通过这个方案就可以设置高亮。但是这个方案有些复杂,具体的看代码吧。

/**
     * 高亮查询
     * @param paramMap
     * @return
     */
    public Map setHiglights(Map paramMap){
        // 获取查询条件
        String keywords = String.valueOf(paramMap.get("keywords"));
        // 获取分页信息 - 当前页、每页展示多少条数据
        Integer pageNo = Integer.parseInt(String.valueOf(paramMap.get("pageNo")));
        Integer pageSize = Integer.parseInt(String.valueOf(paramMap.get("pageSize")));
        // 创建高亮查询对象
        SimpleHighlightQuery query = new SimpleHighlightQuery();
        // 设置高亮选项
        HighlightOptions highlightOptions = new HighlightOptions();
        // 设置标题域需要高亮显示
        highlightOptions.addField("item_title");
        // 设置样式,给需要高亮的字段添加html标签
        // 设置高亮前缀
        highlightOptions.setSimplePrefix("<em style=\"color:red\">");
        // 设置后缀
        highlightOptions.setSimplePostfix("</em>");
        // 将样式设置到高亮查询对象中去
        query.setHighlightOptions(highlightOptions);
        // 创建查询条件对象 - 根据item_keywords域来查
        Criteria item_keywords = new Criteria("item_keywords").is(keywords);
        // 将查询条件对象添加到高亮查询对象中去
        query.addCriteria(item_keywords);
        // 添加分页信息
        if(pageNo == null || pageNo <= 0){
            pageNo = 1;
        }
        // 从哪条记录开始查
        Integer start = (pageNo - 1) * pageSize;
        // 设置记录的开始
        query.setOffset(start);
        // 记录条数
        query.setRows(pageSize);
        // 高亮分页查询标题集合
        HighlightPage<Item> items = solrTemplate.queryForHighlightPage(query, Item.class);
        // 获取结果集中的标题域的集合
        List<HighlightEntry<Item>> highlighted = items.getHighlighted();
        // 存储标题的集合
        List<Item> itemList = new ArrayList<>();
        // 遍历标题域的集合
        for (HighlightEntry<Item> itemHighlightEntry : highlighted) {
            // 获取到原本不带高亮的实体对象
            Item item = itemHighlightEntry.getEntity();
            // 获取高亮集合
            List<HighlightEntry.Highlight> highlights = itemHighlightEntry.getHighlights();
            // 当高亮集合不为空时
            if (highlights != null && highlights.size() > 0) {
                // 获取到高亮标题集合
                List<String> highlightTitle = highlights.get(0).getSnipplets();
                if (highlightTitle != null && highlightTitle.size() > 0) {
                    // 终于获取到高亮的标题
                    String title = highlightTitle.get(0);
                    // 使用高亮的内容替换不带高亮的标题
                    item.setTitle(title);
                }
            }
            itemList.add(item);
        }
        HashMap resMap = new HashMap();
        resMap.put("rows",itemList);
        resMap.put("totalPages",items.getTotalPages());
        resMap.put("total",items.getTotalElements());
        return resMap;
    }

Solr内部十分复杂,很难去记忆,所以每次就通过断点调试往下找:

分类/分组查询

/**
     * 查询分类
     * @param paramMap
     * @return
     */
    private List<String> findCategory(Map paramMap) {
        // 获取查询条件
        String keywords = String.valueOf(paramMap.get("keywords"));
        // 创建查询对象
        SimpleQuery query = new SimpleQuery();
        // 创建查询条件对象 - 根据item_keywords域来查
        Criteria criteria = new Criteria("item_keywords").is(keywords);
        // 给查询对象添加查询条件
        query.addCriteria(criteria);
        // 创建分组对象
        GroupOptions groupOptions = new GroupOptions();
        // 根据分类域进行分组
        groupOptions.addGroupByField("item_category");
        // 将分组放入到查询对象当中
        query.setGroupOptions(groupOptions);
        // 创建存储分类的集合
        ArrayList<String> resList = new ArrayList<>();
        // 分组查询分类集合
        GroupPage<Item> items = solrTemplate.queryForGroupPage(query, Item.class);
        // 获取结果集中的分类域的集合
        GroupResult<Item> item_category = items.getGroupResult("item_category");
        // 获取分类域中的实体集合
        Page<GroupEntry<Item>> groupEntries = item_category.getGroupEntries();
        // 遍历实体集合得到实体对象
        for (GroupEntry<Item> groupEntry : groupEntries) {
            String groupValue = groupEntry.getGroupValue();
            // 将分组的内容放到数组中去
            resList.add(groupValue);
        }
        return resList;
    }

断点调试: 

过滤查询

业务中,我们可能需要做一些过滤,比如过滤某品牌、分类、规格、价格等。Solr也为我们提供了相关解决方案,看如下代码:

// 根据分类过滤查询
if (category != null && !"".equals(category)) {
    // 创建过滤查询对象
    FilterQuery filterQuery = new SimpleFilterQuery();
    // 创建条件对象
    Criteria filterCriteria = new Criteria("item_category").is(category);
    // 将条件对象放入过滤对象中
    filterQuery.addCriteria(filterCriteria);
    // 过滤对象放入查询对象中
    query.addFilterQuery(filterQuery);
}


// 根据规格过滤查询 spec中的数据格式{网络:移动4G, 内存小大: 16G}
if (spec != null && !"".equals(spec)) {
	Map<String, String> speMap = JSON.parseObject(spec, Map.class);
	if (speMap != null && speMap.size() > 0) {
		Set<Map.Entry<String, String>> entries = speMap.entrySet();
		for (Map.Entry<String, String> entry : entries) {
			// 创建过滤查询对象
			FilterQuery filterQuery = new SimpleFilterQuery();
			// 创建条件对象
			Criteria filterCriteria = new Criteria("item_spec_" + entry.getKey())
					.is(entry.getValue());
			// 将条件对象放入过滤对象中
			filterQuery.addCriteria(filterCriteria);
			// 过滤对象放入查询对象中
			query.addFilterQuery(filterQuery);
		}
	}
}


// 根据价格过滤    0-500   500-1000    1000-1500   .....    3000 - *
        if (price != null && !"".equals(price)) {
            //切分价格, 这个素组中有最小值和最大值
            String[] split = price.split("-");
            if (split != null && split.length == 2) {
                // 说明大于等于最小值, 如果第一个最小值为0, 进入不到这里
                if (!"0".equals(split[0])) {
                    //创建过滤查询对象
                    FilterQuery filterQuery = new SimpleFilterQuery();
                    //创建条件对象
                    Criteria filterCriteria = new Criteria("item_price").greaterThanEqual(split[0]);
                    //将条件对象放入过滤对象中
                    filterQuery.addCriteria(filterCriteria);
                    //过滤对象放入查询对象中
                    query.addFilterQuery(filterQuery);
                }
                // 说明小于等于最大值, 如果最后的元素也就是最大值为*, 进入不到这里
                if (!"*".equals(split[1])) {
                    //创建过滤查询对象
                    FilterQuery filterQuery = new SimpleFilterQuery();
                    //创建条件对象
                    Criteria filterCriteria = new Criteria("item_price").lessThanEqual(split[1]);
                    //将条件对象放入过滤对象中
                    filterQuery.addCriteria(filterCriteria);
                    //过滤对象放入查询对象中
                    query.addFilterQuery(filterQuery);
                }
            }
        }
发布了100 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40885085/article/details/104130423