Spring Data Solr入门

2.1 Spring Data Solr简介

虽然支持任何编程语言的能力具有很大的市场价值,你可能感兴趣的问题是:我如何Solr的应用集成到Spring中可以,Spring Data Solr就是为了方便Solr的开发所研制的一个框架,其底层是对SolrJ(官方API)的封装。

2.2 Spring Data Solr入门小Demo

2.2.1 搭建工程

  1. 创建maven工程,pom.xml中引入依赖

   <dependencies>

<dependency>

    <groupId>org.springframework.data</groupId>

    <artifactId>spring-data-solr</artifactId>

    <version>1.5.5.RELEASE</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-test</artifactId>

<version>4.2.4.RELEASE</version>

</dependency>

<dependency>

<groupId>junit</groupId>

<artifactId>junit</artifactId>

<version>4.9</version>

</dependency>

  </dependencies>

(2)在src/main/resources下创建  applicationContext-solr.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:solr="http://www.springframework.org/schema/data/solr"

xsi:schemaLocation="http://www.springframework.org/schema/data/solr

   http://www.springframework.org/schema/data/solr/spring-solr-1.0.xsd

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd">

<!-- solr服务器地址 -->

<solr:solr-server id="solrServer" url="http://127.0.0.1:8080/solr" />

<!-- solr模板,使用solr模板可对索引库进行CRUD的操作 -->

<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">

<constructor-arg ref="solrServer" />

</bean>

</beans>

 

2.2.2 @Field 注解

创建 cn.itcast.pojo 包,将品优购的TbItem实体类拷入本工程  ,属性使用@Field注解标识 。   如果属性与配置文件定义的域名称不一致,需要在注解中指定域名称。

public class TbItem implements Serializable{

 

@Field

    private Long id;

 

@Field("item_title")

    private String title;

    

    @Field("item_price")

private BigDecimal price;

 

    @Field("item_image")

    private String image;

 

    @Field("item_goodsid")

    private Long goodsId;

 

    @Field("item_category")

    private String category;

 

    @Field("item_brand")

    private String brand;

 

    @Field("item_seller")

private String seller;

.......

}

 

2.2.3 增加(修改)

创建测试类TestTemplate.java

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations="classpath:applicationContext-solr.xml")

public class TestTemplate {

 

@Autowired

private SolrTemplate solrTemplate;

 

@Test

public void testAdd(){

TbItem item=new TbItem();

item.setId(1L);

item.setBrand("华为");

item.setCategory("手机");

item.setGoodsId(1L);

item.setSeller("华为2号专卖店");

item.setTitle("华为Mate9");

item.setPrice(new BigDecimal(2000));

solrTemplate.saveBean(item);

solrTemplate.commit();

}

}

2.2.4 按主键查询

@Test

public void testFindOne(){

TbItem item = solrTemplate.getById(1, TbItem.class);

System.out.println(item.getTitle());

}

2.2.5 按主键删除

@Test

public void testDelete(){

solrTemplate.deleteById("1");

solrTemplate.commit();

}

2.2.6 分页查询

首先循环插入100条测试数据

@Test

public void testAddList(){

List<TbItem> list=new ArrayList();

 

for(int i=0;i<100;i++){

TbItem item=new TbItem();

item.setId(i+1L);

item.setBrand("华为");

item.setCategory("手机");

item.setGoodsId(1L);

item.setSeller("华为2号专卖店");

item.setTitle("华为Mate"+i);

item.setPrice(new BigDecimal(2000+i));

list.add(item);

}

 

solrTemplate.saveBeans(list);

solrTemplate.commit();

}

 

编写分页查询测试代码:

 

@Test

public void testPageQuery(){

Query query=new SimpleQuery("*:*");

query.setOffset(20);//开始索引(默认0)

query.setRows(20);//每页记录数(默认10)

ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class);

System.out.println("总记录数:"+page.getTotalElements());

List<TbItem> list = page.getContent();

showList(list);

}

//显示记录数据

private void showList(List<TbItem> list){

for(TbItem item:list){

System.out.println(item.getTitle() +item.getPrice());

}

}

 

2.2.7 条件查询

 Criteria 用于对条件的封装

@Test

