Solr快速入門

1. 什麼是Solr

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應用,咱們更多的工做不是編碼而是配置。數據庫

2. Solr的安裝與配置

解壓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文件

 

3. 經過SolrJ訪問Solr

維護索引:

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"));
        }
    }
}

 

4. SolrCloud的搭建與訪問

Solr集羣須要用到多個solr與多個zookeeper

這裏搭一個以下的簡單架構做爲例子

zookeeper在這個集羣的做用:

1. 集羣管理. 負責solr的主從關係, 負載均衡, 做爲外界訪問集羣的入口. 爲了保證高可用, zookeeper自身也必須是集羣. 爲使選舉和投票有效, zookeeper至少須要三個節點.

2.配置文件管理. 各solr配置文件相同, 將配置文件上傳給zookeeper統一管理, 每一個solr節點都到zookeeper上取配置.

若是在一臺主機上搭建集羣, 注意避免端口衝突.

4.1 搭建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

4.2 搭建solr集羣

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

4.3 使用SolrJ訪問集羣

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, 使用上和單機版沒有任何區別. 集羣對客戶端來講的封閉的.

相關文章
相關標籤/搜索