当我们访问购物网站的时候,我们可以根据我们随意所想的内容输入关键字就可以查询出相关的内容,这是怎么做到呢?这些随意的数据不可能是根据数据库的字段查询的,那是怎么查询出来的呢,为什么千奇百怪的关键字都可以查询出来呢?
答案就是全文检索工具的实现,solr 支持分词检索。举个例子:北京天安门------切分词:北京 京天 天安 安门 等等这些分词。所以我们搜索的时候都可以检索到。
这里主要是讲主要搭建 solr 集群,由于只是开发,并不在生产环境,所以只能实现一个伪集群,也就是和之前的 redis 类似。
但是真正集群和伪集群也只是多台服务器和单台服务器的差别,并没有多大区别,可能防火墙、IP 等会有不同的配置。
伪集群会用了,起码真正集群有思路了,对吧,到时候再见招拆招就是了。
本文主要介绍单 solr 如何安装使用和测试,集群如何搭建,搭建好之后如何测试;
1、单机 solr 安装与测试
1.1、 安装
我这里使用的是 solr-4.10.3 版本有点低,大家可以选择高版本的试下,容器用的是 tomcat,当然你也可以选择 jetty,在我这里用哪个问题都不大,tomcat 比较熟,所以就用 tomcat,如果你是要生产环境用的,倒是要考虑清楚两者优缺点;
我们先在 HOME 目录解压 solr 包
tar -xzvf solr-4.10.3.tgz.tgz
再解压 tomcat 包
tar -xzvf apache-tomcat-7.0.47.tar.gz
一般来说,我们自己安装的软件都会放到/usr/local 里,所以这里也选择这个目录
sudo mkdir /usr/local/solr
再把 tomcat 拷贝到这个目录下
sudo cp -rf apache-tomcat-7.0.47 /usr/local/solr/tomcat
再把 solr 包里的 solr 的 war 包拷贝到 tomcat 的 webapps 里
sudo cp solr-4.10.3/dist/solr-4.10.3.war /usr/local/solr/tomcat/webapps/solr.war
启动 tomcat 解压 war 包
cd /usr/local/solr/tomcat/bin
sudo sh startup.sh
这时可以查看下日志,确认是否已经启动成功 ,日志在 tomcat/logs 的 catalina.out
这里不介绍了。
启动完之后,可以进 tomcat/webapps/下看看,确认有 solr 文件夹生成后,可以停掉 tomcat 了。
cd /usr/local/solr/tomcat/bin
sudo sh shutdown.sh
这里 solr.war 没用了,你可以选择删掉可以留着。
到这,solr 的启动准备已经做好了,现在就开始配置这个 tomcat 里的 solr 了。
1.2 配置
先复制 solr 压缩包中 example 下的 jar 包
cd solr-4.10.3
sudo cp example/lib/ext/*.jar /usr/local/solr/tomcat/webapps/solr/WEB-INF/lib/
接下来配置 solrhome,example 下 solr 可以做为 solrhome
sudo cp -rf example/solr /usr/local/solr/solrhome
有了 solrhome 后,需要配置 solr 的 web.xml 通过 JNDI 指定 solrhome 目录
<!-- People who want to hardcode their "Solr Home" directly into the
WAR File can set the JNDI property here...
-->
<!-- 打开下面env-entry的注释,并且修改entry-value -->
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>/usr/local/solr/solrhome</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
配置完 solrhome 之后,我们就可以启动 tomcat,网页方式登陆 solr 控制台看看了。
cd /usr/local/solr/tomcat/bin/
sudo sh startup.sh
访问 http://虚拟机 IP:8080/solr 访问了。
如果访问不了,确认一下防火墙状态,如果防火墙开了,可以通过修改防火墙配置文件后再访问。
sudo vi /etc/sysconfig/iptables
确认里面有没有以下内容
-A INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT
配置完重启防火墙就可以了。
sudo service iptables restart
1.3 加入 IK 中文分词器,确认需要自定义的 Field Type
下载好 IK Analyzer 包,上传到虚拟机后,解压,把里面的 jar 包和词典等都复制到相应位置
cd IK Analyzer 2012FF_hf1
sudo cp IKAnalyzer2012FF_u1.jar /usr/local/solr/tomcat/webapps/solr/WEB-INF/lib
sudo mkdir /usr/local/solr/tomcat/webapps/solr/WEB-INF/classes
sudo cp ext_stopword.dic IKAnalyzer.cfg.xml mydict.dic /usr/local/solr/tomcat/webapps/solr/WEB-INF/classes/
这样 IK 中文分词器就加入成功了。
接下来定义 solr 的 field type
这里需要进入到 solrhome 中的 collection1 里,修改其中的 schema.xml
cd /usr/local/solr/solrhome/collection1/conf
sudo vi schema.xml
里面有一段定义如下:
solr.TextField allows the specification of custom text analyzers
specified as a tokenizer and a list of token filters. Different
analyzers may be specified for indexing and querying.
TextFiled 允许使用自定义的解析器
所以我们要定义的 fieldtype 也是需要这个类型的,
在文件最后添加以下内容:
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
<field name="item_title" type="text_ik" indexed="true" stored="true"/>
因为我们刚刚已经把 IK 的 jar 包放到 solr 工程里了,所以 solr 能找到这个 IK 解析器。
至于 field 主要是看项目中可能搜索哪些字段,需要搜索的字段都应该在这里添加相应声明配置,
这里需要注意的是,需要中文解析器解析的时候才需要用 text_ik,而类似 URL,数字型的,solr 都有相应的类型可供选择。
配置完这些,需要重启下 tomcat。
1.4 测试
1.4.1 页面验证
重启完 tomcat 后,重新访问下 solr 控制台。
选择 collection1 -> Analysis 查找一下自己定义的 field type 和 field name。
选择 text_ik 或者自定义的 field,在 field value 里随便摘抄一段中文段落,点击 Anaylse Values,检查是否分词成功 ;
1.4.2 代码测试
新建 maven 工程,pom.xml 中包含以下依赖
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<!-- solr客户端 -->
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
</dependency>
test 目录新建 TestSolrJ.java
代码如下:
@Test
public void testAddDocument() throws Exception {
//创建一个solrServer对象,引用HttpSOlrServer对象
//指定URL
SolrServer solrServer = new HttpSolrServer("http://192.168.200.128:8080/solr/collection1");
//创建一个文档对象SolrInputDocument
SolrInputDocument doc = new SolrInputDocument();
//向文档中添加域,必须有id域,域的名称必须在schema.xml中定义
doc.addField("id", "test001");
doc.addField("item_title", "测试商品1");
//写入索引数据库
solrServer.add(doc);
//提交
solrServer.commit();
}
@Test
public void testQuery() throws Exception {
//创建一个solrServer对象
SolrServer solrServer = new HttpSolrServer("http://192.168.200.128:8080/solr/collection1");
//创建一个SolrQuery对象
SolrQuery query = new SolrQuery();
//设置查询条件,过滤条件,分页条件,排序条件,高亮等
//query.set("q","*:*");
query.setQuery("测试");
//分页条件
query.setStart(0);
query.setRows(10);
//默认搜索
query.set("df", "item_title");
//设置高亮
query.setHighlight(true);
query.addHighlightField("item_title");
query.setHighlightSimplePre("<div>");
query.setHighlightSimplePost("</div>");
//执行查询,得到一个Response对象
QueryResponse resp = solrServer.query(query);
//取查询结果
SolrDocumentList resultList = resp.getResults();
//取查询结果总记录数
System.out.println("查询结果总记录数:" + resultList.getNumFound());
for (SolrDocument solrDocument : resultList) {
System.out.println(solrDocument.get("id"));
//取高亮显示
Map<String, Map<String, List<String>>> highlighting = resp.getHighlighting();
List<String> list = highlighting.get(solrDocument.get("id")).get("item_title");
//如果取到的高亮为空,则用原来的item_title,否则用高亮显示
String item_title = "";
if(list != null && list.size() > 0) {
item_title = list.get(0);
} else {
item_title = (String) solrDocument.get("item_title");
}
System.out.println(item_title);
System.out.println("===========================================================");
}
}
}
2. 集群搭建与测试
先新建个 solr-cloud 文件夹
sudo mkdir /usr/local/solr-cloud
2.1 zookeeper 集群搭建
这里使用的 zookeeper 版本是 3.4.6 高版本应该也是一样的,可以作参考。
解压 zookeeper 后,由于集群需要用 3 个 zookeeper,所以需要复制 3 份到/usr/local/solr-cloud 中
sudo cp -rf zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper01
sudo cp -rf zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper02
sudo cp -rf zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper03
接下来进入 zookeeper 文件夹进行配置
cd /usr/local/solr-cloud/zookeeper01
sudo mkdir data
touch data/myid
vi 编译,里面只写 “1”
如下:
[llq@bogon data]$ cat myid
1
创建完 data/myid 后,修改 conf/zoo.cfg 配置,如果没有 ,则用 conf 目录下的 zoo_sample.cfg 复制一个 zoo.cfg
修改里面内容如下:
dataDir=/usr/local/solr-cloud/zookeeper01/data/
clientPort=2181
在文件最后插入以下三行
server.1=192.168.200.128:2881:3881
server.2=192.168.200.128:2882:3882
server.3=192.168.200.128:2883:3883
这里要注意,2181 是客户端访问 zookeeper 的端口,2881 是 zookeeper 集群中 leader 和 follow 之间通信用的,3881 是集群节点间投票选举时用的端口。
zookeeper01 配置完了,另外两个也是同样配置,只改 myid 对应为 2 3, zoo.cfg 中,要改 dataDir 为对应目录,clientPort 也需要相应改为 2182 2183,下面的 server.1 2 3 就不需要改了,直接添加就行了。
也就是如下所示:
[llq@bogon solr-cloud]$ cat zookeeper01/data/myid
1
[llq@bogon solr-cloud]$ cat zookeeper02/data/myid
2
[llq@bogon solr-cloud]$ cat zookeeper03/data/myid
3
由于 zoo.cfg
篇幅较大,这里只贴出 zookeeper03
,看看就知道前面两个怎么配了。
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
#dataDir=/tmp/zookeeper
dataDir=/usr/local/solr-cloud/zookeeper03/data/
# the port at which the clients will connect
clientPort=2183
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
server.1=192.168.200.128:2881:3881
server.2=192.168.200.128:2882:3882
server.3=192.168.200.128:2883:3883
到这里已经配置好 zookeeper 集群了,现在写个脚本启动下这个集群
2.2 solr cloud 搭建
我们这里需要用到 4 个 solr 节点,也就是需要 4 个 tomcat 和 4 个 solrhome,每个节点的安装方式和单机类似,可以直接拷贝单机的过来改一下就行了。
我们先准备 4 个 tomcat,从我们单机版 solr 解压的 tomcat 拷贝到/usr/local/solr-cloud 下
sudo cp -rf apache-tomcat-7.0.47 /usr/local/solr-cloud/tomcat01
sudo cp -rf apache-tomcat-7.0.47 /usr/local/solr-cloud/tomcat02
sudo cp -rf apache-tomcat-7.0.47 /usr/local/solr-cloud/tomcat03
sudo cp -rf apache-tomcat-7.0.47 /usr/local/solr-cloud/tomcat04
接下来就改配置了
cd /usr/local/solr-cloud
sudo vim tomcat01/conf/server.xml
找到以下端口,改之前如下:
<Server port="8005" shutdown="SHUTDOWN">
<Connector port="8080" protocol="HTTP/1.1"
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
改之后如下:
<Server port="8105" shutdown="SHUTDOWN">
<Connector port="8180" protocol="HTTP/1.1"
<Connector port="8109" protocol="AJP/1.3" redirectPort="8443" />
四个 tomcat 都按上面改,每个 tomcat 的端口都不能重复,tomcat02 就是 8205,8280,8209,以此类推
tomcat 搞好之后,我们最好先把之前单机版的 tomcat 关掉,然后我们再把单机的 tomcat 解压的 solr 文件夹拷贝到这 4 台 tomcat 中
sudo /usr/local/solr/tomcat/bin/shutdown.sh
sudo cp -rf ../solr/tomcat/webapps/solr/ tomcat01/webapps/
sudo cp -rf ../solr/tomcat/webapps/solr/ tomcat02/webapps/
sudo cp -rf ../solr/tomcat/webapps/solr/ tomcat03/webapps/
sudo cp -rf ../solr/tomcat/webapps/solr/ tomcat04/webapps/
再把 solrhome 也拷贝四个
sudo cp -rf ../solr/solrhome/ solrhome01
sudo cp -rf ../solr/solrhome/ solrhome02
sudo cp -rf ../solr/solrhome/ solrhome03
sudo cp -rf ../solr/solrhome/ solrhome04
tomcat 和 solrhome 都准备好了之后,我们开始改配置。
sudo vi solrhome01/solr.xml
<solrcloud>
<!-- 这个是tomcat01的ip -->
<str name="host">192.168.200.128</str>
<!-- 这个是tomcat01的端口 -->
<int name="hostPort">8180</int>
<str name="hostContext">${hostContext:solr}</str>
<int name="zkClientTimeout">${zkClientTimeout:30000}</int>
<bool name="genericCoreNodeNames">${genericCoreNodeNames:true}</bool>
</solrcloud>
只改两项,其它三个 tomcat 相应做修改。
solrhome 关联 tomcat 已经改了,tomcat 下的 solr 关联 solrhome 还没有,现在改
sudo vi tomcat01/webapps/solr/WEB-INF/web.xml
主要是修改单机时配置的 solrhome 目录,改为 solr-cloud 的 solrhome 目录
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>/usr/local/solr-cloud/solrhome01</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
另外三个 solr 的 web.xml 也是同样方式修改,每个 solrhome 要对应上。
好了,现在 solrhome 和 tomcat 之间都有联系了,现在就差与 zookeeper 挂上钩了。
现在需要在 tomcat 启动的时候加上-zkHost 的参数,在哪加呢,我们可以在 tomcat/bin 目录下的 catalina.sh 里的 JAVA_OPTS。
# JAVA_OPTS (Optional) Java runtime options used when any command
# is executed.
# Include here and not in CATALINA_OPTS all options, that
# should be used by Tomcat and also by the stop process,
# the version command etc.
# Most options should go into CATALINA_OPTS.
sudo vi tomcat01/bin/catalina.sh
好了,我们赋权启动吧。
sudo chmod +x tomcat-cmd.sh
sudo ./tomcat-cmd.sh
跟单机一样,我们可以看看日志,确认是否已经启动,启动完之后,我们可能还要再配置一下防火墙。
与单机一样改同样的配置,加上以下内容即可。
-A INPUT -p tcp -m state --state NEW -m tcp --dport 2182 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 2183 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 8180 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 8280 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 8380 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 8480 -j ACCEPT
重启防火墙。
2.3 验证测试
2.3.1 页面验证
我们登陆任意一个 solr 的控制台
http://192.168.200.128:8180/solr/#/
可以看到里面多了个 cloud,点进去,可以看到如下图片内容:
从图中可以看到,8480 的 tomcat 为 leader.
但是这个还不是个合理的集群,这里应该是一个 collection 下有两个 share,每个 share 下还要有两个节点,一主一备。
我们使用 solr URL 修改一下。
在浏览器输入以上 URL,加载之后,等待返回成功提示:
name="success">
我们再进入 solr 控制台的 cloud 看看效果
我们现在有个 collection2 符合我们要求了,我们可以把 collection1 删掉了。同样用 URL 命令
http://192.168.200.128:8180/solr/admin/collections?action=DELETE&name=collection1
执行完再刷新一下 cloud,就只剩 collection2 了。
现在可以继续像单机一样,测试一下分词功能是否正常可用。
2.3.2 代码测试
@Test
public void testAddDocument() throws Exception {
//创建一个CloudSolrServer对象,构造方法中需要传入zookeeper的地址列表
CloudSolrServer cloudSolrServer = new CloudSolrServer("192.168.200.128:2181,192.168.200.128:2182,192.168.200.128:2183");
//设置默认的collection
cloudSolrServer.setDefaultCollection("collection2");
//创建一个文档对象SolrInputDocument
SolrInputDocument doc = new SolrInputDocument();
//向文档中添加域,必须有id域,域的名称必须在schema.xml中定义
doc.addField("id", "test001");
doc.addField("item_title", "测试商品2");
//写入索引数据库
cloudSolrServer.add(doc);
//提交
cloudSolrServer.commit();
}
执行完后,其实可以在 solr 的 Query 页面查询,
q 栏上填“测试”,df 栏上填"item_title",执行查询就可以查到了。
{ "responseHeader": { "status": 0, "QTime": 885, "params": { "q": "测试", "df": "item_title", "indent": "true", "wt": "json", "_": "1531575293854" } }, "response": { "numFound": 1, "start": 0, "maxScore": 0.15342641, "docs": [ { "id": "test001", "item_title": "测试商品2", "_version_": 1605973005675004000 } ] } }
查询的测试代码类似,只有创建的 solrServer 对象改为 CloudSolrServer 对象。
终于写完了。
腰酸背痛的。休息去咯。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于