solr介绍
Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务。Solr可以独立运行在Jetty、Tomcat等这些Servlet容器中。
Solr提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展,并对索引、搜索性能进行了优化。
lucene和solr区别
Lucene是一个开放源代码的全文检索引擎工具包,它不是一个完整的全文检索应用。Lucene仅提供了完整的查询引擎和索引引擎,目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者以Lucene为基础构建全文检索应用。
Solr的目标是打造一款企业级的搜索引擎系统,它是基于Lucene一个搜索引擎服务,可以独立运行,通过Solr可以非常快速的构建企业的搜索引擎,通过Solr也可以高效的完成站内搜索功能。
lucene:直接调用api查询
solr:
1. solr是一个web服务
2. solr部署tomcat服务器
3. 通过语句维护
solr安装与运行
1)加载start.jar启动包
2)加载jetty服务器启动容器(类似于tomcat容器)
3)加载webapps下面solr服务程序(solr.war)
4)加载solr服务器程序索引仓库
访问:http://localhost:8983/solr/
solr运行在tomcat中
solr部署步骤:
1. 把solr.war拷贝tomcat服务器 tomcat/webapps
2. 解压solr.war,直接运行tomcat,自动解压
3. 拷贝solr依赖jar文件
- solr内置日志文件:solr解压包/example/lib/ext/* -> tomcat/webapps/solr/WEB-INF/lib/
- contrib,dist依赖类库:solr解压包/ -> 自定义solr仓库/ ====修改solrConfig.xml加载依赖类库
4. 创建自定义仓库
* solr是一个web项目,部署tomcat服务器中运行web项目
* solr用来做搜索,搜索索引库,需要索引仓库
* 在F/:solr定义索引仓库
5. 指定solr服务索引仓库位置
* 配置tomcat/bin/catalina.bat
* set JAVA_OPTS = “-Dsolr.solr.home=F:/solr”
管理界面功能介绍
- Dashboard
仪表盘,显示了该Solr实例开始启动运行的时间、版本、系统资源、jvm等信息。 - Logging
Solr运行日志信息 - Cloud
Cloud即SolrCloud,即Solr云(集群),当使用Solr Cloud模式运行时会显示此菜单,该部分功能在第二个项目,即电商项目会演示。 - Core Admin
Solr Core的管理界面。在这里可以添加SolrCore实例(有bug,不推荐使用浏览器界面添加SolrCore)。 - java properties
Solr在JVM 运行环境中的属性信息,包括类路径、文件编码、jvm内存设置等信息。 - Tread Dump
显示Solr Server中当前活跃线程信息,同时也可以跟踪线程运行栈信息。 Core selector
选择一个SolrCore进行详细操作,如下:7.1 Analysis
通过此界面可以测试索引分析器和搜索分析器的执行情况7.2 dataimport
可以定义数据导入处理器,从关系数据库将数据导入到Solr索引库中。
默认没有配置,需要手工配置。- 7.3 Document
通过/update表示更新索引,solr默认根据id(唯一约束)域来更新Document的内容,如果根据id值搜索不到id域则会执行添加操作,如果找到则更新。
通过此菜单可以创建索引、更新索引、删除索引等操作,
- overwrite=”true” : solr在做索引的时候,如果文档已经存在,就用xml中的文档进行替换
commitWithin=”1000” : solr 在做索引的时候,每隔1000(1秒)毫秒,做一次文档提交。为了方便测试也可以在Document中立即提交,后添加“”
- 7.4 Query
通过/select执行搜索索引,必须指定“q”查询条件方可搜索。
- 7.4 Query
solr home的目录结构
solr home顾名思义,就是solr的家,即solr的存放数据的仓库(索引库)。每个solr home下可以有多个solr core,这个就是用来存放索引的地方。
solr home ——–> 对应 数据库
solr core ——–> 对应 数据库下的表
solr core
core.properties,用来指定solr core(索引库)的名称
conf配置文件
schema.xml,域(类似数据库字段),域类型(字段类型),动态域(类似数据库字段),复制域(类似数据库字段)
- field节点
作用:配置索引的字段,该节点具有以下常用属性:
- name:代表数据字段名称
- type:代表数据类型
- indexed:true or false,代表是否被创建索引
- stored:true or false,代表是否被存储
- multivalued:是否是多值,存储多个值时设置为true,比如存储一个用户的好友id(多个),商品的图片(多个,大图和小图)。
- dynamicField
作用:动态的检索字段。 - uniqueKey
作用:相当于数据库主键 - copyField
作用:将多个字段的值复制到同一个目标字段中。检索时可以根据指定的dest的字段检索。
- source:源字段
- dest:目标字段
- fieldType
作用:指定索引字段的类型。具有如下常见属性:
- name:索引字段的类型名,并filed节点中的name引用
- class:代表solr的类型
- analyzer:指定分词器,type=index/query,index:创建索引;
- query:查询索引
- tokenizer:指定分词器
- filter:指定过滤器
- field节点
solrconfig.xml核心配置文件,solr服务一一对应,solr服务请求执行,对应solrConfig配置文件当中执行类
作用:定义了solr服务的一些处理规则,包括索引数据的存放位置;更新、删除、查询的一些规则配置。常用的节点有:- luceneMatchVersion:指定底层使用的Lucene版本号
- lib:指定solr服务运行需要的jar
- dataDir:指定索引的存放位置
- requestHandler:配置solr CRUD的规则
自定义索引库
- copy solr的模板collection1
- 修改索引库名称
- 修改solrConfig
- 修改schema.xml文件
使用IK分词器 ###
安装分词器:
1. 导入jar包
* 把IK分词器jar文件放入tomcat/webapps/solr/WEB-INF/lib
2. 导入IK分词器配置文件
* 把IK分词器配置文件IKAnalyzer.cfg.xml,ext.dic.stopword.dic拷贝 tomcat/webapps/solr/WEB-INF/classes(自己创建)
域类型–使用IK分词器
在conf的schema.xml中配置域类型
<!-- IKAnalyzer--> <fieldType name="text_ik" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
域使用IK分词器
域使用IK分词器
<!--IKAnalyzer Field--> <field name="content_ik" type="text_ik" indexed="true" stored="true" />
在索引库必须存在和数据库字段相对应域,然后把数据库字段所对应值添加,域名称和字段名称没必要相同.
加载jar包
solrj对索引库的维护
solrj是通过Java客户端去操作solr,它提供了一个Java接口用于添加、更新和查询solr的索引.
- 创建工程
- 准备环境
- 索引的维护
添加索引
/**
* 连接远程solr服务,添加/修改索引库索引
* @throws Exception
* @throws SolrServerException
*/
@Test
public void addIndexSolr() throws Exception{
//指定远程solr服务地址
String solrUrl = "http://localhost:8080/solr/article";
//创建solrj核心对象
SolrServer solrServer = new HttpSolrServer(solrUrl);
//创建文档对象
SolrInputDocument document = new SolrInputDocument();
//向索引库引域添加索引值,此索引域必须在索引库中存在
document.addField("id", "p101");
document.addField("title", "solr经典教程,适合初学者");
document.addField("content", "solr功能很强大!");
//添加索引库
solrServer.add(document);
//提交
solrServer.commit();
}
更新索引
如果id相同,则执行更新操作。
删除索引
- 根据id删除
- 先查在删
/**
* 删除索引库
* @throws Exception
* @throws
*/
@Test
public void deleteIndexSolr() throws Exception{
//指定远程solr服务器地址
String solrUrl = "http://localhost:8080/solr/article";
//连接远程服务器
SolrServer solrServer = new HttpSolrServer(solrUrl);
//第一种删除方式:根据id进行删除
// solrServer.deleteById("p101");
//第二种删除方式:根据查询删除索引库索引
solrServer.deleteByQuery("id:p101");
//提交
solrServer.commit();
}
查询索引
- q:query(主查询条件)
- fq:filter query 过滤查询,必须在q主查询条件有值时才能进行过滤
- sort排序 语法: 排序字段 desc / asc
- filter field 过滤字段 select name,price from products
solr:过滤域字段 字段之间是有空格或者,都可. - default 设置默认查询字段,一般默认查询字段设置复制域
- hl.fl 设置高亮 hl.simple.fl 设置高亮前缀
/**
* 使用solr复杂查询
* @throws Exception
*/
@Test
public void queryIndexBySolr() throws Exception{
//指定远程solr服务地址
String url = "http://127.0.0.1:8080/solr/products";
//创建solr服务对象,连接远程solr服务对象
SolrServer solrServer = new HttpSolrServer(url);
//solr提供参数封装类,封装查询语法,封装参数
SolrQuery solrQuery = new SolrQuery();
//查询所有
// solrQuery.set("q", "*:*");
//a.q主条件查询
solrQuery.setQuery("婚庆");
//b.fq过滤查询,必须在q主查询条件有值时候才能进行过滤
solrQuery.addFilterQuery("product_price:[20 TO *]");
//使用solr服务查询
QueryResponse response = solrServer.query(solrQuery);
//c.sort排序查询
//参数1:设置需要查询字段名称
//参数2:设置排序方式 desc asc
solrQuery.setSort("product_price", ORDER.desc);
//d.设置分页
solrQuery.setStart(0);
solrQuery.setRows(10);
//e.fl:字段过滤查询,查询需要字段即可,域字段之间使用空格或者逗号分割
// solrQuery.setFields("product_price,product_name");
// solrQuery.addField("product_price,product_name");
//f.高亮显示
//开启高亮显示
solrQuery.setHighlight(true);
//指定高亮显示字段,高亮显示字段不能是复制域,只能是单个域
solrQuery.addHighlightField("product_name");
//设置高亮前缀
solrQuery.setHighlightSimplePre("<font color='red'>");
//设置高亮后缀
solrQuery.setHighlightSimplePost("</font>");
//获取查询列表集合对象
SolrDocumentList solrDocumentList = response.getResults();
//获取命中总记录数
long numFound = solrDocumentList.getNumFound();
System.out.println(numFound);
//获取文档数据
for (SolrDocument solrDocument : solrDocumentList) {
//获取文档数据
String id = (String) solrDocument.get("id");
System.out.println("商品id:"+id);
String product_name = (String) solrDocument.get("product_name");
//获取高亮
Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
//第一个map的key就是高亮文档的id
Map<String, List<String>> map = highlighting.get(id);
//第二个map的key就是高亮字段域名称
List<String> list = map.get("product_name");
//判断高亮是否存在
if (list != null && list.size() > 0) {
product_name = list.get(0);
}
System.out.println("商品名称:"+product_name);
Float product_price = (Float) solrDocument.get("product_price");
System.out.println("商品价格:"+product_price);
String product_description = (String) solrDocument.get("product_description");
System.out.println("商品扫描:"+product_description);
String product_picture = (String) solrDocument.get("product_picture");
System.out.println("商品图片:"+product_picture);
String product_catalog_name = (String) solrDocument.get("product_catalog_name");
System.out.println("商品种类名称:"+product_catalog_name);
String product_keywords = (String) solrDocument.get("product_keywords");
System.out.println("商品关键字:"+product_keywords);
}
}
案例
环境搭建:
1. jar
* 加载springmvc配置文件:spring
* 查询远程solr索引库
2. 配置文件
* psringmvc
* solrJ交给spring管理
3. JD案例页面
4. web.xml
* 编码过滤器
* 配置springmvc.xml
5. 将数据库数据导入索引库
5.1 添加DataImportjar包
复制dist目录中的solr-dataimporthandler-4.10.3.jar
没有lib目录,需要手动创建(可以不放lib文件夹中,后面的配置文件路径匹配即可)
5.2 添加数据库驱动包
5.3 修改配置文件,加载jar包,
5.4 配置requestHandler
在solrconfig.xml配置文件中添加:
<requestHandler name="/dataimport"
class="org.apache.solr.handler.dataimport.DataImportHandler">
<lst name="defaults">
<str name="config">data-config.xml</str>
</lst>
</requestHandler>
5.5 创建data-config.xml配置文件
在collection1\conf\目录下创建data-config.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<dataConfig>
<dataSource type="JdbcDataSource"
driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/solr"
user="root"
password="root"/>
<document>
<entity name="product" query="SELECT pid,name,catalog,catalog_name,price,description,picture FROM products">
<field column="pid" name="id"/>
<field column="name" name="product_name"/>
<field column="catalog" name="product_catalog"/>
<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>
5.6 点击“execute”按钮导入数据
注意:导入数据前会先清空索引库,然后再导入。
创建POJO
//商品
public class Product {
private String pid;
private String name;
private String price;
private String picture;
get/set...
}
//分页
public class Result {
private Integer curPage;// 当前页
private Integer pageCount;// 总页数
private Long recordCount;// 数据总条数
private List<Product> productList;// 商品结果集
get/set...
}
Controller
@Controller
public class ProductController {
//注入service
@Resource
private ProductService productService;
/**
* 跳转商品搜索列表页面
*/
@RequestMapping("list")
public String returnPage (String qName, String catelog_name, String price, String sort,@RequestParam(defaultValue="1") Integer page,Model model){
//调用service
PageBean pageBean = productService.queryProductIndex(qName, catelog_name, price, sort, page);
//查询参数回显
model.addAttribute("qName", qName);
model.addAttribute("catelog_name", catelog_name);
model.addAttribute("price", price);
model.addAttribute("sort", sort);
model.addAttribute("page", page);
//设置分页
model.addAttribute("result", pageBean);
return "product_list";
}
}
Service
@Service("productService")
public class ProductServiceImpl implements ProductService {
//注入dao
@Resource
private ProductDao productDao;
@Override
public PageBean queryProductIndex(String qName, String catelog_name, String price, String sort, Integer page) {
//创建solr服务提供solrQuery封装参数对象
SolrQuery solrQuery = new SolrQuery();
//判断参数是否为空
if (qName != null && !qName.equals("")) {
solrQuery.setQuery(qName);
} else {
solrQuery.setQuery("*:*");
}
//设置过滤查询
if (catelog_name != null && !catelog_name.equals("")) {
solrQuery.setFilterQueries("product_catalog_name:"+catelog_name);
}
//过滤价格
if (price != null && !price.equals("")) {
//切分价格区间0-9
String[] prices = price.split("-");
//设置过滤查询
solrQuery.addFilterQuery("product_price:["+prices[0]+"TO"+prices[1]+"]");
}
//排序
if (sort!=null && sort.equals("1")) {
solrQuery.setSort("product_price",ORDER.desc);
} else {
solrQuery.setSort("product_price",ORDER.asc);
}
//设置分页
int startNo = (page-1)*60;
solrQuery.setStart(startNo);
solrQuery.setRows(60);
//设置高亮
//开启高亮显示
solrQuery.setHighlight(true);
//指定高亮显示字段,高亮显示字段不能是复制域,只能是单个域
solrQuery.addHighlightField("product_name");
//设置高亮前缀
solrQuery.setHighlightSimplePre("<font color='red'>");
//设置高亮后缀
solrQuery.setHighlightSimplePost("</font>");
//设置默认查询字段
solrQuery.set("df","product_keywords");
//调用dao查询索引库
PageBean pageBean = productDao.queryProductsIndex(solrQuery);
//获取总记录数
Integer recordCount = pageBean.getRecordCount();
//计算总页码
int pages = recordCount/60;
if (recordCount%60>0) {
pages++;
}
//设置当前页
pageBean.setCurPage(page);
//设置总页码
pageBean.setPageCount(pages);
return pageBean;
}
}
Dao
@Repository("productDao")
public class ProductDaoImpl implements ProductDao{
//注入solr远程对象服务
@Resource
private SolrServer solrServer;
@Override
public PageBean queryProductsIndex(SolrQuery solrQuery) {
//创建pageBean,用于封装分页信息
PageBean pageBean = new PageBean();
try {
//调用远程solr服务,使用solrQuery封装参数对象,直接查询远程索引库
QueryResponse response = solrServer.query(solrQuery);
//获取命中总记录数
SolrDocumentList solrDocumentList = response.getResults();
Long numFound = solrDocumentList.getNumFound();
//把总记录数封装到pagebean中
pageBean.setRecordCount(numFound.intValue());
//创建list集合,封装商品数据
List<Products> pList = new ArrayList<Products>();
//循环获取文档数据集合
for (SolrDocument solrDocument : solrDocumentList) {
//创建商品对象,封装从索引库中查询出文档商品数据
Products product = new Products();
//获取文档数据
String id = (String) solrDocument.get("id");
product.setPid(id);
String product_name = (String) solrDocument.get("product_name");
//获取高亮
Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
//第一个map的key就是高亮文档的id
Map<String, List<String>> map = highlighting.get(id);
//第二个map的key就是高亮字段域名称
List<String> list = map.get("product_name");
//判断高亮是否存在
if (list != null && list.size() > 0) {
product_name = list.get(0);
}
product.setName(product_name);
Float product_price = (Float) solrDocument.get("product_price");
product.setPrice(product_price);
String product_picture = (String) solrDocument.get("product_picture");
product.setPicture(product_picture);
//将商品添加到集合中
pList.add(product);
}
//将商品集合封装到pagebean中
pageBean.setProductList(pList);
} catch (SolrServerException e) {
e.printStackTrace();
}
return pageBean;
}
}