solr_架构案例【京东站内搜索】(附程序源代码)
注意事项:首先要保证部署solr服务的Tomcat容器和检索solr服务中数据的Tomcat容器,它们的端口号不能发生冲突,否则web程序是不可能运行起来的。
一:solr服务的端口号、我这里的solr服务的tomcat容器的端口号已经修改为8083:

二:检索solr服务中数据的tomcat容器的端口号、我这里是8080:

最后必须要保证2个容器能正常访问。
需求:使用Solr实现电商网站中商品信息搜索功能,可以根据关键字搜索商品信息,根据商品分类、价格过滤搜索结果,也可以根据价格进行排序,实现分页。
界面如下:

1、架构分析:

自己开发的应用:
Controller层的作用:获取搜索条件,并响应搜索结果到前台页面。
Service层的作用:接收Controller传递过来的参数,根据参数拼装一个查询条件,调用dao层方法,查询商品数据;接收返回的商品列表和商品的总数量,根据每页显示的商品数量计算总页数。
Dao层的作用:接收Service层传递过来的参数,根据参数去检索solr索引库中的商品数据,返回查询结果。
2、WEB工程的搭建(相关的jar必须得全部引入,环境搭建篇中已经注明了):

需要说明的几点问题:
(a)、在springmvc核心配置文件中配置solr服务时,一定将solr服务的连接地址配置正确,否则无法找到solr索引库:
<?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:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <!-- 配置注解扫描-->
<context:component-scan base-package="com.jd"/> <!-- 配置注解驱动: 就相当于自动替我们配置注解形式的处理器映射器和处理器适配器 -->
<mvc:annotation-driven/> <!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean> <!-- 配置solrServer服务,供数据访问层检索数据使用: -->
<bean id="solrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer">
<!-- 配置构造方法 -->
<constructor-arg value="http://localhost:8083/solr/collection1"/>
</bean>
</beans>
(b)、在项目的web.xml配置文件中配置springmvc的前端控制器、post请求的乱码解决等问题:
<!-- springMvc前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping> <!-- 解决post乱码 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3、各个开发层的代码实现,程序中基本附带注释:
【Dao层】
package com.jd.dao; import org.apache.solr.client.solrj.SolrQuery; import com.jd.pojo.ResultModel; /**
* 商品模块Dao接口:
* @author zxz
*
*/ public interface ProductDao { /**
* 根据检索条件检索solr服务上索引库中的数据:
* @param solrQuery
* @return
* @throws Exception
*/
public ResultModel search(SolrQuery solrQuery) throws Exception; }
package com.jd.dao; import java.util.ArrayList;
import java.util.List;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
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 com.jd.pojo.ProductModel;
import com.jd.pojo.ResultModel; /**
* 商品模块Dao层开发:
* 核心功能:接收Service层传递过来的参数,根据参数去检索solr索引库中的商品数据,返回查询结果
* @author zxz
*
*/
@Repository
public class ProductDaoImpl implements ProductDao { //注入solr服务(该solr服务在springmvc的核心配置文件中已经进行配置了):
@Autowired
private SolrServer solrServer; //检索solr服务上索引库中的数据:
@Override
public ResultModel search(SolrQuery solrQuery) throws Exception {
//1、查询并获取响应结果:
QueryResponse response = solrServer.query(solrQuery); //2、从响应中获取结果集:
SolrDocumentList results = response.getResults(); //3、处理结果集:
//专门用于存放响应结果集中的个个商品数据的集合
List<ProductModel> productList = new ArrayList<ProductModel>();
//用于将检索到的并处理好的数据封装到ResultModel对象中,用于返回给Service层:
ResultModel resultModel = new ResultModel();
//做非空校验,如果检索到的结果集不为空的话,就进行处理并封装结果数据:
if(results != null){
//(1)、封装查询到的商品总数:
resultModel.setRecordCount(results.getNumFound()); //(2)、遍历响应中的结果集,并将数据一一封装进ProductModel对象中:
for (SolrDocument document : results) {
//创建ProductModel对象:
ProductModel product = new ProductModel();
//商品id:
product.setPid(String.valueOf(document.get("id")));
//商品名称:
product.setName(String.valueOf(document.get("product_name")));
//商品价格:
if(String.valueOf(document.get("product_price"))!=null &&
!"".equals(String.valueOf(document.get("product_price")))){
product.setPrice(Float.valueOf(String.valueOf(document.get("product_price"))));
}
//商品图片:
product.setPicture(String.valueOf(document.get("product_picture"))); //将当前遍历并封装好的ProductModel对象添加到存放商品数据的集合中:
productList.add(product);
} //循环处理并封装好结果集之后,将存放商品数据的集合设置到ResultModel对象中:
resultModel.setProductList(productList);
} //将封装好的数据返回给Service层处理:
return resultModel;
}
}
【Service层】
package com.jd.service; import com.jd.pojo.ResultModel; /**
* 商品模块Service层接口:
* @author zxz
*
*/ public interface ProductService { /**
* 根据各种检索条件去调用dao层的方法,得到符合检索条件的数据:
* @param queryString
* @param catalog_name
* @param price
* @param page
* @param sort
* @return
* @throws Exception
*/
public ResultModel search(String queryString, String catalog_name,
String price, Integer page, String sort) throws Exception; }
package com.jd.service; import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrQuery.ORDER;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.jd.dao.ProductDao;
import com.jd.pojo.ResultModel; /**
* 商品模块Service层开发:
* 核心功能:接收Controller传递过来的参数,根据参数拼装一个查询条件,调用dao层方法,查询商品数据。
* 接收返回的商品列表和商品的总数量,根据每页显示的商品数量计算总页数。
* @author zxz
*
*/
@Service
public class ProductServiceImpl implements ProductService { //注入Dao:
@Autowired
private ProductDao productDao; //定义常量,代表每页显示的商品条数:
private final static Integer PAGE_SIZE = 60; //根据检索条件得到数据:
@Override
public ResultModel search(String queryString, String catalog_name, String price, Integer page, String sort)
throws Exception {
//1、封装查询条件对象,因为需要调用dao层的方法,dao层的检索方法就需要一个solr服务的查询条件对象:
SolrQuery solrQuery = new SolrQuery(); //2、设置默认查询的域(该默认的域已经在solrHome/collection1/conf/schema.xml配置文件中配置了业务域):
solrQuery.setQuery("product_keywords"); //3、设置查询的关键字:
if(queryString!=null && !"".equals(queryString)){
solrQuery.setQuery(queryString);
}else{
//如果没有查询的关键字,则默认查询所有商品数据:
solrQuery.setQuery("*:*");
} //4、根据商品分类进行过滤:
if(catalog_name!=null && !"".equals(catalog_name)){
//注意查询语法:不要忽略":"号
solrQuery.addFilterQuery("product_catalog_name:" + catalog_name);
} //5、根据商品价格进行过滤:
if(price!=null && !"".equals(price)){
//因为传递过来的的商品价格的格式为:100-300,所以需要切割并根据价格区间过滤商品数据:
String[] split = price.split("-");
if(split!=null && split.length>1){
//为什么判断长度必须大于1,因为根据价格过滤需要最小值和最大值,必须有俩个值才能过滤成功
solrQuery.addFilterQuery("product_price:["+split[0]+" TO "+split[1]+"]");
}
} //6、按照商品价格排序展示商品数据:
if("1".equals(sort)){
solrQuery.setSort("product_price",ORDER.asc);
}else{
solrQuery.setSort("product_price",ORDER.desc);
} //7、分页查询商品数据:
//首先校验数据合法性,如果当前页的值为空或小于1,则默认开始查询第一页数据:
if(page == null){
page = 1;
}
if(page < 1){
page = 1;
}
//计算起始索引:
Integer startIndex = (page-1) * PAGE_SIZE;
//设置起始索引:
solrQuery.setStart(startIndex);
//设置每页显示的商品记录数:
solrQuery.setRows(PAGE_SIZE); //8、根据封装后的SolrQuery查询对象查询商品数据:
ResultModel resultModel = productDao.search(solrQuery);
//设置当前页数:
resultModel.setCurPage(page);
//计算总页数:
Long pageCount = (long) Math.ceil((resultModel.getRecordCount()*1.0) / PAGE_SIZE);
//设置总页数:
resultModel.setPageCount(pageCount); return resultModel;
}
}
【Controller层】
package com.jd.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 com.jd.pojo.ResultModel;
import com.jd.service.ProductService; /**
* 商品模块:
* @author zxz
*
*/ @Controller
public class ProductController { //注入Service接口:
@Autowired
private ProductService productService; @RequestMapping("/list")
//根据条件和分页信息检索商品数据:
public String proList(String queryString, String catalog_name,
String price, Integer page, String sort,Model model) throws Exception{ //调用service层的方法得到检索后的数据:
ResultModel resultModel = productService.search(queryString, catalog_name, price, page, sort); //将检索得到的数据返回给页面:
model.addAttribute("result", resultModel); //注意:这里的名称必须和jsp页面上获取数据的名称保持一致
//回显查询条件:
model.addAttribute("queryString", queryString); //这里的条件回显时,名称也必须和jsp页面上获取数据的名称保持一致
model.addAttribute("catalog_name", catalog_name);
model.addAttribute("price", price);
model.addAttribute("sort", sort); return "product_list";
}
}
最后pojo类的数据模型截个图给大家分享一下(案例所需的基本程序都在这里了,希望能帮到大家,如果有什么不对的地方望各位指教!!!):


