天天看点

e3mall商城的归纳总结7之solr搭建和应用

敬给读者的话

本文主要应用的技术是solr技术的搭建和应用,本文小编尽量写的更详细一些,让读者在不考虑项目的情况下也能正常完成solr的搭建,说完搭建之后,再说明运行solrj在项目中如何应用solr服务的。

1、solr的搭建

2、把数据库中的数据导入索引库

3、solrJ的使用

solr下载链接,内包含zookeeper、solr、tomcat,若读者只想搭建集群版,则用solr+tomcat即可。zookeeper是在搭建集群中作为集群管理者才使用的。

一、Solr服务的搭建

准备环境:

一台linux系统(小编的的IP地址192.168.25.111)

jdk安装完成。

Tomcat安装完成。

e3mall商城的归纳总结7之solr搭建和应用

第一步:

把solr 的压缩包上传到Linux系统。

e3mall商城的归纳总结7之solr搭建和应用

第二步:

解压solr。

tar -xvf solr-4.10.3.tgz.tgz

e3mall商城的归纳总结7之solr搭建和应用

第三步:

安装Tomcat,解压缩即可。

第四步:

把solr部署到Tomcat下。

在 /root/solr-4.10.3/example/webapps下有solr.war包,复制到tomcat的webapps下

[[email protected] webapps]# cp solr.war /usr/local/tomcat/apache-tomcat-8.0.48/webapps/
           
e3mall商城的归纳总结7之solr搭建和应用

第五步:

解压缩war包。启动Tomcat解压。关闭tomcat,然后删除solr.war包。(一定要关闭tomcat,不然解压的文件也会消失)

e3mall商城的归纳总结7之solr搭建和应用

第六步:

把/root/solr-4.10.3/example/lib/ext目录下的所有的jar包,添加到solr工程中。

[[email protected] ext]# pwd

/root/solr-4.10.3/example/lib/ext

e3mall商城的归纳总结7之solr搭建和应用

[[email protected] ext]# cp * /usr/local/solr/tomcat/webapps/solr/WEB-INF/lib/

e3mall商城的归纳总结7之solr搭建和应用

第七步:

创建一个solrhome。/example/solr目录就是一个solrhome。复制此目录到/usr/local/solr/solrhome

[[email protected] example]# pwd

/root/solr-4.10.3/example

[[email protected] example]# cp -r solr /usr/local/solr/solrhome

[[email protected] example]#

e3mall商城的归纳总结7之solr搭建和应用

第八步:

关联solr及solrhome。需要修改tomcat中solr工程的web.xml文件。

e3mall商城的归纳总结7之solr搭建和应用
e3mall商城的归纳总结7之solr搭建和应用

第九步:启动Tomcat

http://192.168.25.111:8080/solr/

至此项目就搭建完成了,接下来我们来看看界面

认识solr界面

e3mall商城的归纳总结7之solr搭建和应用
e3mall商城的归纳总结7之solr搭建和应用

打表示经常使用.

我们可以用文档documents增加数据,使用query查询数据。

增加的数据为json数据

id:001

title:小锋

e3mall商城的归纳总结7之solr搭建和应用

下面我们查询一下:

e3mall商城的归纳总结7之solr搭建和应用
e3mall商城的归纳总结7之solr搭建和应用

q - 查询字符串。查询所有是? , 根据指定字段查询

fq - filter query 过滤查询。一般用来将查询的结果限定在某一范围,其作用类似于参数q,有时候可以被q取代。

示例(下面为q和fq都能使用的):

查询某字段为某值 type:私企 ; 查询某字段不为某值 -type:私企

查询id区间的 id:[10 TO 20]

某个开区间比如小于0的 num:[* TO 0]

某个时间段的(要满足solr日期格式 yyyy-mm-ddTHH:MM:SSZ) create_time:[2019-01-01T00:00:00Z TO 2019-01-31T23:59:59Z]

查询字段值为空、null或者不存在该字段 -field:*

sort - 排序。

示例:

age desc,id desc

fl - fieldlist 返回字段。多用于字段较多,只想关注某个字段时。

