solr的使用以及配置
- 传统的SQL语句实现方式效率低下
solr简介
- 基于Lucene的Java搜索引擎服务器程序
- 功能
- 数据导入
- 增量更新
- 数据检索(全文检索,高亮显示,精确搜索)
- Solr下载地址
- http://archive.apache.org/dist/lucene/solr/
- 教学版本
- Solr4.9.1
- Solr4.9.1依赖环境
- JDK1.7+
- Tomcat7.0+
solr安装配置
- solr_home:管理Core的配置目录
- core(collection):类似于数据库中的视图,一个core代表一种类型的数据集合
- 将dist\solr-4.9.war文件复制到tomcat的webapps目录下,并将文件命名为solr.war
- 复制 solr解压包下example\lib\ext 下所有的jar 到tomcat 的lib目录下
- 在计算机本地新建一个文件夹solrhome(当然你可以随便起名字), 然后复制solr-4.9.1\example\solr 下的所有文件到solrhome下
- 启动tomcat,待tomcat启动成功后,关闭tomcat。打开tomcat的webapps目录。注意,此时solr的war包以及被解压成solr文件夹。删除tomcat的webapps目录下的solr的war包,保留solr文件夹
- 修改配置文件 apache-tomcat-7.0.67\webapps\solr\WEB-INF\web.xml
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>D:/solr/solr_home</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
- 看到如下界面说明初始配置成功
core操作
- 新建core
- 新建core(solr中把配置的每一个模块都叫core),在solr_home目录下,拷贝collection1文件夹,并起名为test。打开test文件夹,修改core.properties文件,将name修改为test
- 重新启动tomcat,并访问solr,如出现以下界面,则表示新建test core新建成功
- 删除core
- 删除solr_home下test文件夹即可
- 拷贝数据库连接jar包(mysql-connector-java-5.1.18.jar)到tomcat的lib目录
- 配置数据源
- 配置字段
- 执行数据导入
- 测试数据导入结果
- 详细步骤
- 拷贝数据库连接jar包(mysql-connector-java-5.18.jar)到tomcat的lib目录
- 以创建testcore的方式新建hotel core
- 打开hotel的conf文件夹中的solrconfig.xml文件,在requestHandlername="/select"
- 前面上加上一个dataimport的处理的Handler
<requestHandler name="/dataimport"
class="org.apache.solr.handler.dataimport.DataImportHandler">
<lst name="defaults">
<str name="config">data-config.xml</str>
</lst>
</requestHandler>
- 在hotel的的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/itripdb" user="root" password="root" />
<document name="hotel_doc">
<entity name="hotel" pk="id" query="select id,hotelName,address from itrip_hotel">
<field column="id" name="id"/>
<field column="hotelName" name="hotelName"/>
<field column="address" name="address"/>
</entity>
</document>
</dataConfig>
- dataSource是数据库数据源。
- Entity就是一张表对应的实体,pk是主键,query是查询语句。
- Field对应一个字段,column是数据库里的column名,后面的name属性对应着Solr的Filed的名字。
- 修改同目录下的schema.xml(schema.xml是solr对数据库里的数据进行索引管理和数据字段展示管理的配置文件)
- 删除多余的field,保留version 和text这两个field(注意不要删除fieldType)
- 添加索引字段:这里每个field的name要和data-config.xml里的entity的field的name一样,一一对应
<field name="id" type="int" indexed="true" stored="true"/>
<field name="hotelName" type="string" indexed="true" stored="true"/>
<field name="address" type="string" indexed="true" stored="true"/>
- 将导入数据的JAR包拷贝到webapps/solr的lib目录下
- solr-4.9.1\dist\solr-dataimporthandler-4.9.1.jar
- solr-4.9.1\dist\solr-dataimporthandler-extras-4.9.1.jar
- 启动Tomcat,执行数据导入
- 异常处理
- 当你把id设置为int后,solr在启动的时候会加载elevate.xml,这个文件中定义的id的值为MA147LL/A,那么就出现异常Invalid Number: MA147LL/A
- 解决办法,将elevate.xml文件中这段代码注释掉
- 查询数据
- 增量更新:根据某一字段的值,动态导入更新数据。
- 配置增量更新
- 导入增量更新jar包
- 配置增量更新文件
- 增加增量更新监听器
- 编写增量更新SQL
- 启动测试
- 详细步骤
- 将资料中提供的apache-solr-dataimports-cheduler.jar包添加至solr的lib目录下
- 使用教学提供的jar包
- 增加增量更新配置文件,在solr_home文件夹下新建conf文件夹,并新建名为dataimport.properties的配置文件
# dataimportschedulerproperties #
# #
#################################################
# tosyncornottosync
# 1-active;anythingelse-inactive
syncEnabled=1
# whichcorestoschedule
# inamulti-coreenvironmentyoucandecidewhichcoresyouwantsyncronized
# leaveemptyorcommentitoutifusingsingle-coredeployment
syncCores=hotel
# solrservernameorIPaddress
# [defaultstolocalhostifempty]
server=localhost
# solrserverport
# [defaultsto80ifempty]
port=8080
# applicationname/context
# [defaultstocurrentServletContextListener'scontext(app)name]
webapp=solr
# 增量索引的参数
# URLparams[mandatory]
# remainderofURL
params=/dataimport?command=delta-import&clean=false&commit=true
# 重做增量索引的时间间隔
# scheduleinterval
# numberofminutesbetweentworuns
# [defaultsto30ifempty]
interval=1
# 重做全量索引的时间间隔,单位分钟,默认7200,即5天;
# 为空,为0,或者注释掉:表示永不重做索引
#reBuildIndexInterval=7200
# 重做索引的参数
reBuildIndexParams=/dataimport?command=full-import&clean=true&commit=true
# 重做索引时间间隔的计时开始时间,第一次真正执行的时间
reBuildIndexBeginTime+reBuildIndexInterval*60*1000;
# 两种格式:2012-04-1103: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_home\hotel\conf\data-config.xml)
deltaImportQuery="select id,hotelName,address from itrip_hotel where id = '${dih.delta.id}'"
deltaQuery="SELECT id as id FROM itrip_hotel where modifyDate > '${dih.last_index_time}'"
- deltaQuery是根据dataimport.properties配置文件中的更新时间,从数据库中查询出,修改日期在最后一次更新日期之后的酒店数据,并记录其id,而deltaImportQuery的目的是将deltaQuery查询出的数据导入到solr中
- 启动Tomcat进行测试
- 修改数据库中的酒店数据并同时修改该数据的modifyDate时间
- 1分钟后查询酒店数据,确定数据是否更新
- 全文检索:分析用户输入,并对用户输入进行拆分,组合等转化操作,根据转化后的数据对数据源数据进行检索,并将检索结果返回给用户
- 分词器:将用户输入根据语义拆分成多个词语
- 常见的中文分词器
- word分词器
- Ansj分词器
- IKAnalyzer分词器
- 课程选用分词器:IKAnalyzer分词器(版本2012FF_ul.jar)
- 常见的中文分词器
- Solr分词器配置
- 首先,下载IKAnalyzer
- https://github.com/medcl/elasticsearch-analysis-ik
- 拷贝jar包
- 配置过滤词语stopword.dic
- 配置分词器
- 配置schema.xml
- 修改字段类型
- 重启Tomcat,访问Solr测试分词器
- 首先,下载IKAnalyzer
- 详细步骤
- 将ik的所有jar文件 拷贝到 webapps\solr\WEB-INF\lib 目录下
- 在webapps\solr\WEB-INF\下新建classes文件夹,将IKAnalyzer.cfg.xml和stopword.dic文件拷贝到改文件夹下
- 在 solr_home\hotel\conf\schema.xml 增加如下配置
<fieldType name="text_ik" class="solr.TextField">
<analyzer type="index" isMaxWordLength="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/>
<analyzer type="query" isMaxWordLength="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
- 修改solrhome\hotel\conf\schema.xml将hotelName和address指定成为textik类型
<field name="hotelName" type="text_ik" indexed="true" stored="true"/>
<field name="address" type="text_ik" indexed="true" stored="true"/>
- 重启tomcat测试
solr查询语法
- q – 查询字符串,一般用于关键词过滤
- hotelName:北京
- fl – (field list)指定返回字段
- id,hotelName
- start –偏移值
- 从第几条开始
- rows – 指定返回结果最多有多少条记录,配合start来实现分页
- 每页显示条数
- sort – 排序
- id asc/desc
- wt – (writer type)指定输出格式(xml, json, python,ruby,php,csv)
- fq – (filter query)过滤查询
- 作用:在q查询符合结果中同时是fq查询符合的
- 执行完成之后,会对结果进行缓存 id:3 or id:5id:3 and hotelName:玉
solr多字段匹配
- 需求
- 对多个字段进行检索
- 步骤
- 新建field指定multiValued="true”
- 配置copyField
- 详细步骤
- 在hotel/conf/schema.xml文件中新增filed字段存储多字段的值
- 添加如下内容
<field name="keyword" type="text_ik" indexed="true" stored="true" multiValued="true"/>
<copyField source="hotelName" dest="keyword"/>
<copyField source="address" dest="keyword"/>
solrj集成solr应用
- solr本身提供了对外调用的Http接口,利用Http请求可以直接从solr中获取数据。为了方便Java程序员调用solr,Apache提供了基于solr操作的solrj程序包。
- 创建Solr查询的接收对象
- 编写客户端程序
- 创建HttpSolrClient对象
- 创建SolrQuery对象
- 创建QueryResponse数据接收对象
- 接收数据,转化数据
- 测试
- 详细步骤
- 下载solrj程序jar包
- 使用maven依赖方式添加
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>5.3.1</version>
</dependency>
<!--solrj的两个依赖jar包,是日志框架相关的jar包 -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
- 在程序中创建solr查询的接收对象
- 对应schema文件-创建Solr查询的接收对象
- 添加Field注解
public class ItripHotelVO implements Serializable {
@Field
private Integer id;
@Field
private String hotelName;
@Field
private String address;
}
- 编写客户端程序
- 创建HttpSolrClient对象
- 创建SolrQuery对象
- 创建QueryResponse数据接收对象
- 接收数据,转化数据
@Test
public void test1() {
// 连接url---本地solr访问地址:ip:端口号/solr/模块名
String url = "http://localhost:8080/solr/hotel";
// 创建solrClient
HttpSolrClient solrClient = new HttpSolrClient(url);
// 设置响应的解析器
solrClient.setParser(new XMLResponseParser());
// 设置建立连接的最长时间
solrClient.setConnectionTimeout(5000);
// 定义查询对象solrQuery
SolrQuery solrQuery = new SolrQuery("*:*");
// 设置排序规则
solrQuery.setSort("id", SolrQuery.ORDER.asc);
// 设置起始位置
solrQuery.setStart(0);
solrQuery.setRows(10);
try {
// 得到查询的响应对象
QueryResponse queryResponse = solrClient.query(solrQuery);
// 通过getBeans可以执行查询,将solr中的数据通过.class反射封装到对象中
List<ItripHotelVO> list = queryResponse.getBeans(ItripHotelVO.class);
for (ItripHotelVO hotelVO : list) {
System.out.println(hotelVO.getHotelName());
}
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
dao的封装
- 出口
- controller JSON
- 分层
- 数据访问层
- 通用查询抽取
- 参数抽取
- 数据访问层
- 业务逻辑层
- 表示层
- 抽取baseDao
public class BaseDao<T> {
private HttpSolrClient solrClient;
private QueryResponse queryResponse;
public BaseDao(String url) {
// 创建solrClient
solrClient = new HttpSolrClient(url);
// 设置响应的解析器
solrClient.setParser(new XMLResponseParser());
// 设置建立连接的最长时间
solrClient.setConnectionTimeout(5000);
}
public List<T> queryList(SolrQuery solrQuery, Class clazz) {
List<T> list = new ArrayList<>();
try {
// 得到查询的响应对象
queryResponse = solrClient.query(solrQuery);
// 通过getBeans可以执行查询,将solr中的数据通过.class反射封装到对象中
list = queryResponse.getBeans(clazz);
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
return list;
}
}
}
- 编写具体HotelDao
public class HotelDao extends BaseDao {
private static String url = "http://localhost:8080/solr/hotel";
public HotelDao() {
// 注意,url属性前一定要用static修饰,否则会报错
super(url);
}
public List<ItripHotelVO> queryList(String keyword) {
SolrQuery solrQuery = new SolrQuery("keyword:" + keyword);
// 调用baseDao的queryList方法
List list = this.queryList(solrQuery, ItripHotelVO.class);
return list;
}
}