public void testPageQueryMutil(){

Query query=new SimpleQuery("*:*");

Criteria criteria=new Criteria("item_title").contains("2");

criteria=criteria.and("item_title").contains("5");

query.addCriteria(criteria);

//query.setOffset(20);//开始索引(默认0)

//query.setRows(20);//每页记录数(默认10)

ScoredPage<TbItem> page = solrTemplate.queryForPage(query, TbItem.class);

System.out.println("总记录数:"+page.getTotalElements());

List<TbItem> list = page.getContent();

showList(list);

}

2.2.8 删除全部数据

@Test

public void testDeleteAll(){

Query query=new SimpleQuery("*:*");

solrTemplate.delete(query);

solrTemplate.commit();

}

3.批量数据导入

3.1需求分析

编写专门的导入程序,将商品数据导入到Solr系统中

3.2查询商品数据列表

3.2.1 工程搭建

(1)创建pinyougou-solr-util(jar) ,引入pinyougou-dao  以及spring 相关依赖

(2)创建spring 配置文件

内容为:

<context:component-scan base-package="com.pinyougou.solrutil">

</context:component-scan>

3.2.2 代码编写

创建com.pinyougou.solrutil包,创建类SolrUtil ,实现商品数据的查询(已审核商品)

@Component

public class SolrUtil {

@Autowired

private TbItemMapper itemMapper;

 

/**

 * 导入商品数据

 */

public void importItemData(){

TbItemExample example=new TbItemExample();

Criteria criteria = example.createCriteria();

criteria.andStatusEqualTo("1");//已审核

List<TbItem> itemList = itemMapper.selectByExample(example);

System.out.println("===商品列表===");

for(TbItem item:itemList){

System.out.println(item.getTitle());

}

System.out.println("===结束===");

}

 

public static void main(String[] args) {

ApplicationContext context=new ClassPathXmlApplicationContext("classpath*:spring/applicationContext*.xml");

SolrUtil solrUtil=  (SolrUtil) context.getBean("solrUtil");

solrUtil.importItemData();

}

}

 

3.3数据导入Solr索引库

3.3.1实体类

  1. 将demo工程中添加了@Field注解的实体类拷贝到pinyougou-pojo中
  2. 在pinyougou-pojo中引入依赖

   <dependency>

    <groupId>org.springframework.data</groupId>

    <artifactId>spring-data-solr</artifactId>

    <version>1.5.5.RELEASE</version>

</dependency>

 

3.3.2添加Solr配置文件

添加applicationContext-solr.xml到spring目录

<!-- solr服务器地址 -->

<solr:solr-server id="solrServer" url="http://127.0.0.1:8080/solr" />

<!-- solr模板,使用solr模板可对索引库进行CRUD的操作 -->

<bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate">

<constructor-arg ref="solrServer" />

</bean>

3.2.3调用模板类导入solr

修改pinyougou-solr-util的SolrUtil.java

@Autowired

private SolrTemplate solrTemplate;

 

/**

 * 导入商品数据

 */

public void importItemData(){

 

TbItemExample example=new TbItemExample();

Criteria criteria = example.createCriteria();

criteria.andStatusEqualTo("1");//已审核

List<TbItem> itemList = itemMapper.selectByExample(example);

System.out.println("===商品列表===");

for(TbItem item:itemList){

System.out.println(item.getTitle());

}

solrTemplate.saveBeans(itemList);

solrTemplate.commit();

System.out.println("===结束===");

}

3.4规格导入动态域

3.4.1@Dynamic注解

修改TbItem.java ,添加属性  

    @Dynamic

    @Field("item_spec_*")

    private Map<String,String> specMap;

    public Map<String, String> getSpecMap() {

return specMap;

}

public void setSpecMap(Map<String, String> specMap) {

this.specMap = specMap;

}

3.4.2修改导入工具

修改pinyougou-solr-util的SolrUtil.java   ,引入fastJSON依赖

/**

 * 导入商品数据

 */

public void importItemData(){

TbItemExample example=new TbItemExample();

Criteria criteria = example.createCriteria();

criteria.andStatusEqualTo("1");//已审核

List<TbItem> itemList = itemMapper.selectByExample(example);

System.out.println("===商品列表===");

for(TbItem item:itemList){

Map specMap= JSON.parseObject(item.getSpec());//将spec字段中的json字符串转换为map

item.setSpecMap(specMap);//给带注解的字段赋值

System.out.println(item.getTitle());

}

solrTemplate.saveBeans(itemList);

solrTemplate.commit();

System.out.println("===结束===");

}

高亮显示

