如果你的项目中用到了搜索,现在的选择就奔上就是Solr或者Elasticsearch了,今天我们就来看看Solr,当然我一般是不会在博客中讲什么原理的,因为讲原理是我自己的理解,我怕误导大家,好了开始吧
一、简介
- 为什么要使用搜索呢?
- 我们知道,一个大型网站,用户的搜索是一个及其消耗服务器性能的事情,如果在这点上处理不好,将会使得用户体验度大打折扣,甚至拖垮整个应用!
- Solr
- 讲到Solr其实肯定就会提到Lucene,两者的区别在于Lucene是一个底层的API实现,而Solr是在应用的层面上封装了Lucene。
- Solr是Apache旗下的一款快速的,高度可扩展,可提供高性能,以文本为中心的开源搜索服务器。它基于HTTP请求访问,也就是说跨平台性得到了保障;主要用于构建搜索应用程序。Yonik Seely于2004年创建,并于2006年1月成为Apache软件基金会下的一个开源项目;
- Solr的另一大可以说是特性就是可以和Hadoop一起使用,也就是说不仅限于搜索,Solr也可以用于数据的存储和数据处理,是一种非关系数据存储和处理技术;
- 如果你想知道Elasticsearch和Solr的区别,可以查看这篇
二、Solr的安装
-
在Win上的安装
-
Solr5之前的版本安装
- 这里我选择的是4.9.1,即5之前的最后一个版本;
- 解压之后把dist之中的solr-4.9.1.war复制到Tomcat的webapp下;
- 启动,等待解压,完成后把下载包中的\example\lib\ext中所有的jar拷贝到Tomcat\webapps\solr\WEB-INF\lib中,主要是给solr提供一个日志方面的包;
- 配置索引库:把解压包中的\example\solr到电脑中的一个位置,如我放在D:\Documents\SolrHome,我把solr重命名为SolrHome,把D:\Documents\SolrHome配置到Solr应用的web.xml中的env-entity中;
- 启动Tomcat,访问:http://localhost:8080/solr,安装完成
-
Solr5及其之后的版本安装
- // TODO 有时间补
三、配置中文分词器
- 这里我们使用IKAnalyzer来做中文分词,单独使用请参考我的另一片文章中文分词器 ~ IK Analyzer;
- 在Solr中使用的步骤如下:
- 文章中文分词器 ~ IK Analyzer中的配置;
- 修改 SolrHome 中的 schema.xml 文件,配置一个 FieldType,使Solr采用 IKAnalyzer作为默认的文本分词器:
<fieldType name="text_ik" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType>
- 配置完成后启动服务器
四、域
- 域,即字段,在Solr的配置schema.xml文件中对应的标签是field;还有一个就是fieldType,这个指的是域的数据类型;
- 我们一般是要在数据库中搜索数据的,尽管Solr的配置中已经为我们提供了相当多的域,但是我们在做项目的时候还是要根据我们的需求自定义添加一些域,并给这些域设置相应的属性,常见的属性如下:
- name:指定域的名称,自定义,一般是数据表中的字段名
- type:指定域的类型,即fieldType
- indexed:是否索引,取值true/false
- stored:是否存储,取值true/false
- required:是否必须,取值true/false
- multiValued:是否多值,取值true/false
- 自定义域
- 分析需要搜索的字段;
- 在SolrHome的schema.xml文件中添加字段field,根据业务需求添加这些域,同时设置上面的属性;
- 复制域
- 我们在搜索的时候摁钉还会遇到一种情况,用户在搜索的时候可以填写很多信息,而这些信息对应数据库的很多字段,难道我们要把分词的结果全部在数据库中笛卡尔积式 'LIKE' 吗?Solr中为我们解决了这个问题,解决的途径就是使用复制域来解决;
- 复制域schema.xml文件中对应的标签是copyField,含有两个属性:
- source:来源域的name属性
- dest:目标域,即:将source域复制到该目标域进行搜索)
- 动态域
- 动态域主要用来解决项目表中存储的数据是是动态类型的情况,比如我们常用的字典表就是这一类型,某列的值是根据当前记录的类型决定的;
- 动态域的配置与普通的字段域大部分相同,为疑似不同的就是在name属性上提供通配符 *;
五、SolrJ
- SolrJ是Solr官方提供的Java客户端,它提供了增删改查Solr索引的Java接口。SolrJ针对Solr提供了Rest 的HTTP接口进行了封装, SolrJ底层是通过使用httpClient中的方法来完成Solr的操作的;
- Solr是一个应用,SolrJ是一个请求Solr应用的客户端,之间使用HTTP进行通讯;
- 使用参考这篇文章;
六、SpringDataSolr
- SpringDataSolr其实就是Spring对SolrJ的一个封装;
- 使用步骤
- 引入Maven库
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-solr</artifactId> <version>3.0.11.RELEASE</version> </dependency>
- 添加配置文件:application-solr.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="https://www.springframework.org/schema/beans" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- Solr Server配置方式1 --> <solr:solr-server id = "solrServer" url = "<solr-access-url>" /> <!-- Solr Server配置方式2 --> <bean id = "solrServer" class = "org.apache.solr.client.solrj.impl.HttpSolrServer"> <constructor-arg index="0" value = "<solr-access-url>" /> </bean> <!-- Solr Server集群配置方式 --> <bean id = "solrServer" class = "org.apache.solr.client.solrj.impl.CloudSolrServer"> <constructor-arg index="0" value="<ip-port-comma>" /> <property name="defaultCollection" value="<collection-name>" /> </bean> <!-- Solr Template --> <bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate"> <constructor-arg ref="solrServer" /> </bean> </beans>
- 关联数据库字段与Solr搜索字段
- 关联直接使用注解@org.apache.solr.client.solrj.beans.Field作用在实体类上即可,如果数据库字段名和Solr搜索字段不相同则在参数中执行即可;
- 动态域在关联实体类的时候需要添加注解@Dynamic,凡是需要关联的实体字段是使用@Field,注解@Field是SolrJ提供的,而@Dynamic是SpringDataSolr提供的,所以在pom引用的时候直接引用SpringDataSolr即可,底层的框架会自动引入;
- 编码初始化Solr数据
- 编码的时候直接使用solrTemplate的save/delete/deleteById/queryForPage/getById等方法即可实现数据的增删改查,但是要注意的是,增删改语句后必须添加事务的提交语句
solrTemplate.commit();
,否则数据不会受影响的; - 具体的请查看API提示即可;
- Query:分页查询的封装类,请看代码:
Query query = new Query("*:*"); query.setOffset(<start>); query.setRows(<page-size>); query.setCriteria(<criteria>); // 封装查询条件 ScoredPage page = solrTemplate.queryForPage(query, <Bean>.class); List<<bean>> beansOfThisPage = page.getContent(); System.out.println("一页数据:" + beansOfThisPage); System.out.println("总条数:" + page.getTotalElements()); System.out.println("总页数:" + page.getTotalPages()); System.out.println("总页数:" + page.getSize());
- 使用上面的方法结合MyBatis把数据库中的数据保存到Solr索引中;具体就不在赘述;
- 编码的时候直接使用solrTemplate的save/delete/deleteById/queryForPage/getById等方法即可实现数据的增删改查,但是要注意的是,增删改语句后必须添加事务的提交语句
- 引入Maven库
- 关键字搜索
- 根据上面SolrTemplate的查询方法编写查询Solr的服务;
- Solr增量更新(参考这里和这里)
- 我们可以手动编写导入代码结合定时器完成,但是SpringDataSolr已经帮我们做了一部分工作,配置一下即可;如下:
- 导入solr数据更新的pom:
<dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-dataimporthandler</artifactId> <version>6.6.5</version> </dependency>
- 在SolrHome目录下新建一个文件夹conf,再在conf文件夹下新建dataimport.properties文件,其内容为:
################################################# # # # dataimport scheduler properties # # # ################################################# # to sync or not to sync # 1 - active; anything else - inactive syncEnabled=1 # which cores to schedule # in a multi-core environment you can decide which cores you want syncronized # leave empty or comment it out if using single-core deployment syncCores=test,hotel # solr server name or IP address # [defaults to localhost if empty] server=localhost # solr server port # [defaults to 80 if empty] port=8083 # application name/context # [defaults to current ServletContextListener's context (app) name] webapp=solr # 增量索引的参数 # URL params [mandatory] # remainder of URL params=/dataimport?command=delta-import&clean=false&commit=true # 重做增量索引的时间间隔 # schedule interval # number of minutes between two runs # [defaults to 30 if empty] interval=1 # 重做全量索引的时间间隔,单位分钟,默认7200,即5天; # 为空,为0,或者注释掉:表示永不重做索引 #reBuildIndexInterval=7200 # 重做索引的参数 reBuildIndexParams=/dataimport?command=full-import&clean=true&commit=true # 重做索引时间间隔的计时开始时间,第一次真正执行的时间=reBuildIndexBeginTime+reBuildIndexInterval*60*1000; # 两种格式:2012-04-11 03:10:00 或者 03:10:00,后一种会自动补全日期部分为服务启动时的日期 reBuildIndexBeginTime=03:10:00
- 增加增量更新监听器。即在Solr服务的web.xml加入监听器:
<listener> <listener-class> org.apache.solr.handler.dataimport.scheduler.ApplicationListener </listener-class> </listener>
- 编写增量更新SQL:在Solr的conf\data-config.xml中<entity>标签加入两个属性:
deltaImportQuery="<data-query-sql>'" deltaQuery="<primary-key-query-sql>"
- 属性介绍:
query是获取全部数据的SQL
deltaImportQuery是获取增量数据时使用的SQL
deltaQuery是获取主键的SQL
parentDeltaQuery是获取父Entity的主键的SQL - Full Import工作原理:
- 执行本Entity的Query,获取所有数据;
- 针对每个行数据Row,获取主键,组装子Entity的Query;
- 执行子Entity的Query,获取子Entity的数据。
- Delta Import工作原理:
- 查找子Entity,直到没有为止;
- 执行Entity的deltaQuery,获取变化数据的主键;
- 合并子Entity parentDeltaQuery得到的主键;
- 针对每一个主键 Row,组装父Entity的parentDeltaQuery;
- 执行parentDeltaQuery,获取父Entity的主键;
- 执行deltaImportQuery,获取自身的数据;
- 如果没有deltaImportQuery,就组装Query;
- 限制:
✔ 子Entity的query必须引用父Entity的主键;
✔ 子Entity的parentDeltaQuery必须引用自己的主键;
✔ 子Entity的parentDeltaQuery必须返回父Entity的主键;
✔ deltaImportQuery引用的必须是自己的主键;
- 属性介绍:
网友评论