Solr和Spring Data Solr
1.Solr简介
Solr是一个开源搜索平台,用于构建搜索应用程序。 它建立在Lucene(全文搜索引擎)之上。 Solr是企业级的,快速的和高度可扩展的。Solr可以和Hadoop(http://www.yiibai.com/hadoop/)一起使用。由于Hadoop处理大量数据,Solr帮助我们从这么大的源中找到所需的信息。不仅限于搜索,Solr也可以用于存储目的。像其他NoSQL数据库一样,它是一种非关系数据存储和处理技术。总之,Solr是一个可扩展的,可部署,搜索/存储引擎,优化搜索大量以文本为中心的数据。
2.Linux下Solr的安装
1:把Tomcat安装包导入Linux系统,解压 Tomcat并重命名tomcat-solr
2:导入solr的Linux安装包到Linux服务器,解压 solr-4.10.3.tgz.tgz。
命令:tar -zxvf solr-4.10.3.tgz.tgz
3:把 solr 下的example/webapps/solr.war部署到 Tomcat-solr\webapps下(去掉版本号)。
命令:cp solr-4.10.3/example/webapps/solr.war tomcat-solr/webapps/
4:使用命令解压:unzip -oq solr.war -d solr
5:把solr下example/lib/ext 目录下的所有的 jar 包,添加到 solr 的工程中(\WEB-INF\lib目录下)。
命令:cp solr-4.10.3/example/lib/ext/* tomcat-solr/webapps/solr/WEB-INF/lib/
6:创建一个索引仓库。solr 下的/example/solr 目录就是一个索引仓库。复制此目录【solr】到任意磁盘即可完 成自定义索引仓库创建。
命令:cp -r solr-4.10.3/example/solr . (把solr索引库仓库文件夹拷贝当前目录; . 表示当前目录)
7:关联tomcat服务器中 solr项目 和 索引仓库solr。修改Tomcat/bin/catalina.sh文件指定索引仓库路径即可
//在Tomcat/bin/catalina.sh第二行指定索引仓库路径即可
export JAVA_OPTS="-Dsolr.solr.home=/usr/local/dintalk/singleSolr/solr"
http://IP:8080/solr/
9.加载contrib,dist依赖类库
把solr-4.10.3/contrib,dist 文件夹拷贝 索引仓库目录下(和索引库在同一级目录)
命令:cp -r solr-4.10.3/contrib/ solr-4.10.3/dist/ solr
配置solr索引库中核心配置文件:solrConfig.xml 加载contrib,dist依赖jar包
IK Analyzer 是一个开源的,基亍 java 语言开发的轻量级的中文分词工具包。最初,它是以开源项目Luence 为应用主体的,结合词典分词和文法分析算法的中文分词组件。从 3.0 版本开始,IK 发展为面向 Java 的公用分词组件,独立亍 Lucene 项目,同时提供了对 Lucene 的默认优化实现。在 2012 版本中,IK 实现了简单的分词歧义排除算法,标志着 IK 分词器从单纯的词典分词向模拟语义分词衍化。
3.1IK Analyzer配置
1、把IKAnalyzer2012FF_u1.jar 添加到 solr 工程的 lib 目录下
2、创建WEB-INF/classes(手动创建)文件夹 把扩展词典、停用词词典、配置文件放到 solr 工程的 WEB- INF/classes 目录下:
3、修改 索引库 的 schema.xml 文件,配置一个 FieldType,使用 IKAnalyzer
<fieldType name="text_ik" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> fieldType>
域相当于数据库的表字段,用户存放数据,因此用户根据业务需要去定义相关的Field(域),一般来说,每一种对应着一种数据,用户对同一种数据进行相同的操作。
域的常用属性:
-
name:指定域的名称
-
type:指定域的类型
-
indexed:是否索引
-
stored:是否存储
-
required:是否必须
-
multiValued:是否多值
4.1普通域
修改solrhome的schema.xml 文件 设置业务系统 Field :
<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中的数据复制到另一个域中 :
<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/> <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的应用集成到Spring中?Spring Data Solr就是为了方便Solr的开发所研制的一个框架,其底层是对SolrJ(官方API)的封装。
1.Spring Data Solr 使用步骤
第一步:导入相关坐标
<dependency> <groupId>org.springframework.datagroupId> <artifactId>spring-data-solrartifactId> <version>1.5.5.RELEASEversion> dependency>
<?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: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"> <solr:solr-server id="solrServer" url="http://127.0.0.1:8080/solr"/> <bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate"> <constructor-arg ref="solrServer"/> bean> beans>
public class TbItem implements Serializable{ // id 和solr中的主键名称一致可以不用写 @Field private Long id; @Field("item_title") private String title; @Field("item_image") private String image; ...
/** * 测试Solr的简单操作 * @author Mr.song * @date 2019/06/13 16:55 */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext-solr.xml") public class SolrTest { @Autowired private SolrTemplate solrTemplate; @Test //增加item public void testAddItemToSolrHome(){ TbItem item = new TbItem(); item.setId(1L); item.setTitle("测试Title"); item.setImage("这是图片"); solrTemplate.saveBean(item); //增删改需要提交 solrTemplate.commit(); } //重新赋值便是更新 @Test //根据主键查询 public void testQueryById(){ TbItem item = solrTemplate.getById(1L, TbItem.class); System.out.println(item.getTitle()); } @Test //条件查询 public void testQuery(){ //查询所有, *:* 前面是字段 后面是条件 SimpleQuery simpleQuery = new SimpleQuery("*:*"); //设置分页 simpleQuery.setOffset(5);//开始索引 simpleQuery.setRows(5);//每页记录数 //拼接条件 Criteria criteria = new Criteria("item_title"); criteria = criteria.contains("苹果"); simpleQuery.addCriteria(criteria); ScoredPageitems = solrTemplate.queryForPage(simpleQuery, TbItem.class); for (TbItem item : items) { System.out.println(item.getTitle()); } } @Test //删除item(根据主键删除) public void testDelItem(){ solrTemplate.deleteById("1"); solrTemplate.commit(); } @Test //清空 public void delSolrHome(){ SimpleQuery query = new SimpleQuery("*:*"); solrTemplate.delete(query); solrTemplate.commit(); } }
/** * @author Mr.song * @date 2019/06/13 18:22 */ @Service public class ItemSearchServiceImpl implements ItemSearchService { @Autowired private TbItemMapper itemMapper; @Autowired private SolrTemplate solrTemplate; /** * 根据关键字查询solr索引库 * @param searchMap 前端的查询条件,封装为Map * @return 查询的结果,不封装为实体,返回Map效果一样 */ @Override public Map search(Map searchMap) { //1.关键字查询 String keywords = searchMap.get("keywords").toString(); //2.封装查询条件(高亮查询) SimpleHighlightQuery simpleHighlightQuery = new SimpleHighlightQuery(); if (keywords != null) { //这是查询的域 Criteria criteria = new Criteria("item_keywords"); criteria = criteria.contains(keywords); simpleHighlightQuery.addCriteria(criteria); } //1.高亮查询的高亮设置(即查询关键字的高亮显示) HighlightOptions options = new HighlightOptions(); //设置高亮的头部和尾部 options.setSimplePrefix(""); options.setSimplePostfix(""); //设置高亮的域名字,设置查询的选项 options.addField("item_title"); simpleHighlightQuery.setHighlightOptions(options); //2.过滤查询条件=====分类相关 String categoryStr = (String) searchMap.get("category"); if (categoryStr != null){ //2.1按照传入的分类字符串进行查询,创建过滤查询对象 SimpleFilterQuery filterQuery = new SimpleFilterQuery(); //2.2创建条件,设置域的名称 Criteria criteria = new Criteria("item_category"); //2.3设置匹配字符串 criteria = criteria.contains(categoryStr); //2.4过滤查询添加条件 filterQuery.addCriteria(criteria); //2.5查询添加过滤查询 simpleHighlightQuery.addFilterQuery(filterQuery); System.out.println("分类过滤查询:"+categoryStr); } //3.过滤查询条件=====品牌相关 String brand = (String) searchMap.get("brand"); if (brand != null){ SimpleFilterQuery filterQuery = new SimpleFilterQuery(); Criteria criteria = new Criteria("item_brand"); criteria = criteria.contains(brand); filterQuery.addCriteria(criteria); simpleHighlightQuery.addFilterQuery(filterQuery); System.out.println("品牌过滤查询:"+brand); } //4.过滤查询条件=====规格相关 MapspecMap = (Map) searchMap.get("spec"); if (specMap != null){ for (String s : specMap.keySet()) { SimpleFilterQuery filterQuery = new SimpleFilterQuery(); Criteria criteria = new Criteria("item_spec_"+s); criteria = criteria.contains(specMap.get(s)); filterQuery.addCriteria(criteria); simpleHighlightQuery.addFilterQuery(filterQuery); System.out.println("规格滤查询:"+s); } } //4.过滤条件查询=====价格相关 String price = (String) searchMap.get("price");//0-199 if (price != null){ //1500-2000 String[] prices = price.split("-"); //过滤条件增加起始价格 SimpleFilterQuery filterQuery1 = new SimpleFilterQuery(); Criteria criteria1 = new Criteria("item_price"); criteria1 = criteria1.greaterThanEqual(prices[0]); //大于等于起始价格 filterQuery1.addCriteria(criteria1); simpleHighlightQuery.addFilterQuery(filterQuery1); //过滤条件增加结束价格 if(!"*".equals(prices[1])){ //防止3000元以上的*号 SimpleFilterQuery filterQuery2 = new SimpleFilterQuery(); Criteria criteria2 = new Criteria("item_price"); criteria2 = criteria2.lessThanEqual(prices[1]); //小于等于结束价格 filterQuery2.addCriteria(criteria2); simpleHighlightQuery.addFilterQuery(filterQuery2); } System.out.println("价格过滤查询:"+price); } //5.价格升降序=======价格升降序,前端设置默认是desc String sort = (String) searchMap.get("sort"); //定义排序对象 Sort orders = null; if ("DESC".equalsIgnoreCase(sort)){ //降序查询 :参数1-指定升降序 参数2-指定域 orders = new Sort(Sort.Direction.DESC,"item_price"); System.out.println("价格降序过滤查询:"+sort); }else { orders = new Sort(Sort.Direction.ASC,"item_price"); System.out.println("价格升序过滤查询:"+sort); } //为查询添加排序 simpleHighlightQuery.addSort(orders); //6.分页相关 Integer pageSize = (Integer) searchMap.get("pageSize"); Integer pageNo = (Integer) searchMap.get("pageNo"); //设置分页参数 :起始索引和每页条数 simpleHighlightQuery.setOffset((pageNo-1)*pageSize); simpleHighlightQuery.setRows(pageSize); //查询 HighlightPage tbItems = solrTemplate. queryForHighlightPage(simpleHighlightQuery, TbItem.class); //将高亮设置后的属性赋值给查出的内容 List contents = tbItems.getContent(); for (TbItem content : contents) { List highlights = tbItems.getHighlights(content); if (highlights.size()>0){//防止数组空内容 List snipplets = highlights.get(0).getSnipplets(); if (snipplets.size()>0){//防止空内容 content.setTitle(snipplets.get(0)); } } } //构建返回的map对象 Map returnMap = new HashMap(); returnMap.put("rows", contents); //分页需要总记录数 returnMap.put("total",tbItems.getNumberOfElements()); return returnMap; } /** * 根据商品的id(spu)将商品(sku)导入到solr索引库中 * @param ids 商品的id数组(spu) */ @Override public void importItemsByGoodsId(Long[] ids) { //goods的所有ids,查询其列表导入到solr索引库 TbItemExample example = new TbItemExample(); example.createCriteria().andGoodsIdIn(Arrays.asList(ids)); List tbItems = itemMapper.selectByExample(example); //将数据存入solr索引库 solrTemplate.saveBeans(tbItems); solrTemplate.commit(); System.out.println("solr库导入了商品:"+tbItems.size()+"个"); } /** * 根据商品的id(spu)将商品(sku)从solr索引库中删除 * @param ids 商品的id数组(spu) */ @Override public void delItemsByGoodsId(Long[] ids) { //id是goods的id TbItemExample example = new TbItemExample(); example.createCriteria().andGoodsIdIn(Arrays.asList(ids)); List tbItems = itemMapper.selectByExample(example); //循环删除sku(solr索引库中的) for (TbItem tbItem : tbItems) { solrTemplate.deleteById(tbItem.getId().toString()); } solrTemplate.commit(); System.out.println("solr库删除了商品:"+tbItems.size()+"个"); } }
关注微信公众号, 随时随地学习