df - 默认的查询字段,一般默认指定。

wt - write type 指定输出格式。

qt - query type指定哪个类型来处理查询请求,一般不用指定,默认standarad。

indent - 返回的结果是否缩进。默认关闭。

version - 查询语法的版本。建议不使用它,有服务器指定默认值。

e3mall商城的归纳总结7之solr搭建和应用

三、配置项目中的业务域

solr服务里有自带的业务域,但是很明显不太适合我们的项目的表(就算适合,我们也想配置一个和我们项目mysql表类似的域名称,方便查看和使用。)solr也有自带的名词解析器,这里因为我们用的中文居多,因此我们需要配置一个中文解析器(推荐使用IKAnalyzer2012FF_u1)

配置业务域在solr的配置文件中的schema.xml中定义。我们需要1、商品Id 2、商品标题 3、商品卖点 4、商品价格 5、商品图片 6、分类名称

而创建对应的业务域需要制定中文分析器。

1、创建中文解析器

创建步骤:

第一步:把中文分析器添加到工程中。

1、把IKAnalyzer2012FF_u1.jar添加到solr工程的lib目录下

e3mall商城的归纳总结7之solr搭建和应用

2、把扩展词典、配置文件放到solr工程的WEB-INF/classes目录下。

e3mall商城的归纳总结7之solr搭建和应用

第二步:配置一个FieldType,制定使用IKAnalyzer

e3mall商城的归纳总结7之solr搭建和应用

修改schema.xml文件

修改Solr的schema.xml文件,添加FieldType:

<fieldType name="xiaofeng_ik" class="solr.TextField">
  <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
           

第三步:配置业务域,type制定使用自定义的FieldType。

设置业务系统Field

<field name="item_title" type="xiaofeng_ik" indexed="true" stored="true"/>
<field name="item_sell_point" type="xiaofeng_ik" indexed="true" stored="true"/>
<field name="item_price"  type="long" indexed="true" stored="true"/>
<field name="item_image" type="string" indexed="false" stored="true" />
<field name="item_category_name" type="string" indexed="true" stored="true" />

<field name="item_keywords" type="xiaofeng_ik" indexed="true" stored="false" multiValued="true"/>
<copyField source="item_title" dest="item_keywords"/>
<copyField source="item_sell_point" dest="item_keywords"/>
<copyField source="item_category_name" dest="item_keywords"/>
           
e3mall商城的归纳总结7之solr搭建和应用

第四步:重启tomcat

测试,我们写一段话测试一下中文解析器运行的如何.

e3mall商城的归纳总结7之solr搭建和应用

可以看到很完美的展示了中文的词组信息.(当然我在mydict.dic中配置了关键词,)

你也可以试一试

四、solr在项目中的使用

众所周知,每一个商城都会有有一个搜素引擎,而搜索引擎的使用才能进一步让我们找到想要的东西,但是如果我们直接在数据库中搜索关键词的话,必须是在数据库中存在的,而且必须是连续的词语,比如数据库中有台灯这个词汇,当用户搜索台灯这个词的时候,数据库也会找到相应的产品显示出来,但是若用户搜索电灯呢?,这时候就搜索不到相应的产品了,所以此时就引出了solr在项目中的使用.当然solr是基于tomcat使用的,所以我们如果是大型项目,需要配置solrclound来更快的响应用户。我们该如何管理solr呢?于是乎就引出了solrJ。

添加文档

第一步:把solrJ的jar包添加到工程中。

第二步:创建一个SolrServer,使用HttpSolrServer创建对象。

第三步:创建一个文档对象SolrInputDocument对象。

第四步:向文档中添加域。必须有id域,域的名称必须在schema.xml中定义。

第五步:把文档添加到索引库中。

第六步:提交

测试:

HttpSolrServer和CloudSolrServer是SolrServer的子包,因此我们用他们的父类进行接收子类的对象,这样方便单机版和集群版的切换(类似nginx单机和nginx集群版),spring主需要向容器中注册HttpSolrServer或者CloudSolrServer,即可使用SolrServer。(只允许其中一个单独使用)配置文件如下:

