全文检索技术——Solr
2 站内搜索技术选型
1、使用Lucene来实现:需要大量的编码才能实现。集群方案需要自己解决。查询速度的优化都需要自己解决。不推荐使用。
2、使用搜素引擎提供的接口实现站内搜索。索引库在搜索引擎上,维护不方便。开发简单。
3、使用Solr来实现站内搜索。可以独立运行,提供全套的解决方案。Solr集群、索引库的优化。推荐使用。
3 什么是solr
3.1 什么是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的配置和运行情况。
3.2 Solr和lucene的区别
Lucene是一个开放源代码的全文检索引擎工具包,它不是一个完整的全文检索引擎,Lucene提供了完整的查询引擎和索引引擎,目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者以Lucene为基础构建全文检索引擎。
Solr的目标是打造一款企业级的搜索引擎系统,它是一个搜索引擎服务,可以独立运行,通过Solr可以非常快速的构建企业的搜索引擎,通过Solr也可以高效的完成站内搜索功能。
3.3 Solr的下载
下载地址:lucene.apache.org/solr/mirrors-solr-latest-redir.html?
版本是:4.10.3
4 Solr的安装及配置
4.1 Solr的运行环境
Solr4.10要求jdk1.7.0及以上版本
要求tomcat7.0以上
4.2 Solr集成tomcat
第一步:安装tomcat,我们使用的版本是apache-tomcat-7.0.53
第二步:部署solr的war包。将solr-4.10.3.war复制到tomcat的webapp下。改名为solr.war
第三步:解压Solr.war,在solr\WEB-INF\lib添加日志需要的jar包。
将solr-4.10.3\example\lib\ext目录下的jar复制到lib下。
第四步:配置solrhome,及solrcore。
Solrhome也就是solr服务器所有配置文件存放的文件夹。
\solr-4.10.3\example\solr文件夹就是一个标准的solrhome。
1)solr文件夹复制到指定位置E:\B_develop\apache-tomcat-7.0.67\webapps\solr\solrhome
2)Solrcore:collection1就是一个solrcore,一个solrcore就是一个索引库。可以对比mysql的数据库,一个solrcore相当于一个mysql 的数据库。索引库和索引库之间相互独立。
3)collection1\conf:每个sorlcore的配置信息。
4)Solrconfig.xml:solrcore的配置,如果使用默认配置可以不用修改。
luceneMatchVersion:匹配的lucene的版本
Lib:solrcore扩展包的位置,默认是collection1\lib文件夹,如果没有lib文件夹就创建一个。
dataDir:索引库存放的位置。默认是collection1\data文件夹,如果没有sorl会自动创建。
查询索引使用的URL:
<requestHandler name="/select" class="solr.SearchHandler">
维护索引使用的url:
<requestHandler name="/update" class="solr.UpdateRequestHandler">
默认查询条件:
<defaultQuery>*:*</defaultQuery>
第五步:将solrhome的位置告诉solr服务。使用jndi的方式。修改web.xml文件
修改solrhome
第六步:启动tomcat
第七步:访问solr服务http://localhost:8080/solr
4.3 管理界面介绍
4.3.1 添加solrCore
第一步:复制collection1为collection2
第二步:修改core.properties文件将name=collection2
第三步:重启tomcat
4.3.2 选择solrcore
在下拉框中选型要查看或者维护的solrcore
4.3.3 Analysis
4.3.4 Dataimport
可以讲关系型数据库中的数据导入到索引库中。
4.3.5 维护索引
4.3.6 搜索文档的功能
5 Schema.xml
在schema.xml定义域及域的类型,必须先定义后使用。
5.1 Field域定义
Name:域的名字
Type:域的类型,可以可以自定义。也是在schema.xml中定义。
Indexed:是否索引
Stored:是否存储
multiValued:是否多值,就是在一个域中存储多个值,存储一个数组。
5.2 dynamicField动态域
如果一个未定义的域可以和动态域相匹配那么也是可以使用的。
Name:动态域的表达式
Type:域的类型
Indexed:是否索引
Stored:是否存储
multiValued:是否多值,就是在一个域中存储多个值,存储一个数组。
5.3 uniqueKey
索引库的主键。
每个文档必须包含id域。
5.4 copyField复制域
Source:源域
Dest:目标域
当向索引库中添加文档时,copyfield会自动将源域的内容复制到目标域中。
例如:
<copyField source="cat" dest="text"/>
5.5 fieldType域类型
Name:域类型的名称
Class:实际对应的java类型
Analyzer:可以配置第三方分析器。可以自定义数据类型配置中文分析器。
6 配置中文分析器
修改schema.xml先添加fieldType然后再添加field。
第一步:先将IKAnalyzer的jar包添加到solr工程中。
第二步:把配置文件复制到solr工程的classpath下。
第三步:修改schema.xml添加自定义的fieldtype。
<!-- IKAnalyzer-->
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
第四步:在schema.xml添加自定义的域field。
第五步:重启tomcat
6.1 设置业务系统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"/>
和商品表的表结构对应。
7 索引库的维护
7.1 添加文档
{"id":"a0001","title_ik":"中文分析器的title","content_ik":"接下来点击顶部导航的“搜索框样式”,进入搜索框设置界面。"}
7.2 文档的删除
7.2.1 根据id删除文档
7.2.2 根据查询删除文档
7.3 更新文档
先删除后添加。
只需要再添加一个id和需要更新的文档id一致新文档就可以了。
7.4 批量添加文档,使用dataimport插件
7.4.1 Dataimport插件需要的jar包
7.4.2 配置插件
第一步:先将插件依赖的jar包添加到solrcore中。放到Collection1\lib下。
第二步:mysql数据库的驱动也添加到Collection1\lib下
第三步:修改solrconfig.xml配置文件。
<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文件放到collection\conf文件夹下。
第五步:重启tomcat。
先清空索引库然后再倒入。
8 索引库的查询
Request-Handler:/select
Q:查询条件。默认是*:*。完全支持lucene的查询语法,并且范围查询语法支持数值类型的域。
Fq:过滤查询条件。是在查结果基础上,进一步过滤。查询语法和查询条件的语法一致。
Sort:排序。指定排序的域在后面跟上asc|desc 。如果多个排序条件,使用半角逗号“,”分隔。
分页处理:
Start:起始记录的下标。
Row:每页显示的记录数。
Fl:返回结果中文档包含的域列表。多个域使用半角逗号“,”分隔。不设置此属性默认返回全部域。
Df:默认搜索域。如果查询条件中不指定搜索的域,而且不设置默认搜索域,就查询不到结果。
Wt:返回结果的数据格式。可以是json、xml
Hl:高亮显示
1)hl.fl:高亮显示的域
2)Hl.simple.pre:前缀
3)Hl.simple.post:后缀
9 使用solrJ客户端
9.1 依赖的jar包
9.2 使用solrJ维护索引
索引的增删改操作。
9.2.1 实现步骤
第一步:创建一个java工程
第二步:导入jar包。
第三步:创建和服务端的连接。SolrServer对象,HttpSolrServer创建连接。
第四步:创建一个文档对象。SolrInputDocument。
第五步:向文档对象中添加域。
第六步:把文档对象发送给服务端。
第七步:关闭连接。
9.2.2 添加文档
代码实现
//添加文档 @Test public void addDocument() throws Exception { //建立连接 //参数是solr服务器的地址 SolrServer server = new HttpSolrServer("http://localhost:8080/solr"); //创建文档对象 SolrInputDocument document = new SolrInputDocument(); //添加域,域名必须是schema.xml中定义的。而且必须有id这个域。 document.addField("id", "a001"); document.addField("title_ik", "新添加的文档"); document.addField("content_ik", "新添加文档的内容"); document.addField("product_name", "还没想好叫什么名字"); //把文档添加到索引库 server.add(document); //提交修改 server.commit(); } |
9.2.3 删除文档
9.2.3.1 根据id删除文档
//删除文档 @Test public void deleteDocument() throws Exception { //建立连接 //参数是solr服务器的地址 SolrServer server = new HttpSolrServer("http://localhost:8080/solr"); //删除指定id的文档 server.deleteById("a001"); //提交 server.commit(); } |
9.2.3.2 根据查询删除文档
9.2.3.3 修改文档
没有专门的修改文档的方法,直接在添加一条新的文档,要求id和需要更新的文档id保持一致就可以了。
跟添加文档的方法一样。
9.3 solrJ查询索引库
//查询索引库 @Test public void searchIndex() throws Exception { //建立连接 SolrServer server = new HttpSolrServer("http://localhost:8080/solr"); //创建一个query对象 SolrQuery query = new SolrQuery(); //查询条件 query.setQuery("花儿"); //过滤条件 query.addFilterQuery("product_price:[10 TO 100]"); //排序 query.setSort("product_price", ORDER.asc); //分页处理 query.setStart(0); query.setRows(10); //文档中包含的域列表 query.setFields("product_picture", "product_catalog_name", "product_price", "product_name", "id"); //设置默认搜索域 query.set("df", "product_keywords"); //高亮设置 query.setHighlight(true); //高亮显示的域 query.addHighlightField("product_name"); //设置高亮前缀 query.setHighlightSimplePre("<em>"); //高亮后缀 query.setHighlightSimplePost("</em>"); //执行查询 QueryResponse queryResponse = server.query(query); //取查询结果 SolrDocumentList solrDocumentList = queryResponse.getResults(); //获得查询结果的总数量 System.out.println("查询结果的总数量" + solrDocumentList.getNumFound()); //遍历查询结果 for (SolrDocument solrDocument : solrDocumentList) { System.out.println(solrDocument.get("id")); System.out.println(solrDocument.get("product_picture")); System.out.println(solrDocument.get("product_catalog_name")); System.out.println(solrDocument.get("product_price")); //取高亮显示 String name = ""; //取高亮内容 Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting(); List<String> list = highlighting.get(solrDocument.get("id")).get("product_name"); if (null == list) { name = (String) solrDocument.get("product_name"); } else { name = list.get(0); } System.out.println(name); } } |