什么是
solr
Solr
是
Apache
下的一个顶级开源项目,采用
Java
开发,它是基于
Lucene
的
全文搜索服务
。
Solr
可以独立运行在
Jetty
、
Tomcat
等这些
Servlet
容器中。
使用
Solr
进行创建索引和搜索索引的实现方法很简单,如下:
创建索引:客户端(可以是浏览器可以是
Java
程序)用
POST
方法向
Solr
服务器发送一个描述
Field
及其内容的
XML
文档,
Solr
服务器根据
xml
文档添加、删除、更新索引 。
搜索索引:客户端(可以是浏览器可以是
Java
程序)用
GET
方法向
Solr
服务器发送请求,然后对
Solr
服务器返回
Xml
、
json
等格式的查询结果进行解析。
Solr
不提供构建页面
UI
的功能。
Solr
提供了一个管理界面,通过管理界面可以查询
Solr
的配置和运行情况。
Solr
是一个可以独立运行的搜索服务器,使用
solr
进行全文检索服务的话,只需要通过
http
请求访问该服务器即可。
S
olr
和
Lucene
的区别
Lucene
是一个开放源代码的全文检索
引擎工具包
,它不是一个完整的全文检索应用。
Lucene
仅提供了完整的查询引擎和索引引擎,目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者以
Lucene
为基础构建全文检索应用。
Solr
的目标是打造一款企业级的搜索引擎系统,它是基于
Lucene
一个
搜索引擎服务
,可以独立运行,通过
Solr
可以非常快速的构建企业的搜索引擎,通过
Solr
也可以高效的完成站内搜索功能。
1. 什么是solr:
solr是apache公司出品的一个全文检索引擎系统.
solr和lucene区别:
lucene是一个工具包, 放入tomcat不能独立运行,
solr是一个全文检索系统,放入tomcat下可以独立运行,solr底层使用luecene来开发实现的.
2. solr作用:
我们可以不用写大量的对索引和文档的增删改查的代码, 将solr部署到tomcat后就可以独立运行,
solr对外通过htttp的形式提供索引和文档的增删改查服务.
solr部署:
a) 将solr的war包放入tomcat的webapps目录下.
b) 运行tomcat目的是解压war包, 等解压后,关掉黑窗口,然后将webapps下的war删除
c) 将solr/example下的solr目录整个拷贝到硬盘根目录,因为这个是solrHome
要求路径中不能有中文和空格
d) 将solrHome的路径复制到tomcat下webapps/solr/WEB-INF/web.xml中进行配置
e) 将solr/example/lib/ext下的所有log的jar包拷贝到tomcat下solr项目中的lib包中
f)
添加log4j
.properties
把
solr
解压包下
solr-4.10.3\example\resources\log4j.properties
文件进行复制
粘贴到
Tomcat
的
webapps
的
solr
的
WEB-INF
\classes
目录下这里没有
classes
文 件夹创建一个即可
g) 重新运行tomcat
solrHome:就是solr的家, 一个solr服务器只能有一个solrHome, solrHome中包含多个solrCore,
一个solrCore就是一个solr实例, 一个实例可以对外单独提供索引和文档的增删改查服务, 实例
和实例之间是互相隔离的.
注意: solr中域要先定义后使用,如果没有定义就使用会报错.
ERROR: [doc=002] unknown field 'xxxxxx'
solr每次增加的时候必须有id域, id为主键域没有会报错
Document is missing mandatory uniqueKey field: id"
solr中没有专门的修改方法, 首先根据id去索引库和文档库中去查找, 如果找到了就删除原来的,
将新的添加进去, 如果没有找到, 就直接将新的添加进去
利用浏览器访问界面删除索引和文档:
根据id删除
<delete>
<id>004</id>
</delete>
<commit/>
删除所有
<delete>
<query>*:*</query>
</delete>
<commit/>
solr
基本使用
1.
schema.xml
schema.xml
文件在
SolrCore
的
conf
目录下,在此配置文件中定义了域以及域的类型等一些配置。在
solr
中域必须先定义后使用。
1.1. field
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
Name
:域的名称
Type
:域的类型
Indexed
:是否索引
Stored
:是否存储
Required
:是否必须
multiValued
:是否是多值,存储多个值时设置为
true
,
solr
允许一个
Field
存储多个值,比如存储一个用户的好友
id
(多个),商品的图片(多个,大图和小图)
1.2. dynamicField
(动态域)
<dynamicField name="*_s" type="string" indexed="true" stored="true" />
Name
:动态域的名称,是一个表达式,
*
匹配任意字符,只要域的名称和表达式的规则能够匹配就可以使用。
例如:搜索时查询条件
[
product_i
:钻石
]
就可以匹配这个动态域,可以直接使用,不用单独再定义一个
product_i
域。
1.3.
uniqueKey
<uniqueKey>id</uniqueKey>
相当于主键,每个文档中必须有一个
id
域。
1.4. copyField
(复制域)
<copyField source="cat" dest="text"/>
可以将多个
Field
复制到一个
Field
中,以便进行统一的检索。当创建索引时,
solr
服务器会自动的将源域的内容复制到目标域中。
l source
:源域
l
dest
:目标域,搜索时,指定目标域为默认搜索域,可以提高查询效率。
下面例子:在ters_solr(里面包含test_name和tset_desc)中查询test_name和tset_desc描述的时候可以使用复制域配置如下
1.5.
fieldType
(域类型)
name
:域类型的名称
class
:指定域类型的
solr
类型。
analyzer
:指定分词器。在
FieldType
定义的时候最重要的就是定义这个类型的数据在建立索引和进行查询的时候要使用的分析器
analyzer
,包括分词和过滤。
type
:
index
和
query
。
I
ndex
是创建索引,
query
是查询索引。
tokenizer
:指定分词器
filter
:指定过滤器
主要是配置分词器
2.
配置中文分析器
第一步导包 把中文分词器的jar包 导入\tomcat\tomcat1\webapps\solr\WEB-INF\lib
第二步在WEB-INF下创建classes(服务器会自己找到)文件夹,将扩展词和停用词还有配置文件放到里面
第三步 在solr\collection1\conf\schema.xml 中配置下面的代码
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
3.
solrj
的复杂查询
3.1.
solr
的查询语法
1. q
:
查询关键字,必须的。
请求的
q
是字符串,如果查询所有使用
*:*
2. fq: (filter query)
过滤查询
作用:在
q
查询符合结果中同时是
fq
查询符合的
请求
fq
是一个数组(多个值)
过滤查询价格从
1
到
20
的记录。
也可以使用
“
*
”表示无限,例如:
20
以上:
product_price:[20 TO *]
20
以下:
product_price:[
*
TO
20
]
也可以在
“
q
”查询条件中使用
product_price:[1 TO
20]
,
如下效果和上面一样:
3. sort:
排序,
desc
代表降序,
asc
代表升序
按照价格升序排
4. start:
分页显示使用,开始记录下标,从
0
开始
rows:
指定返回结果最多有多少条记录,配合
start
来实现分页。
5. fl: (Field List)
指定返回那些字段内容,用逗号或空格分隔多个。
显示商品
id
、商品名称、商品分类名称
6. df:
指定默认搜索
Field
7. wt: (writer type)
指定输出格式,可以有
xml, json, php, phps
8. hl:
是否高亮
,
设置高亮
Field
,设置格式前缀和后缀。
单元测试solrj使用
//复杂查询索引 @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")); } } |
配置solr(使用配置文件注入solr)
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" 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 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <bean id="solrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer"> <constructor-arg value="http://192.168.200.128:8079/solr"/> </bean> </beans> |
Dao
商品对象模型:
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;
}
@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); productModel.setPrice((float) solrDocument.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; } } |
Service
@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; } } |
controller
@Controller public class ProductController { @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"; } } |