e3mall商城的归纳总结7之solr搭建和应用
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
	<!--单机版solr  -->
	 <bean id="httpSolrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer">
		<constructor-arg name="baseURL" value="http://192.168.25.110:8080/solr/collection1"/>
	</bean>
	<!-- 集群版solrServer -->
	<!-- <bean id="cloudSolrServer" class="org.apache.solr.client.solrj.impl.CloudSolrServer">
		<constructor-arg index="0" value="192.168.25.110:2281,192.168.25.110:2282,192.168.25.110:2283" />
		<property name="defaultCollection" value="collection1" />
	 </bean> -->
</beans>
           

不结合spring的测试类:

@Test
	public void addDocument() throws Exception {
		// 第一步:把solrJ的jar包添加到工程中。
		// 第二步:创建一个SolrServer,使用HttpSolrServer创建对象。
		SolrServer solrServer = new HttpSolrServer("http://192.168.25.154:8080/solr");
		// 第三步:创建一个文档对象SolrInputDocument对象。
		SolrInputDocument document = new SolrInputDocument();
		// 第四步:向文档中添加域。必须有id域,域的名称必须在schema.xml中定义。
		document.addField("id", "test001");
		document.addField("item_title", "测试商品");
		document.addField("item_price", "199");
		// 第五步:把文档添加到索引库中。
		solrServer.add(document);
		// 第六步:提交。
		solrServer.commit();
	}
           

后台数据一键导入数据到solr服务中。

service层(solr模块):

@Autowired
	private SearchMapper searchMapper;
	
	@Autowired
	private SolrServer solrServer;
	
	@Autowired
	private SolrQueryUtils solrQueryUtils;
	
	//后台更新solr索引库
	@Override
	public E3Result querySearch() {
	try {
		//获取数据库中得所有数据
		List<SearchResult> itemList = searchMapper.getItemList();
		//遍历所有数据,都导入到solr服务中。
		for (SearchResult searchResult : itemList) 
			{
			SolrInputDocument document = new SolrInputDocument();
			document.addField("id",searchResult.getId());
			document.addField("item_title",searchResult.getTitle());
			document.addField("item_sell_point",searchResult.getSell_point());
			document.addField("item_price",searchResult.getPrice());
			document.addField("item_image",searchResult.getImage());
			document.addField("item_category_name",searchResult.getCategory_id());
			solrServer.add(document);
			}
		//添加数据需要commit。
		solrServer.commit();
		//返回导入成功
		return E3Result.ok();
		}
		catch (Exception e) {
				e.printStackTrace();
				return E3Result.build(500, "导入失败");
			}
		
	}

           

controller层(后台的controller层manager模块)

@Controller
public class SearchController {

	@Autowired
	private SearchService searchService;
	@RequestMapping("/index/item/import")
	@ResponseBody
	public E3Result searchSolr() throws Exception {
		return  searchService.querySearch();
	}
}
           

首页搜索引擎:默认第一页,传入数据keywords、page、

service层(solr模块)

在//首页搜索引擎
	@Override
	public SearchZhuResult search(String keyword, Integer page, Integer rows) throws Exception{
		//创建搜索对象
		SolrQuery solrQuery = new SolrQuery();
		//添加默认搜索域
		solrQuery.set("df", "item_title"); 
		//添加搜索关键字
		solrQuery.setQuery(keyword);
		//搜索从第几个数据开始
		solrQuery.setStart((page-1)*rows);
		//搜索多少个数据
		solrQuery.setRows(rows);
		//设置高亮开启
		solrQuery.setHighlight(true);
		//设置高亮的返回域
		solrQuery.addHighlightField("item_title");
		//设置高亮的开头
		solrQuery.setHighlightSimplePre("<span style='color:red;'>");
		//设置高亮的结尾
		solrQuery.setHighlightSimplePost("</span>");
		//开始查询(自己写了一个工具类,方便查询使用)
		SearchZhuResult ZhuResult = solrQueryUtils.querySolr(solrQuery);
		//查询的数据有多少个
		Integer count = ZhuResult.getRecourdCount();
		//算出数据有多少页
		int pages =(count/rows);
		if (count % rows >0) {
			pages++;
		}
		ZhuResult.setTotalPages(pages);
		return ZhuResult;
	}
           