1.1需求分析

将用户输入的关键字在标题中以红色的字体显示出来,就是搜索中常用的高亮显示.

1.2后端代码

修改服务层代码ItemSearchServiceImpl.java

创建私有方法,用于返回查询列表的结果(高亮)

 

/**

 * 根据关键字搜索列表

 * @param keywords

 * @return

 */

private Map searchList(Map searchMap){

Map map=new HashMap();

HighlightQuery query=new SimpleHighlightQuery();

HighlightOptions highlightOptions=new HighlightOptions().addField("item_title");//设置高亮的域

highlightOptions.setSimplePrefix("<em style='color:red'>");//高亮前缀

highlightOptions.setSimplePostfix("</em>");//高亮后缀

query.setHighlightOptions(highlightOptions);//设置高亮选项

//按照关键字查询

Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords"));

query.addCriteria(criteria);

HighlightPage<TbItem> page = solrTemplate.queryForHighlightPage(query, TbItem.class);

for(HighlightEntry<TbItem> h: page.getHighlighted()){//循环高亮入口集合

TbItem item = h.getEntity();//获取原实体类

if(h.getHighlights().size()>0 && h.getHighlights().get(0).getSnipplets().size()>0){

item.setTitle(h.getHighlights().get(0).getSnipplets().get(0));//设置高亮的结果

}

}

map.put("rows",page.getContent());

return map;

}

 

修改ItemSearchServiceImpl search方法,调用刚才编写的私有方法

@Override

public Map<String, Object> search(Map searchMap) {

Map<String,Object> map=new HashMap<>();

//1.查询列表

map.putAll(searchList(searchMap));

return map;

}

1.3前端代码

我们测试后发现高亮显示的html代码原样输出,这是angularJS为了防止html攻击采取的安全机制。我们如何在页面上显示html的结果呢?我们会用到$sce服务的trustAsHtml方法来实现转换。

因为这个功能具有一定通用性,我们可以通过angularJS的过滤器来简化开发,这样只写一次,调用的时候就非常方便了,看代码:

  1. 修改base.js

// 定义模块:

var app = angular.module("pinyougou",[]);

/*$sce服务写成过滤器*/

app.filter('trustHtml',['$sce',function($sce){

    return function(data){

        return $sce.trustAsHtml(data);

    }

}]);

  1. 使用过滤器

ng-bind-html指令用于显示html内容

竖线 |用于调用过滤器,竖线前是要过滤的数据,后是过滤器名称

<div class="attr" ng-bind-html="item.title | trustHtml"></div>

|就是竖线,看起来有点斜是因为字体原因。

2.搜索业务规则分析

2.1需求分析

我们今天要完成的目标是在关键字搜索的基础上添加面板搜索功能。

面板上有商品分类、品牌、各种规格和价格区间等条件

业务规则:

  1. 当用户输入关键字搜索后,除了显示列表结果外,还应该显示通过这个关键字搜索到的记录都有哪些商品分类。
  2. 根据第一个商品分类查询对应的模板,根据模板查询出品牌列表
  3. 根据第一个商品分类查询对应的模板,根据模板查询出规格列表
  4. 当用户点击搜索面板的商品分类时,显示按照这个关键字查询结果的基础上,筛选此分类的结果。
  5. 当用户点击搜索面板的品牌时,显示在以上结果的基础上,筛选此品牌的结果
  6. 当用户点击搜索面板的规格时,显示在以上结果的基础上,筛选此规格的结果
  7. 当用户点击价格区间时,显示在以上结果的基础上,按价格进行筛选的结果
  8. 当用户点击搜索面板的相应条件时,隐藏已点击的条件。

2.2实现思路

  1. 搜索面板的商品分类需要使用Spring Data Solr的分组查询来实现
  2. 为了能够提高查询速度,我们需要把查询面板的品牌、规格数据提前放入redis
  3. 查询条件的构建、面板的隐藏需要使用angularJS来实现
  4. 后端的分类、品牌、规格、价格区间查询需要使用过滤查询来实现

3.查询分类列表

3.1需求分析

根据搜索关键字查询商品分类名称列表

3.2后端代码

修改SearchItemServiceImpl.java创建方法   

/**

 * 查询分类列表  

 * @param searchMap

 * @return

 */