solr_架构案例【京东站内搜索】(附程序源代码)的更多相关文章
- 一步步开发自己的博客 .NET版(5、Lucenne.Net 和 必应站内搜索)
前言 这次开发的博客主要功能或特点: 第一:可以兼容各终端,特别是手机端. 第二:到时会用到大量html5,炫啊. 第三:导入博客园的精华文章,并做分类.(不要封我) 第四:做 ...
- Lucene.net站内搜索—3、最简单搜索引擎代码
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
- Lucene.net站内搜索—1、SEO优化
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
- 使用Lucene.NET实现简单的站内搜索
使用Lucene.NET实现简单的站内搜索 导入Lucene.NET 开发包 Lucene 是apache软件基金会一个开放源代码的全文检索引擎工具包,是一个全文检索引擎的架构,提供了完整的查询引擎和 ...
- Compass实战 站内搜索
今天早上打算对这两天学习的Lucene以及Compass总结一下,想来想去,还是写个小项目来验证最好了.于是就有了今天的这篇文章.难易程度适合对于Compass或者Lucene刚入门的童鞋,大牛看到后 ...
- 为帝国cms模板添加站内搜索小教程
由于客户的需要,最近都在整帝国cms,很多东西还是不熟悉,特别是帝国cms模板,以前用的那些网站模板一般是保存在ftp文件中,而帝国cms模板是直接保存在数据库中,修改是在网站后台的模板管理,得慢慢适 ...
- 利用Solr服务建立的站内搜索雏形---solr1
最近看完nutch后总感觉像好好捯饬下solr,上次看到老大给我展现了下站内搜索我便久久不能忘怀.总觉着之前搭建的nutch配上solr还是有点呆板,在nutch爬取的时候就建立索引到solr服务下, ...
- Lucene.net站内搜索—6、站内搜索第二版
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
- Lucene.net站内搜索—5、搜索引擎第一版实现
目录 Lucene.net站内搜索—1.SEO优化 Lucene.net站内搜索—2.Lucene.Net简介和分词Lucene.net站内搜索—3.最简单搜索引擎代码Lucene.net站内搜索—4 ...
随机推荐
- Taurus.MVC 2.0 开源发布:WebAPI开发教程
背景: 有用户反映,Tausus.MVC 能写WebAPI么? 能! 教程呢? 嗯,木有! 好吧,刚好2.0出来,就带上WEBAPI教程了! 开源地址: https://github.com/cyq1 ...
- TinyWeb v1.0 正式完成第一个Release版本(功能基于 libuv 跨平台库)
使用方法很简单,很容易融入现有项目,使现有项目拥有Web网站功能和WebSocket,以及Socket直连! 并且包含了一个跨平台(windows/linux)工具集合; 嗯,也挺棒的^,^ 在项目中 ...
- angular实现统一的消息服务
后台API返回的消息怎么显示更优雅,怎么处理才更简洁?看看这个效果怎么样? 自定义指令和服务实现 自定义指令和服务实现消息自动显示在页面的顶部,3秒之后消失 1. 显示消息 这种显示消息的方式是不是有 ...
- 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法
若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...
- 开始学nodejs——net模块
net模块的组成部分 详见 http://nodejs.cn/api/net.html 下面整理出了整个net模块的知识结构,和各个事件.方法.属性的用法 net.Server类 net.Socket ...
- 算法与数据结构(八) AOV网的关键路径
上篇博客我们介绍了AOV网的拓扑序列,请参考<数据结构(七) AOV网的拓扑排序(Swift面向对象版)>.拓扑序列中包括项目的每个结点,沿着拓扑序列将项目进行下去是肯定可以将项目完成的, ...
- UE4新手引导入门教程
请大家去这个地址下载:file:///D:/UE4%20Doc/虚幻4新手引导入门教程.pdf
- springMVC初探--环境搭建和第一个HelloWorld简单项目
注:此篇为学习springMVC时,做的笔记整理. MVC框架要做哪些事情? a,将url映射到java类,或者java类的方法上 b,封装用户提交的数据 c,处理请求->调用相关的业务处理—& ...
- 代码的坏味道(19)——狎昵关系(Inappropriate Intimacy)
坏味道--狎昵关系(Inappropriate Intimacy) 特征 一个类大量使用另一个类的内部字段和方法. 问题原因 类和类之间应该尽量少的感知彼此(减少耦合).这样的类更容易维护和复用. 解 ...
- Android事件分发机制浅谈(一)
---恢复内容开始--- 一.是什么 我们首先要了解什么是事件分发,通俗的讲就是,当一个触摸事件发生的时候,从一个窗口到一个视图,再到一个视图,直至被消费的过程. 二.做什么 在深入学习android ...