调用的工具类:(solr模块)

package cn.tsu.search.e3mall.solr;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import cn.tsu.e3mall.pojo.SearchResult;
import cn.tsu.e3mall.pojo.SearchZhuResult;

/**
 * 工具类 查询
 * @author xiaofeng
 *
 */



@Repository
public class SolrQueryUtils {
	
	@Autowired
	private SolrServer solrServer; 
	
	public SearchZhuResult querySolr(SolrQuery solrQuery) throws Exception{
		//开始查询
		QueryResponse query = solrServer.query(solrQuery);
		//获取查询的list
		SolrDocumentList documentList = query.getResults();
		//创建一个返回对象(把数据包装进新对象中)
		SearchZhuResult zhuResult = new SearchZhuResult();
		//查询的数据有多少个
		zhuResult.setRecourdCount((int) documentList.getNumFound());
		//创建一个list大对象接收 
		List<SearchResult> list = new ArrayList<>();
		Map<String, Map<String, List<String>>> highlighting = query.getHighlighting();
		for (SolrDocument solrDocument : documentList) {
			//创建List<SearchResult>中的SearchResult对象
			SearchResult listitem = new SearchResult();
			//向对象中存放id
			listitem.setId((String) solrDocument.get("id"));
			//通过id获取高亮的map集合
			Map<String, List<String>> map = highlighting.get(solrDocument.get("id"));
			//获取高亮的map集合中的item_title域的值
			List<String> title_list = map.get("item_title");
			//如果不为空,则存放高亮的数据到返回对象listitem中
			if(null !=title_list && title_list.size() > 0) {
				listitem.setTitle(title_list.get(0));
			}else{
			//否则存放不是高亮的item_title
			listitem.setTitle((String) solrDocument.get("item_title"));
				}
			//存放其他域的值
			listitem.setSell_point((String) solrDocument.get("item_sell_point"));
			listitem.setCategory_id((String) solrDocument.get("item_category_name"));
			listitem.setImage((String) solrDocument.get("item_image"));
			listitem.setPrice((Long) solrDocument.get("item_price"));
			//添加到list集合中
			list.add(listitem);
		}
		//把list集合存放到返回对象中
		zhuResult.setItemList(list);
		return zhuResult;
	}
}

           

controller层(solr模块)

package cn.tsu.search.e3mall.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import cn.tsu.e3mall.common.Commons;
import cn.tsu.e3mall.pojo.SearchZhuResult;
import cn.tsu.search.e3mall.service.SearchService;

/**
 * 首页搜索引擎
 * @author xiaofeng
 *
 */
@Controller
public class SearchController {

	@Autowired 
	private SearchService searchService;
	
	@RequestMapping("/search")
	public String search(String keyword,@RequestParam(defaultValue="1") Integer page,Model model) {
		try {
			//解决乱码
			keyword= new String(keyword.getBytes("ISO-8859-1"), "UTF-8");
			//调用服务层,返回搜索结果(高亮)
			SearchZhuResult searchResult = searchService.search(keyword, page, Commons.SOLR_ROWS);
			model.addAttribute("query", keyword);
			model.addAttribute("totalPages", searchResult.getTotalPages());
			model.addAttribute("page",page);
			model.addAttribute("recourdCount", searchResult.getRecourdCount());
			model.addAttribute("itemList", searchResult.getItemList());
			return "search";
		} catch (Exception e) {
			e.printStackTrace();
			model.addAttribute("query", "啊哦~,你搜索的不存在"); 
			return "search";
		}
		
	}
}

           

本章写了又改,改了又写,写的很详细了,希望可以给您带来一些帮助,如果您有什么疑惑,欢迎评论区留言,如果我看到会及时回复大家的。。

继续阅读