1. Solr的安装及配置php
a) Solr整合tomcathtml
b) Solr后台管理功能介绍java
c) 配置中文分析器mysql
2. 使用Solr的后台管理索引库程序员
a) 添加文档web
b) 删除文档算法
c) 修改文档spring
d) 查询文档sql
3. 使用SolrJ管理索引库数据库
a) 添加文档
b) 修改文档
c) 删除文档
d) 查询文档
4. 电商搜索案例实现
a) 案例分析
b) 案例实现
使用Solr实现电商网站中商品信息搜索功能,能够根据关键字、分类、价格搜索商品信息,也能够根据价格进行排序。
在一些大型门户网站、电子商务网站等都须要站内搜索功能,使用传统的数据库查询方式实现搜索没法知足一些高级的搜索需求,好比:搜索速度要快、搜索结果按相关度排序、搜索内容格式不固定等,这里就须要使用全文检索技术实现搜索功能。
单独使用Lucene实现站内搜索须要开发的工做量较大,主要表如今:索引维护、索引性能优化、搜索性能优化等,所以不建议采用。
基于Solr实现站内搜索扩展性较好而且能够减小程序员的工做量,由于Solr提供了较为完备的搜索引擎解决方案,所以在门户、论坛等系统中经常使用此方案。
Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务器。Solr提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展,并对索引、搜索性能进行了优化。
Solr能够独立运行,运行在Jetty、Tomcat等这些Servlet容器中,Solr 索引的实现方法很简单,用 POST 方法向 Solr 服务器发送一个描述 Field 及其内容的 XML 文档,Solr根据xml文档添加、删除、更新索引 。Solr 搜索只须要发送 HTTP GET 请求,而后对 Solr 返回Xml、json等格式的查询结果进行解析,组织页面布局。Solr不提供构建UI的功能,Solr提供了一个管理界面,经过管理界面能够查询Solr的配置和运行状况。
Solr与Lucene的区别:
Lucene是一个开放源代码的全文检索引擎工具包,它不是一个完整的全文检索引擎,Lucene提供了完整的查询引擎和索引引擎,目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者以Lucene为基础构建全文检索引擎。
Solr的目标是打造一款企业级的搜索引擎系统,它是一个搜索引擎服务,能够独立运行,经过Solr能够很是快速的构建企业的搜索引擎,经过Solr也能够高效的完成站内搜索功能。
从Solr官方网站(http://lucene.apache.org/solr/ )下载Solr4.10.3,根据Solr的运行环境,Linux下须要下载lucene-4.10.3.tgz,windows下须要下载lucene-4.10.3.zip。
Solr使用指南可参考:https://wiki.apache.org/solr/FrontPage。
将solr-4.10.3.zip解压:
bin:solr的运行脚本
contrib:solr的一些贡献软件/插件,用于加强solr的功能。
dist:该目录包含build过程当中产生的war和jar文件,以及相关的依赖文件。
docs:solr的API文档
example:solr工程的例子目录:
该目录叫作solrHome,是一个包含了默认配置信息的Solr的Core目录。
该目录包含了在Solr的multicore中设置的多个Core目录。
该目录中包括一个solr.war,该war可做为solr的运行实例工程。
licenses:solr相关的一些许可信息
solr 须要运行在一个Servlet容器中,Solr4.10.3要求jdk使用1.7以上,Solr默认提供Jetty(java写的Servlet容器),这里使用Tocmat做为Servlet容器,环境以下:
Solr:Solr4.10.3
Jdk:jdk1.7.0_72
Tomcat:apache-tomcat-7.0.53
建立一个Solr home目录,SolrHome是Solr运行的主目录,目录中包括了运行Solr实例全部的配置文件和数据文件,Solr实例就是SolrCore,一个SolrHome能够包括多个SolrCore(Solr实例),每一个SolrCore提供单独的搜索和索引服务。
example\solr是一个solr home目录结构,以下:
上图中“collection1”是一个SolrCore(Solr实例)目录 ,目录内容以下所示:
说明:
collection1:叫作一个Solr运行实例SolrCore,SolrCore名称不固定,一个solr运行实例对外单独提供索引和搜索接口。
solrHome中能够建立多个solr运行实例SolrCore。
一个solr的运行实例对应一个索引目录。
conf是SolrCore的配置文件目录 。
data目录存放索引文件须要建立
第一步:安装tomcat。D:\temp\apache-tomcat-7.0.53
第二步:把solr的war包复制到tomcat 的webapp目录下。
把\solr-4.10.3\dist\solr-4.10.3.war复制到D:\temp\apache-tomcat-7.0.53\webapps下。
更名为solr.war
第三步:solr.war解压。使用压缩工具解压或者启动tomcat自动解压。解压以后删除solr.war
第四步:把\solr-4.10.3\example\lib\ext目录下的全部的jar包(日志)添加到solr工程中
第五步:配置solrHome和solrCore。
1)建立一个solrhome(存放solr全部配置文件的一个文件夹)。\solr-4.10.3\example\solr目录就是一个标准的solrhome。
2)把\solr-4.10.3\example\solr文件夹复制到D:\temp\0108路径下,更名为solrhome,更名不是必须的,是为了便于理解。
3)在solrhome下有一个文件夹叫作collection1这就是一个solrcore。就是一个solr的实例。一个solrcore至关于mysql中一个数据库。Solrcore之间是相互隔离。
Xml的配置信息:
Lib:solr服务依赖的扩展包,默认的路径是collection1\lib文件夹,若是没有就建立一个
dataDir:配置了索引库的存放路径。默认路径是collection1\data文件夹,若是没有data文件夹,会自动建立。
requestHandler:
第六步:告诉solr服务器配置文件也就是solrHome的位置。修改web.xml使用jndi的方式告诉solr服务器。
Solr/home名称必须是固定的。
第七步:启动tomcat
第八步:访问http://localhost:8080/solr/
仪表盘,显示了该Solr实例开始启动运行的时间、版本、系统资源、jvm等信息。
Solr运行日志信息
Cloud即SolrCloud,即Solr云(集群),当使用Solr Cloud模式运行时会显示此菜单,以下图是Solr Cloud的管理界面:
Solr Core的管理界面。Solr Core 是Solr的一个独立运行实例单位,它能够对外提供索引和搜索服务,一个Solr工程能够运行多个SolrCore(Solr实例),一个Core对应一个索引目录。
添加solrcore:
第一步:复制collection1更名为collection2
第二步:修改core.properties。name=collection2
第三步:重启tomcat
Solr在JVM 运行环境中的属性信息,包括类路径、文件编码、jvm内存设置等信息。
显示Solr Server中当前活跃线程信息,同时也能够跟踪线程运行栈信息。
选择一个SolrCore进行详细操做,以下:
经过此界面能够测试索引分析器和搜索分析器的执行状况。
能够定义数据导入处理器,从关系数据库将数据导入 到Solr索引库中。
经过此菜单能够建立索引、更新索引、删除索引等操做,界面以下:
/update表示更新索引,solr默认根据id(惟一约束)域来更新Document的内容,若是根据id值搜索不到id域则会执行添加操做,若是找到则更新。
经过/select执行搜索索引,必须指定“q”查询条件方可搜索。
schema.xml,在SolrCore的conf目录下,它是Solr数据表配置文件,它定义了加入索引的数据的数据类型。主要包括FieldTypes、Fields和其余的一些缺省设置。
下边“text_general”是Solr默认提供的FieldType,经过它说明FieldType定义的内容:
FieldType子结点包括:name,class,positionIncrementGap等一些参数:
name:是这个FieldType的名称
class:是Solr提供的包solr.TextField,solr.TextField 容许用户经过分析器来定制索引和查询,分析器包括一个分词器(tokenizer)和多个过滤器(filter)
positionIncrementGap:可选属性,定义在同一个文档中此类型数据的空白间隔,避免短语匹配错误,此值至关于Lucene的短语查询设置slop值,根据经验设置为100。
例如:搜索big car,若是document中存的是big red car,就没法搜索到了, positionIncrementGap就是设置big和car中间最大的间隔距离,只要在距离内就能搜索到.
在FieldType定义的时候最重要的就是定义这个类型的数据在创建索引和进行查询的时候要使用的分析器analyzer,包括分词和过滤
索引分析器中:使用solr.StandardTokenizerFactory标准分词器,solr.StopFilterFactory停用词过滤器,solr.LowerCaseFilterFactory小写过滤器。
搜索分析器中:使用solr.StandardTokenizerFactory标准分词器,solr.StopFilterFactory停用词过滤器,这里还用到了solr.SynonymFilterFactory同义词过滤器。
solr索引字段在solrhome\collection1\conf\schema.xml配置文件中,相似下面这些,包含在<fields>与</fields>之间的。
在fields结点内定义具体的Field,filed定义包括name,type(为以前定义过的各类FieldType),indexed(是否被索引),stored(是否被储存),multiValued(是否存储多个值)等属性。
以下:
<field name="name" type="text_general" indexed="true" stored="true"/>
<field name="features" type="text_general" indexed="true" stored="true" multiValued="true"/>
multiValued:该Field若是要存储多个值时设置为true,solr容许一个Field存储多个值,好比存储一个用户的好友id(多个),商品的图片(多个,大图和小图),经过使用solr查询要看出返回给客户端是数组:
Solr中默认定义惟一主键key为id域,以下:
Solr在删除、更新索引时使用id域进行判断,也能够自定义惟一主键。
注意在建立索引时必须指定惟一约束。
copyField复制域,能够将多个Field复制到一个Field中,以便进行统一的检索:
好比,输入关键字搜索title标题内容content,
定义title、content、text的域:
根据关键字只搜索text域的内容就至关于搜索title和content,将title和content复制到text中,以下:
动态字段就是不用指定具体的名称,只要定义字段名称的规则,例如定义一个 dynamicField,name 为*_i,定义它的type为text,那么在使用这个字段的时候,任何以_i结尾的字段都被认为是符合这个定义的,例如:name_i,gender_i,school_i等。
自定义Field名为:product_title_t,“product_title_t”和scheam.xml中的dynamicField规则匹配成功,以下:
“product_title_t”是以“_t”结尾。
建立索引:
搜索索引:
使用IKAnalyzer中文分析器。
第一步:把IKAnalyzer2012FF_u1.jar添加到solr/WEB-INF/lib目录下。
第二步:复制IKAnalyzer的配置文件和自定义词典和停用词词典到solr的classpath下。
也就是在apache-tomcat-7.0.54\webapps\solr\WEB-INF目录下新建classes目录,将配置文件和词典放进去.
第三步:在schema.xml中添加一个自定义的fieldType,使用中文分析器。
<!-- IKAnalyzer--> <fieldType name="text_ik" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType> |
第四步:定义field,指定field的type属性为text_ik
<!--IKAnalyzer Field--> <field name="title_ik" type="text_ik" indexed="true" stored="true" /> <field name="content_ik" type="text_ik" indexed="true" stored="false" multiValued="true"/> |
第四步:重启tomcat
测试:
若是不使用Solr提供的Field能够针对具体的业务须要自定义一套Field,以下是商品信息Field:
<!--product-->
<field name="product_name" type="text_ik" indexed="true" stored="true"/>
<field name="product_price" type="float" indexed="true" stored="true"/>
<field name="product_description" type="text_ik" indexed="true" stored="false" />
<field name="product_picture" type="string" indexed="false" stored="true" />
<field name="product_catalog_name" type="string" indexed="true" stored="true" />
<field name="product_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>
<copyField source="product_name" dest="product_keywords"/>
<copyField source="product_description" dest="product_keywords"/>
使用dataimport插件批量导入数据。
第一步:把dataimport插件依赖的jar包添加到solrcore(collection1\lib)中
还须要mysql的数据库驱动。
第二步:配置solrconfig.xml文件,添加一个requestHandler。
<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler"> <lst name="defaults"> <str name="config">data-config.xml</str> </lst> </requestHandler>
第三步:建立一个data-config.xml,保存到collection1\conf\目录下
<?xml version="1.0" encoding="UTF-8" ?> <dataConfig> <dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/lucene" user="root" password="root"/> <document> <entity name="product" query="SELECT pid,name,catalog_name,price,description,picture FROM products "> <field column="pid" name="id"/> <field column="name" name="product_name"/> <field column="catalog_name" name="product_catalog_name"/> <field column="price" name="product_price"/> <field column="description" name="product_description"/> <field column="picture" name="product_picture"/> </entity> </document> </dataConfig>
第四步:重启tomcat
第五步:点击“execute”按钮导入数据
导入数据前会先清空索引库,而后再导入。
删除索引格式以下:
1) 删除制定ID的索引
<delete> <id>8</id> </delete>
2) 删除查询到的索引数据
<delete> <query>product_catalog_name:幽默杂货</query> </delete>
3) 删除全部索引数据
<delete> <query>*:*</query> </delete>
经过/select搜索索引,Solr制定一些参数完成不一样需求的搜索:
2. fq - (filter query)过虑查询,做用:在q查询符合结果中同时是fq查询符合的,例如::
过滤查询价格从1到20的记录。
也能够在“q”查询条件中使用product_price:[1 TO 20],以下:
也可使用“*”表示无限,例如:
20以上:product_price:[20 TO *]
20如下:product_price:[* TO 20]
3. sort - 排序,格式:sort=<field name>+<desc|asc>[,<field name>+<desc|asc>]… 。示例:
按价格降序
4. start - 分页显示使用,开始记录下标,从0开始
5. rows - 指定返回结果最多有多少条记录,配合start来实现分页。
显示前10条。
6. fl - 指定返回那些字段内容,用逗号或空格分隔多个。
显示商品图片、商品名称、商品价格
7. df-指定一个搜索Field
也能够在SolrCore目录 中conf/solrconfig.xml文件中指定默认搜索Field,指定后就能够直接在“q”查询条件中输入关键字。
8. wt - (writer type)指定输出格式,能够有 xml, json, php, phps, 后面 solr 1.3增长的,要用通知咱们,由于默认没有打开。
9. hl 是否高亮 ,设置高亮Field,设置格式前缀和后缀。
solrj是访问Solr服务的java客户端,提供索引和搜索的请求方法,SolrJ一般在嵌入在业务系统中,经过SolrJ的API接口操做Solr服务,以下图:
第一步:建立一个java工程
第二步:导入jar包。包括solrJ的jar包。还须要
第三步:使用SolrServer和Solr服务器创建链接。HttpSolrServer对象创建链接。SolrServer是抽象类,链接单机版solr使用httpSolrServer,连接集群版使用CloudSolrServer。
第四步:建立一个SolrInputDocument对象,而后添加域。
第五步:将SolrInputDocument添加到索引库。
第六步:提交。
1 //向索引库中添加索引 2 3 @Test 4 5 public void addDocument() throws Exception { 6 7 //和solr服务器建立链接 8 9 //参数:solr服务器的地址 10 11 SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr"); 12 13 //建立一个文档对象 14 15 SolrInputDocument document = new SolrInputDocument(); 16 17 //向文档中添加域 18 19 //第一个参数:域的名称,域的名称必须是在schema.xml中定义的 20 21 //第二个参数:域的值 22 23 document.addField("id", "c0001"); 24 25 document.addField("title_ik", "使用solrJ添加的文档"); 26 27 document.addField("content_ik", "文档的内容"); 28 29 document.addField("product_name", "商品名称"); 30 31 //把document对象添加到索引库中 32 33 solrServer.add(document); 34 35 //提交修改 36 37 solrServer.commit(); 38 39 40 41 }
@Test public void testIndexCreate() throws Exception{ //建立和Solr服务端链接 SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr"); //建立solr文档对象 SolrInputDocument doc = new SolrInputDocument(); //域要先定义后使用,还有注意必需要有id主键域 //solr中没有专用的修改方法, 会自动根据id进行查找,若是找到了则删除原来的将新的加入就是修改,若是没找到,将新的直接加入则就是新增 doc.addField("id", "a001"); doc.addField("product_name", "台灯1`111"); doc.addField("product_price", "12.5"); //将文档加入solrServer对象中 solrServer.add(doc); //提交 solrServer.commit(); }
1 //删除文档,根据id删除 2 3 @Test 4 5 public void deleteDocumentByid() throws Exception { 6 7 //建立链接 8 9 SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr"); 10 11 //根据id删除文档 12 13 solrServer.deleteById("c0001"); 14 15 //提交修改 16 17 solrServer.commit(); 18 19 }
查询语法彻底支持Lucene的查询语法。
1 //根据查询条件删除文档 2 3 @Test 4 5 public void deleteDocumentByQuery() throws Exception { 6 7 //建立链接 8 9 SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr"); 10 11 //根据查询条件删除文档,这里是删除全部*:* 12 13 solrServer.deleteByQuery("*:*"); 14 15 //提交修改 16 17 solrServer.commit(); 18 19 }
在solrJ中修改没有对应的update方法,只有add方法,只须要添加一条新的文档,和被修改的文档id一致就,能够修改了。本质上就是先删除后添加。
1 //查询索引 2 3 @Test 4 5 public void queryIndex() throws Exception { 6 7 //建立链接,连接solr服务端 8 9 SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr"); 10 11 //建立一个query对象,solr查询条件对象 12 13 SolrQuery query = new SolrQuery(); 14 15 //设置查询条件 16 17 query.setQuery("*:*"); 18 19 //查询,执行查询并获取查询响应对象 20 21 QueryResponse queryResponse = solrServer.query(query); 22 23 //取查询结果,从查询响应中获取查询结果集对象 24 25 SolrDocumentList solrDocumentList = queryResponse.getResults(); 26 27 //共查询到商品数量 28 29 System.out.println("共查询到商品数量:" + solrDocumentList.getNumFound()); 30 31 //遍历查询的结果 32 33 for (SolrDocument solrDocument : solrDocumentList) { 34 35 System.out.println(solrDocument.get("id")); 36 37 System.out.println(solrDocument.get("product_name")); 38 39 System.out.println(solrDocument.get("product_price")); 40 41 System.out.println(solrDocument.get("product_catalog_name")); 42 43 System.out.println(solrDocument.get("product_picture")); 44 45 46 47 } 48 49 }
其中包含查询、过滤、分页、排序、高亮显示等处理。
例子1:
//复杂查询索引 @Test public void queryIndex2() throws Exception { //建立链接 SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr"); //建立一个query对象 SolrQuery query = new SolrQuery(); //设置查询条件 query.setQuery("钻石"); //过滤条件 query.setFilterQueries("product_catalog_name:幽默杂货"); //排序条件 query.setSort("product_price", ORDER.asc); //分页处理 query.setStart(0); query.setRows(10); //结果中域的列表 query.setFields("id","product_name","product_price","product_catalog_name","product_picture"); //设置默认搜索域 query.set("df", "product_keywords"); //高亮显示 query.setHighlight(true); //高亮显示的域 query.addHighlightField("product_name"); //高亮显示的前缀 query.setHighlightSimplePre("<em>"); //高亮显示的后缀 query.setHighlightSimplePost("</em>"); //执行查询 QueryResponse queryResponse = solrServer.query(query); //取查询结果 SolrDocumentList solrDocumentList = queryResponse.getResults(); //共查询到商品数量 System.out.println("共查询到商品数量:" + solrDocumentList.getNumFound()); //遍历查询的结果 for (SolrDocument solrDocument : solrDocumentList) { System.out.println(solrDocument.get("id")); //取高亮显示 String productName = ""; Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting(); List<String> list = highlighting.get(solrDocument.get("id")).get("product_name"); //判断是否有高亮内容 if (null != list) { productName = list.get(0); } else { productName = (String) solrDocument.get("product_name"); } System.out.println(productName); System.out.println(solrDocument.get("product_price")); System.out.println(solrDocument.get("product_catalog_name")); System.out.println(solrDocument.get("product_picture")); } }
例子2
@Test public void testIndexSearch2() throws Exception{ //链接solr服务端 SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr"); //建立solr查询条件对象 SolrQuery solrQuery = new SolrQuery(); //查询关键字输入 solrQuery.setQuery("台灯"); //设置默认搜索域 solrQuery.set("df", "product_keywords"); //设置过滤查询 solrQuery.addFilterQuery("product_price:[1 TO 100]"); //设置排序,这里是降序 solrQuery.setSort("product_price", ORDER.desc); //=======设置分页======== //设置起始条数 solrQuery.setStart(0); //设置查询多少条 solrQuery.setRows(50); //========设置高亮显示======= //高亮默认是关闭的,因此要手动开启 solrQuery.setHighlight(true); //设置须要高亮显示的域 solrQuery.addHighlightField("product_name"); //设置高亮前缀 solrQuery.setHighlightSimplePre("<span style=\"color:red\">"); //设置高亮后缀 solrQuery.setHighlightSimplePost("</span>"); //===================查询并获取查询响应对象===================================== QueryResponse queryResponse = solrServer.query(solrQuery); //从查询响应中获取查询结果集对象 SolrDocumentList results = queryResponse.getResults(); //打印一共查询到多少条记录,也就是记录总数 System.out.println("=====count====" + results.getNumFound()); //遍历查询结果集 for(SolrDocument doc : results){ System.out.println("============="+doc.get("id")); //获取高亮 Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting(); List<String> list = highlighting.get(doc.get("id")).get("product_name"); if(list != null && list.size() > 0){ String hlName = list.get(0); System.out.println("=======high lighting=====" + hlName); } System.out.println("============="+doc.get("product_name")); System.out.println("============="+doc.get("product_price")); System.out.println("===================================================="); } }
建立一个web工程导入jar包
一、springmvc的相关jar包
二、solrJ的jar包
三、Example\lib\ext下的jar包
<?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: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://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="com.itheima.jd"/> <!-- 配置注解驱动,若是配置此标签能够不用配置处理器映射器和适配器 --> <mvc:annotation-driven/> <!-- 配置视图解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"/> <property name="suffix" value=".jsp"/> </bean> <!-- SolrServer的配置 --> <bean id="httpSolrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer"> <constructor-arg index="0" value="http://localhost:8080/solr"/> </bean> </beans>
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>solr-jd</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <!-- 配置前段控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <!-- 指定springmvc配置文件的路径 若是不指定默认为:/WEB-INF/${servlet-name}-servlet.xml --> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </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> </web-app>
功能:接收service层传递过来的参数,根据参数查询索引库,返回查询结果。
参数:SolrQuery对象
返回值:一个商品列表List<ProductModel>,还须要返回查询结果的总数量。
返回:ResultModel
方法定义:ResultModel queryProduct(SolrQuery query) throws Exception;
商品对象模型:
public class ProductModel { // 商品编号 private String pid; // 商品名称 private String name; // 商品分类名称 private String catalog_name; // 价格 private float price; // 商品描述 private String description; // 图片名称 private String picture; }
返回值对象模型
public class ResultModel { // 商品列表 private List<ProductModel> productList; // 商品总数 private Long recordCount; // 总页数 private int pageCount; // 当前页 private int curPage; }
dao
@Repository public class ProductDaoImpl implements ProductDao { @Autowired private SolrServer solrServer; @Override public ResultModel queryProduct(SolrQuery query) throws Exception { ResultModel resultModel = new ResultModel(); //根据query对象查询商品列表 QueryResponse queryResponse = solrServer.query(query); SolrDocumentList solrDocumentList = queryResponse.getResults(); //取查询结果的总数量 resultModel.setRecordCount(solrDocumentList.getNumFound()); List<ProductModel> productList = new ArrayList<>(); //遍历查询结果 for (SolrDocument solrDocument : solrDocumentList) { //取商品信息 ProductModel productModel = new ProductModel(); productModel.setPid((String) solrDocument.get("id")); //取高亮显示 String productName = ""; Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting(); List<String> list = highlighting.get(solrDocument.get("id")).get("product_name"); if (null != list) { productName = list.get(0); } else { productName = (String) solrDocument.get("product_name"); } productModel.setName(productName); if(null == doc.get("product_price")){ productModel.setPrice(0f); }else{ productModel.setPrice((float)doc.get("product_price")); } productModel.setCatalog_name((String) solrDocument.get("product_catalog_name")); productModel.setPicture((String) solrDocument.get("product_picture")); //添加到商品列表 productList.add(productModel); } //商品列表添加到resultmodel中 resultModel.setProductList(productList); return resultModel; } }
功能:接收action传递过来的参数,根据参数拼装一个查询条件,调用dao层方法,查询商品列表。接收返回的商品列表和商品的总数量,根据每页显示的商品数量计算总页数。
参数:
一、查询条件:字符串
二、商品分类的过滤条件:商品的分类名称,字符串
三、商品价格区间:传递一个字符串,知足格式:“0-100、101-200、201-*”
四、排序条件:页面传递过来一个升序或者降序就能够,默认是价格排序。0:升序1:降序
五、分页信息:每页显示的记录条数建立一个常量60条。传递一个当前页码就能够了。
业务逻辑
一、根据参数建立查询对象
二、调用dao执行查询。
三、根据总记录数计算总页数。
返回值:ResultModel
方法定义:ResultModel queryProduct(String queryString, String caltalog_name, String price, String sort, Integer page) throws Exception;
@Service public class ProductServiceImpl implements ProductService { @Autowired private ProductDao productDao; @Override public ResultModel queryProduct(String queryString, String caltalog_name, String price, String sort, Integer page) throws Exception { //拼装查询条件 SolrQuery query = new SolrQuery(); //查询条件 if (null != queryString && !"".equals(queryString)) { query.setQuery(queryString); } else { query.setQuery("*:*"); } //商品分类名称过滤 if (null != caltalog_name && !"".equals(caltalog_name)) { query.addFilterQuery("product_catalog_name:" + caltalog_name); } //价格区间过滤 if (null != price && !"".equals(price)) { String[] strings = price.split("-"); query.addFilterQuery("product_price:["+strings[0]+" TO "+strings[1]+"]"); } //排序条件 if ("1".equals(sort)) { query.setSort("product_price", ORDER.desc); } else { query.setSort("product_price", ORDER.asc); } //分页处理 if (null == page) { page = 1; } //start int start = (page-1) * Commons.PAGE_SIZE; query.setStart(start); query.setRows(Commons.PAGE_SIZE); //设置默认搜索域 query.set("df", "product_keywords"); //高亮设置 query.setHighlight(true); query.addHighlightField("product_name"); query.setHighlightSimplePre("<span style=\"color:red\">"); query.setHighlightSimplePost("</span>"); //查询商品列表 ResultModel resultModel = productDao.queryProduct(query); //计算总页数 long recordCount = resultModel.getRecordCount(); int pages = (int) (recordCount/Commons.PAGE_SIZE); if (recordCount % Commons.PAGE_SIZE > 0) { pages ++; } resultModel.setPageCount(pages); resultModel.setCurPage(page); return resultModel; } }
功能:接收页面传递过来的参数调用service查询商品列表。将查询结果返回给jsp页面,还须要查询参数的回显。
参数:
一、查询条件:字符串
二、商品分类的过滤条件:商品的分类名称,字符串
三、商品价格区间:传递一个字符串,知足格式:“0-100、101-200、201-*”
四、排序条件:页面传递过来一个升序或者降序就能够,默认是价格排序。0:升序1:降序
五、分页信息:每页显示的记录条数建立一个常量60条。传递一个当前页码就能够了。
六、Model:至关于request。
返回结果:String类型,就是一个jsp的名称。
方法定义:String queryProduct(String queryString, String caltalog_name, String price, String sort, Integer page, Model model) throws Exception;
@Controller public class ProductAction { @Autowired private ProductService productService; @RequestMapping("/list") public String queryProduct(String queryString, String catalog_name, String price, String sort, Integer page, Model model) throws Exception { //查询商品列表 ResultModel resultModel = productService.queryProduct(queryString, catalog_name, price, sort, page); //列表传递给jsp model.addAttribute("result", resultModel); //参数回显 model.addAttribute("queryString", queryString); model.addAttribute("caltalog_name", catalog_name); model.addAttribute("price", price); model.addAttribute("sort", sort); model.addAttribute("page", page); return "product_list"; } }