private  List searchCategoryList(Map searchMap){

List<String> list=new ArrayList();

Query query=new SimpleQuery();

//按照关键字查询

Criteria criteria=new Criteria("item_keywords").is(searchMap.get("keywords"));

query.addCriteria(criteria);

//设置分组选项

GroupOptions groupOptions=new GroupOptions().addGroupByField("item_category");

query.setGroupOptions(groupOptions);

//得到分组页

GroupPage<TbItem> page = solrTemplate.queryForGroupPage(query, TbItem.class);

//根据列得到分组结果集

GroupResult<TbItem> groupResult = page.getGroupResult("item_category");

//得到分组结果入口页

Page<GroupEntry<TbItem>> groupEntries = groupResult.getGroupEntries();

//得到分组入口集合

List<GroupEntry<TbItem>> content = groupEntries.getContent();

for(GroupEntry<TbItem> entry:content){

list.add(entry.getGroupValue());//将分组结果的名称封装到返回值中

}

return list;

}

search方法调用

@Override

public Map<String, Object> search(Map searchMap) {

Map<String,Object> map=new HashMap<>();

//1.按关键字查询(高亮显示)

......

//2.根据关键字查询商品分类

List categoryList = searchCategoryList(searchMap);

map.put("categoryList",categoryList);

return map;

}

3.3前端代码

修改search.html

<div class="type-wrap" ng-if="resultMap.categoryList!=null">

<div class="fl key">商品分类</div>

<div class="fl value">

<span ng-repeat="category in resultMap.categoryList">

<a href="#">{{category}}</a>

</span>

</div>

<div class="fl ext"></div>

</div>

7.过滤查询

7.1需求分析

根据上一步构建的查询条件,实现分类、品牌和规格的过滤查询

7.2代码实现

7.2.1分类过滤

修改pinyougou-search-service工程的SearchItemServiceImpl.java

/**

 * 根据关键字搜索列表

 * @param keywords

 * @return

 */

private Map searchList(Map searchMap){

.......

//1.1关键字查询......

//1.2按分类筛选

if(!"".equals(searchMap.get("category"))){

Criteria filterCriteria=new Criteria("item_category").is(searchMap.get("category"));

FilterQuery filterQuery=new SimpleFilterQuery(filterCriteria);

query.addFilterQuery(filterQuery);

}

//高亮显示处理.....

}

7.2.2品牌过滤

修改pinyougou-search-service工程的SearchItemServiceImpl.java

/**

 * 根据关键字搜索列表

 * @param keywords

 * @return

 */

private Map searchList(Map searchMap){

.......

//1.1关键字查询

         .......

//1.2按分类筛选

         .......

//1.3按品牌筛选

if(!"".equals(searchMap.get("brand"))){

Criteria filterCriteria=new Criteria("item_brand").is(searchMap.get("brand"));

FilterQuery filterQuery=new SimpleFilterQuery(filterCriteria);

query.addFilterQuery(filterQuery);

}

//高亮显示处理...............

}

7.2.3规格过滤

实现思路:规格有多项,需要循环过滤。循环规格查询条件,根据key得到域名城,根据value设置过滤条件。

修改pinyougou-search-service工程的SearchItemServiceImpl.java

/**

 * 根据关键字搜索列表

 * @param keywords

 * @return

 */

private Map searchList(Map searchMap){

......

//1.1关键字查询

....

//1.2按分类筛选

.....

//1.3按品牌筛选

......

//1.4过滤规格

if(searchMap.get("spec")!=null){

Map<String,String> specMap= (Map) searchMap.get("spec");

for(String key:specMap.keySet() ){

Criteria filterCriteria=new Criteria("item_spec_"+key).is( specMap.get(key) );

FilterQuery filterQuery=new SimpleFilterQuery(filterCriteria);

query.addFilterQuery(filterQuery);

}

}

//高亮显示处理.....

}

7.2.4根据分类查询品牌规格列表

 

@Override

public Map<String, Object> search(Map searchMap) {

Map<String,Object> map=new HashMap<>();

//1.按关键字查询(高亮显示)

......

//2.根据关键字查询商品分类

......

//3.查询品牌和规格列表

String categoryName=(String)searchMap.get("category");

if(!"".equals(categoryName)){//如果有分类名称

map.putAll(searchBrandAndSpecList(categoryName));

}else{//如果没有分类名称,按照第一个查询

if(categoryList.size()>0){

map.putAll(searchBrandAndSpecList(categoryList.get(0)));

}

}

return map;

}

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值