Solr是基于lucene的全文检索服务器。
不一样于lucene工具包,solr是一个web应用,运行在servlet容器,屏蔽了底层细节,并对外提供服务。html
点我lucene快速入门mysql
Solr建立及维护索引:
solr客户端向solr服务端发送POST请求,请求内容是包含Field等信息的一个xml文档。经过该文档,solr实现对索引的维护(增删改)。web
Solr的搜索:
solr客户端向solr服务端发送GET请求,solr服务器返回一个xml文档。sql
做为一个web应用,咱们更多的工做不是编码而是配置。数据库
解压solr压缩文件,能够看到下面几个目录
bin : 存放solr命令
contrib : solr加强功能
dist : solr编译后产生的war包和依赖包
exapmle: solr的示例,其中,example/solr->solrhome, example/solr/collection1->solrcorejson
slorhome是solr服务运行的主目录,一个solrhome里包含多个solrcore。
solrcore存放了solr实例运行时须要的配置文件和索引数据,每一个solrcore均可以单独提供服务,多个solrcore之间没有关系。
不一样的业务模块可使用不一样的solrcore来提供服务;创建solr集群的时候,必须配置多个solrcore。
`solrcore`/conf->配置文件
`solrcore`/data->solr的数据,包含索引文件和log
`solrcore`/core.properties->本solrcore对外的名字tomcat
安装配置步骤:服务器
1. 解压war包至servlet容器,删除war包
2. 添加日志:
example/lib/ext复制到solr的WEB-INF/lib下
example/resources/log4j.properties复制到WEB-INF/classes下
3. 添加分词器:
分词器的jar包复制到solr的WEB-INF/lib下
分词器的字典,中止词,配置文件复制到WEB-INF/classes下
记得在后面配置分词器的fieldType架构
4. 复制example下面的solrhome(含solrcore),至自定义目录下。若是须要,复制example下面的dist和contrib,至自定义目录下
5. 修改Web.xml的<env-entry>,设置solrhome的位置
6. 配置`solrcore`/conf/solrconfig.xml
1)lib标签。若是须要,指定相关加强功能包的位置。其中solr.install.dir表示solrcore的位置,做相应修改("../"部分)
2)datadir标签。指定data的位置,其中solr.data.dir表示`solrcore`/data,不用修改
3)requestHandler标签。设置请求url和服务器索引维护(update),搜索(search)行为之间的对应关系。后面使用dataimport插件时须要设置。负载均衡
<requestHandler name="/select" class="solr.SearchHandler"> <!-- 默认参数值,能够在请求URL中覆盖--> <lst name="defaults"> <str name="echoParams">explicit</str> <int name="rows">10</int> <!--默认显示数量--> <str name="wt">json</str> <!--默认显示格式--> <str name="df">text</str> <!--默认搜索字段--> </lst> </requestHandler>
7. 配置`solrcore`/conf/schema.xml
详解:
<!-- name:field的名称, 使用field必备; type:见下方fieldType,决定了是否分词; indexed:是否索引; stored:是否存储; required:该field是否必需;
multiValued: 是否存储多个值, 好比商品图片地址 --> <!-- 索引数据库中根据须要索引字段创建各field --> <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" /> <!-- 动态field, 用通配符指定field名称 --> <dynamicField name="*_i" type="int" indexed="true" stored="true"/> <!-- 惟一键, 用做id的field. 该field必须已经定义且required属性为true, schema中有且仅有一个uniqueKey--> <uniqueKey>id</uniqueKey> <!-- 复制域, source:被复制的field; dest:复制到的field. 两个field必须已经定义且dest的multiValued属性为true --> <!-- 将多个域的信息复制到一个域里面, 目的: 方便组合查找 --> <copyField source="cat" dest="text"/> <!-- 域的类型,自定义分词器须要配置 class:相似lucene,但没有是否索引,是否存储的信息, 该信息定义在field标签里 --> <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <!--创建索引时设置--> <tokenizer class="solr.StandardTokenizerFactory"/> <!-- 创建索引时的分词器, 和搜索时分词器须相同 --> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" /> <!--中止词过滤器--> <filter class="solr.LowerCaseFilterFactory"/> <!--大写转小写过滤器--> </analyzer> <analyzer type="query"> <!--搜索时设置, 与索引时设置基本一致, 能够只设置一个 --> <tokenizer class="solr.StandardTokenizerFactory"/> <!-- 搜索时的分词器, 和索引分词器须相同 --> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" /> <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> </fieldType>
添加dataimport插件
dataimport插件实现将sql语句的查询结果批量导入到solr索引库中, 固然该功能也能够经过下面的SolrJ实现
solr管理界面dataimport默认不可用, 如下步骤可开启:
1.添加`solrcore`/conf/solrconfig.xml的lib标签, 指定dist/solr-dataimporthandler
2.复制mysql数据库驱动包至contrib/db/lib下, 添加lib标签
3.添加`solrcore`/conf/solrconfig.xml的requestHandler标签, class:DataImportHandler, name:/dataimport, 指定sql语句配置文件data-config.xml
4.创建data-config.xml文件
维护索引:
public class IndexManager { @Test public void createAndUpdateIndex() throws Exception { // 建立Document对象 SolrInputDocument doc = new SolrInputDocument(); // field要求已经在solar服务器的配置文件中定义 doc.addField("id", "testId"); doc.addField("name", "testName"); // 建立HttpSolrServer HttpSolrServer server = new HttpSolrServer("http://localhost:8080/solr"); // 根据惟一键查找, 没有则建立, 有则修改 server.add(doc); // 提交 server.commit(); } @Test public void deleteIndex() throws Exception { HttpSolrServer server = new HttpSolrServer("http://localhost:8080/solr"); // 根据ID删除 server.deleteById("c001"); // 根据条件删除 server.deleteByQuery("id:c001"); // 删除所有(慎用) server.deleteByQuery("*:*"); // 提交 server.commit(); } }
搜索:
public class IndexSearch { @Test public void searchSimple() throws Exception { HttpSolrServer server = new HttpSolrServer("http://localhost:8080/solr"); // 建立SolrQuery对象 SolrQuery query = new SolrQuery(); // 查询条件 query.setQuery("product_name:玩具"); // 执行查询并接收响应 QueryResponse response = server.query(query); // 拿到结果 SolrDocumentList queryResults = response.getResults(); // 匹配结果总数 long count = queryResults.getNumFound(); System.out.println("结果总数:" + count); for (SolrDocument doc : queryResults) { System.out.println(doc.get("id")); System.out.println(doc.get("product_name")); System.out.println(doc.get("product_catalog")); System.out.println(doc.get("product_price")); System.out.println(doc.get("product_picture")); } } @Test public void searchComplicate() throws Exception { SolrQuery query = new SolrQuery(); query.set("q", "product_name:玩具"); // 设置过滤条件, 可添加多个 query.addFilterQuery("product_price:[1 TO 10]"); // 设置排序 query.setSort("product_price", ORDER.asc); // 设置结果分页 query.setStart(0); query.setRows(10); // 设置结果显示的Field域集合 query.setFields("id,product_name,product_price"); // 设置默认搜索域, 查询语句中不须要"product_keywords:"了 query.set("df", "product_keywords"); // 设置某field高亮显示 query.setHighlight(true); query.addHighlightField("product_name"); query.setHighlightSimplePre("<font style=\"color:red\">"); query.setHighlightSimplePost("</font>"); HttpSolrServer server = new HttpSolrServer("http://localhost:8080/solr"); QueryResponse response = server.query(query); // 获得结果 SolrDocumentList queryResults = response.getResults(); long count = queryResults.getNumFound(); System.out.println("匹配结果总数:" + count); // 获得被封装的高亮结果, 相似: 普通字段<font style="color:red">高亮字段</font>普通字段 Map<String, Map<String, List<String>>> hlResults = response.getHighlighting(); for (SolrDocument doc : queryResults) { System.out.println(doc.get("id")); // 解析被封装的带高亮显示的结果. 对可能的高亮field分别处理 List<String> hlLists = hlResults.get(doc.get("id")).get("product_name"); if (hlLists != null) System.out.println("高亮显示商品名:" + hlLists.get(0)); else { System.out.println("正常显示商品名:" + doc.get("product_name")); } System.out.println(doc.get("product_price")); } } }
Solr集群须要用到多个solr与多个zookeeper
这里搭一个以下的简单架构做为例子
zookeeper在这个集群的做用:
1. 集群管理. 负责solr的主从关系, 负载均衡, 做为外界访问集群的入口. 为了保证高可用, zookeeper自身也必须是集群. 为使选举和投票有效, zookeeper至少须要三个节点.
2.配置文件管理. 各solr配置文件相同, 将配置文件上传给zookeeper统一管理, 每一个solr节点都到zookeeper上取配置.
若是在一台主机上搭建集群, 注意避免端口冲突.
1)在zookeeper01目录下建立一个data文件夹。
2)在data目录下建立一个myid的文件
3)Myid的内容为1(zookeeper02对应“2”,zookeeper03对应“3”)
4)进入conf文件, 复制zoo_sample.cfg模板文件建立zoo.cfg
5)修改zoo.cfg
把dataDir属性指定为刚建立的data文件夹
指定clientPort, 这是外界访问zookeeper01的端口
添加以下内容:
server.1=`zookeeper01的ip`:`port2`:`port3`
server.2=`zookeeper02的ip`:`port2`:`port3`
server.3=`zookeeper03的ip`:`port2`:`port3`
两个端口号分别是zookeeper间相互通讯, 进行投票和选举的端口
6)zookeeper02 03以此类推
7)启动zookeeper. 使用zookeeper的bin目录下的zkServer.sh
启动:./zkServer.sh start
关闭:./zkServer.sh stop
查看服务状态:./zkServer.sh status
1)须要准备4台tomcat与4个solr实例
2)建立solrhome, 修改web.xml关联solrhome等相似单机solr
3)修改`solrhome`/solr.xml. 将solrCloud下的host, hostPort修改成所在的web容器访问地址与端口号
4)使用solr-4.10.3/example/scripts/cloud-scripts/zkcli.sh命令将某台的`solrcore`/conf目录上传到zookeeper集群
./zkcli.sh -zkhost `zookeeper01的ip`:`port1`,zookeeper02的ip`:`port1`,zookeeper03的ip`:`port1` -cmd upconfig -confdir `solrcore`/conf -confname myconf
查看是否上传成功, 使用zookeeper的zkCli.sh命令
5)通知solr实例zookeeper的位置。修改tomcat的catalina.sh添加
JAVA_OPTS="-DzkHost=`zookeeper01的ip`:`port1`,zookeeper02的ip`:`port1`,zookeeper03的ip`:`port1`"
6)启动solr实例, 访问以下url进行分片, 分为2片, 每片一主一从
分片, 建立solrcore collection2:
http://某solr的ip:port/solr/admin/collections?action=CREATE&name=collection2&numShards=2&replicationFactor=2
能够删除不用的solrcore collection1
http://某solr的ip:port/solr/admin/collections?action=DELETE&name=collection1
public class IndexManager { @Test public void createAndUpdateIndex() throws Exception { SolrInputDocument document = new SolrInputDocument(); document.addField("id", "testId"); document.addField("item_title", "testName"); // 建立一个SolrServer对象, zkHost地址为三个zookeeper地址 CloudSolrServer solrServer = new CloudSolrServer("192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183"); // 设置使用的solrcore(分片策略) solrServer.setDefaultCollection("collection2"); solrServer.add(document); solrServer.commit(); } }
能够看出除了获取solrServer, 使用上和单机版没有任何区别. 集群对客户端来讲的封闭的.