在一臺虛擬機(jī)上搭建Solr集群
1. Solr技術(shù)群的系統(tǒng)架構(gòu)

Collection:
Collection在SolrCloud集群中是一個邏輯意義上的完整的索引結(jié)構(gòu)。它常常被劃分為一個或多個Shard(分片),它們使用相同的配置信息。
比如:針對商品信息搜索可以創(chuàng)建一個collection。
collection=shard1+shard2+....+shardX`
Core
每個Core是Solr中一個獨(dú)立運(yùn)行單位,提供 索引和搜索服務(wù)。一個shard需要由一個Core或多個Core組成。由于collection由多個shard組成所以collection一般由多個core組成。
Master或Slave
Master是master-slave結(jié)構(gòu)中的主結(jié)點(diǎn)(通常說主服務(wù)器),Slave是master-slave結(jié)構(gòu)中的從結(jié)點(diǎn)(通常說從服務(wù)器或備服務(wù)器)。同一個Shard下master和slave存儲的數(shù)據(jù)是一致的,這是為了達(dá)到高可用目的。
Shard
Collection的邏輯分片。每個Shard被化成一個或者多個replication,通過選舉確定哪個是Leader。
1.1. 物理結(jié)構(gòu)
? 三個Solr實(shí)例( 每個實(shí)例包括兩個Core),組成一個SolrCloud。
1.2. 邏輯結(jié)構(gòu)
? 索引集合包括兩個Shard(shard1和shard2),shard1和shard2分別由三個Core組成,其中一個Leader兩個Replication,Leader是由zookeeper選舉產(chǎn)生,zookeeper控制每個shard上三個Core的索引數(shù)據(jù)一致,解決高可用問題。
用戶發(fā)起索引請求分別從shard1和shard2上獲取,解決高并發(fā)問題。
1.3. 需要實(shí)現(xiàn)的solr集群架構(gòu)

Zookeeper作為集群的管理工具
- 集群管理:容錯、負(fù)載均衡。
- 配置文件的集中管理
- 集群的入口
需要實(shí)現(xiàn)zookeeper 高可用。需要搭建集群。建議是奇數(shù)節(jié)點(diǎn)。需要三個zookeeper服務(wù)器。
搭建solr集群需要7臺服務(wù)器。
搭建偽分布式:
需要三個zookeeper節(jié)點(diǎn)
需要四個tomcat節(jié)點(diǎn)。
建議虛擬機(jī)的內(nèi)存1G以上。
2. 環(huán)境準(zhǔn)備
CentOS-6.5-i386-bin-DVD1.iso
jdk-7u72-linux-i586.tar.gz
apache-tomcat-7.0.47.tar.gz
zookeeper-3.4.6.tar.gz
solr-4.10.3.tgz
3. 安裝步驟
3.1 . Zookeeper集群搭建
第一步:需要安裝jdk環(huán)境。
第二步:把zookeeper的壓縮包上傳到服務(wù)器。
第三步:解壓縮。
第四步:把zookeeper復(fù)制三份。
[root@localhost ~]# mkdir /usr/local/solr-cloud
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper01
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper02
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper03
第五步:在每個zookeeper目錄下創(chuàng)建一個data目錄。
第六步:在每個data目錄下創(chuàng)建一個myid文件,文件名就叫做“myid”。內(nèi)容就是每個實(shí)例的id。例如1、2、3
[root@localhost data]# echo 1 >> myid
[root@localhost data]# ll
total 4
-rw-r--r--. 1 root root 2 Apr 7 18:23 myid
[root@localhost data]# cat myid
1
第七步:修改配置文件。把conf目錄下的zoo_sample.cfg文件改名為zoo.cfg
clientPort不能沖突,如分別配置為2181 , 2182 , 2183

第八步:啟動每個zookeeper實(shí)例。
啟動bin/zkServer.sh start
查看zookeeper的狀態(tài):
bin/zkServer.sh status
3.2. Solr集群搭建
第一步:創(chuàng)建四個tomcat實(shí)例。每個tomcat運(yùn)行在不同的端口。8180、8280、8380、8480
第二步:部署solr的war包。把單機(jī)版的solr工程復(fù)制到集群中的tomcat中。
第三步:為每個solr實(shí)例創(chuàng)建一個對應(yīng)的solrhome。使用單機(jī)版的solrhome復(fù)制四份。
第四步:需要修改solr的web.xml文件。把solrhome關(guān)聯(lián)起來。
第五步:配置solrCloud相關(guān)的配置。每個solrhome下都有一個solr.xml,把其中的ip及端口號配置好。

第六步:讓zookeeper統(tǒng)一管理配置文件。需要把solrhome/collection1/conf目錄上傳到zookeeper。上傳任意solrhome中的配置文件即可。
使用工具上傳配置文件:/root/solr-4.10.3/example/scripts/cloud-scripts/zkcli.sh目錄下的運(yùn)行
需要先啟動zookeeper
[root@localhost cloud-scripts/]# ./zkcli.sh -zkhost 192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183 -cmd upconfig -confdir /usr/local/solr-cloud/solrhome01/collection1/conf -confname myconf
查看zookeeper上的配置文件:
使用zookeeper目錄下的bin/zkCli.sh命令查看zookeeper上的配置文件:
[root@localhost bin]# ./zkCli.sh
[zk: localhost:2181(CONNECTED) 0] ls /
[configs, zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /configs
[myconf]
[zk: localhost:2181(CONNECTED) 2] ls /configs/myconf
[admin-extra.menu-top.html, currency.xml, protwords.txt, mapping-FoldToASCII.txt, _schema_analysis_synonyms_english.json, _rest_managed.json, solrconfig.xml, _schema_analysis_stopwords_english.json, stopwords.txt, lang, spellings.txt, mapping-ISOLatin1Accent.txt, admin-extra.html, xslt, synonyms.txt, scripts.conf, update-script.js, velocity, elevate.xml, admin-extra.menu-bottom.html, clustering, schema.xml]
[zk: localhost:2181(CONNECTED) 3]
退出:
[zk: localhost:2181(CONNECTED) 3] quit
第七步:修改tomcat/bin目錄下的catalina.sh 文件,關(guān)聯(lián)solr和zookeeper。
把此配置添加到配置文件中:
JAVA_OPTS="-DzkHost=192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183"

第八步:啟動每個tomcat實(shí)例。要包裝zookeeper集群是啟動狀態(tài)。
第九步:訪問集群

第十步:創(chuàng)建新的Collection進(jìn)行分片處理。
http://192.168.25.154:8180/solr/admin/collections?action=CREATE&name=collection2&numShards=2&replicationFactor=2


第十一步:刪除不用的Collection。
http://192.168.25.154:8180/solr/admin/collections?action=DELETE&name=collection1

4. 使用solrJ管理集群
pom依賴
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
</dependency>
4.1. 添加文檔
使用步驟:
第一步:把solrJ相關(guān)的jar包添加到工程中。
第二步:創(chuàng)建一個SolrServer對象,需要使用CloudSolrServer子類。構(gòu)造方法的參數(shù)是zookeeper的地址列表。
第三步:需要設(shè)置DefaultCollection屬性。
第四步:創(chuàng)建一SolrInputDocument對象。
第五步:向文檔對象中添加域
第六步:把文檔對象寫入索引庫。
第七步:提交。
@Test
public void testSolrCloudAddDocument() throws Exception {
// 第一步:把solrJ相關(guān)的jar包添加到工程中。
// 第二步:創(chuàng)建一個SolrServer對象,需要使用CloudSolrServer子類。構(gòu)造方法的參數(shù)是zookeeper的地址列表。
//參數(shù)是zookeeper的地址列表,使用逗號分隔
CloudSolrServer solrServer = new CloudSolrServer("192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183");
// 第三步:需要設(shè)置DefaultCollection屬性。
solrServer.setDefaultCollection("collection2");
// 第四步:創(chuàng)建一SolrInputDocument對象。
SolrInputDocument document = new SolrInputDocument();
// 第五步:向文檔對象中添加域
document.addField("item_title", "測試商品");
document.addField("item_price", "100");
document.addField("id", "test001");
// 第六步:把文檔對象寫入索引庫。
solrServer.add(document);
// 第七步:提交。
solrServer.commit();
}
4.2. 查詢文檔
- 簡單查詢
/**
* 查詢索引庫
*/
@Test
public void testQueryIndex() throws Exception {
// 第二步:創(chuàng)建一個SolrServer對象,需要使用CloudSolrServer子類。構(gòu)造方法的參數(shù)是zookeeper的地址列表。
//參數(shù)是zookeeper的地址列表,使用逗號分隔
CloudSolrServer solrServer = new CloudSolrServer("192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183");
// 第三步:需要設(shè)置DefaultCollection屬性。
solrServer.setDefaultCollection("collection2");
// 常見一個SolrQuery對象
SolrQuery query = new SolrQuery();
// 設(shè)置查詢條件
// query.set("q", "*:*");
query.setQuery("*:*");
// 執(zhí)行查詢
QueryResponse response = solrServer.query(query);
// 獲取查詢結(jié)果
SolrDocumentList results = response.getResults();
System.out.println("查詢結(jié)果總記錄數(shù):" + results.getNumFound());
// 遍歷查詢結(jié)果
for (SolrDocument solrDocument : results) {
System.out.println(solrDocument.get("id"));
System.out.println(solrDocument.get("product_name"));
System.out.println(solrDocument.get("product_price"));
System.out.println(solrDocument.get("product_catelog_name"));
System.out.println(solrDocument.get("product_picture"));
}
}
- 復(fù)雜查詢
/**
* 復(fù)雜查詢索引庫
*/
@Test
public void testQueryIndexFuZa() throws Exception {
// 第二步:創(chuàng)建一個SolrServer對象,需要使用CloudSolrServer子類。構(gòu)造方法的參數(shù)是zookeeper的地址列表。
//參數(shù)是zookeeper的地址列表,使用逗號分隔
CloudSolrServer solrServer = new CloudSolrServer("192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183");
// 第三步:需要設(shè)置DefaultCollection屬性。
solrServer.setDefaultCollection("collection2");
// 常見一個SolrQuery對象
SolrQuery query = new SolrQuery();
// 設(shè)置主查詢條件
query.setQuery("廚房");
// 設(shè)置過濾條件
query.addFilterQuery("product_price:[0 TO 20]");
// 根據(jù)價格排序
// 參數(shù)1:要排序的域 , 參數(shù)2:排序方式
query.setSort("product_price", ORDER.asc);
// 設(shè)置分頁
query.setStart(0);
query.setRows(6);
// 設(shè)置返回結(jié)果包含的域
query.setFields("id", "product_name", "product_price", "product_catelog_name", "product_picture");
// 設(shè)置默認(rèn)搜索域
query.set("df", "product_keywords");
// 開啟高亮
query.setHighlight(true);
// 高亮后顯示的域
query.addHighlightField("product_name");
// 高亮前綴
query.setHighlightSimplePre("<em>");
// 高亮后綴
query.setHighlightSimplePost("</em>");
// 執(zhí)行查詢
QueryResponse response = solrServer.query(query);
// 獲取查詢結(jié)果
SolrDocumentList results = response.getResults();
System.out.println("查詢結(jié)果總記錄數(shù):" + results.getNumFound());
// 遍歷查詢結(jié)果
for (SolrDocument solrDocument : results) {
System.out.println(solrDocument.get("id"));
//取高亮顯示
Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
List<String> list = highlighting.get(solrDocument.get("id")).get("product_name");
String productName = "";
if(list != null && list.size() > 0) {
productName = list.get(0);
}else {
productName = (String) solrDocument.get("product_name");
}
System.out.println(productName);
System.out.println(solrDocument.get("product_price"));
System.out.println(solrDocument.get("product_catelog_name"));
System.out.println(solrDocument.get("product_picture"));
}
}
5. 配置xml文件,把搜索功能切換到集群版
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util4.2.xsd">
<!-- 單機(jī)版solr服務(wù)配置 -->
<!-- <bean id="httpSolrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer">
<constructor-arg name="baseURL" value="http://192.168.25.154:8080/solr"></constructor-arg>
</bean> -->
<!-- 集群版solr服務(wù) -->
<bean id="cloudSolrServer" class="org.apache.solr.client.solrj.impl.CloudSolrServer">
<constructor-arg name="zkHost" value="192.168.25.154:2181,192.168.25.154:2182,192.168.25.154:2183"></constructor-arg>
<property name="defaultCollection" value="collection2"></property>
</bean>
</beans>