solr7 簡介、安裝、使用

一、solr簡介(需要整理 總結)

 

首先Solr是基於Lucene做的,Solr的目標是打造一款企業級的搜索引擎系統,因此它更接近於我們認識到的搜索引擎系統,它是一個搜索引擎服務,通過各種API可以讓你的應用使用搜索 服務,而不需要將搜索邏輯耦合在應用中。而且Solr可以根據配置文件定義數據解析的方式,更像是一個搜索框架,它也支持主從、熱換庫等操作。

solr還是一種開放源碼的、基於 Lucene Java 的搜索服務器,易於加入到 Web 應用程序中。Solr 提供了層面搜索(就是統計)、命中醒目顯示並且支持多種輸出格式(包括XML/XSLT 和JSON等格式)。它易於安裝和配置,而且附帶了一個基於HTTP 的管理界面。可以使用 Solr 的表現優異的基本搜索功能,也可以對它進行擴展從而滿足企業的需要。Solr的特性包括:

  • 高級的全文搜索功能
  • 專爲高通量的網絡流量進行的優化
  • 基於開放接口(XML和HTTP)的標準
  • 綜合的HTML管理界面
  • 可伸縮性-能夠有效地複製到另外一個Solr搜索服務器
  • 使用XML配置達到靈活性和適配性
  • 可擴展的插件體系

Solr 必須運行在Java1.6 或更高版本的Java 虛擬機中,運行標準Solr 服務只需要安裝JRE 即可,但如果需要擴展功能或編譯源碼則需要下載JDK 來完成。

Solr 是一個開源的企業級搜索服務器,底層使用易於擴展和修改的Java 來實現。服務器通信使用標準的HTTP 和XML,所以如果使用Solr 瞭解Java 技術會有用卻不是必須的要求

文檔通過Http利用XML 加到一個搜索集合中。查詢該集合也是通過http收到一個XML/JSON響應來實現。它的主要特性包括:高效、靈活的緩存功能,垂直搜索功能,高亮顯示搜索結果,通過索引複製來提高可用性,提供一套強大Data Schema來定義字段,類型和設置文本分析,提供基於Web的管理界面等。

二、Solr緩存

 

緩存在 Solr 中充當了一個非常重要的角色,Solr 中主要有這三種緩存:

  • Filter cache(過濾器緩存),用於保存過濾器(fq 參數)和層面搜索的結果
  • Document cache(文檔緩存),用於保存 lucene 文檔存儲的字段
  • Query result(查詢緩存),用於保存查詢的結果
  • 還有第四種緩存,lucene 內部的緩存,不過該緩存外部無法控制到。

通過這 3 種緩存,可以對 solr 的搜索實例進行調優。調整這些緩存,需要根據索引庫中文檔的數量,每次查詢結果的條數等。

在調整參數前,需要事先得到 solr 示例中的以下信息: 索引中文檔的數量 每秒鐘搜索的次數 過濾器的數量 一次查詢返回最大的文檔數量,不同查詢和不同排序的個數,這些數量可以在 solr admin 頁面的日誌模塊找到。

假設以上的值分別爲:

索引中文檔的數量:1000000

每秒鐘搜索的次數:100

過濾器的數量:200

一次查詢返回最大的文檔數量:100

不同查詢和不同排序的個數:500

然後可以開始修改 solrconfig.xml 中緩存的配置了

第一個是過濾器緩存:

第二個是查詢結果緩存:

第三個是文檔緩存:

這幾個配置是基於以上的幾個假設 的值進行調優的。

三、solr 安裝

1.安裝背景概要

因爲solr7+ 新增了誇核(solr 跨核概念,是建立在,solr存儲方式的基礎上,因爲使用solr前必須創建Core,Core即爲solr的核,那不同的業務有可能在不同的核中,之前版本是不支持跨核搜索的)搜索功能,寫法如下:

shards=localhost:9095/solr/core0,localhost:9095/solr/core1 ,因爲跨核的功能有可能在實際業務場景中應用到,所以本次是對 Solr7.1.0 安裝部署。在安裝 solr前需要安裝jdk1.8或以上版本,這裏選用tomcat作爲solr的容器,tomcat也建議使用8.0或以上版本

2.下載

關於jdk,tomcat的安裝就不在本文複述,見下鏈接。

jdk1.8 下載與安裝: https://blog.csdn.net/yx1214442120/article/details/55098380

 

tomcat8 下載與安裝:http://tomcat.apache.org/download-80.cgi ,注意系統兼容,我這裏選擇64位Windows,解壓後配置環境變量,因爲 tomcat默認8080端口容易與oracle 衝突,把端口號改爲8888,地址爲http://localhost:8888/。(5以後就不需要依賴tomcat了,這裏 還採用tomcat 是爲了部署linux 時候可以同樣套用該步驟)

solr7.1.0 下載 (包含過往版本) :http://archive.apache.org/dist/lucene/solr/

 

3. solr7.1.0 安裝(以下步驟都不可省略,請認真按步驟執行~)

3.1 解壓出solr-7.1.0,將 solr 壓縮包中 solr-7.1.0\server\solr-webapp\文件夾下有個webapp文件夾,將之複製到Tomcat\webapps\目錄下,並改成solr (名稱隨意,爲了後面訪問方便,改爲solr).

3.2 在E盤(根據實際情況)新建一個文件夾:solrhome ,回到tomcat的webapps目錄下,打開tomcat\webapps 下 solr\WEB-INF\web.xml文件。在web-app節點中加入以下代碼,env-entry-value 目錄可根據實際情況自行更替:

<env-entry> <env-entry-name>solr/home</env-entry-name> <env-entry-value>E:\solrhome</env-entry-value> <env-entry-type>java.lang.String</env-entry-type> </env-entry>

* 把 security-constraint 整個標籤註釋:

<!-- <security-constraint>

<web-resource-collection>

<web-resource-name>Disable TRACE</web-resource-name>

<url-pattern>/</url-pattern>

<http-method>TRACE</http-method>

</web-resource-collection>

<auth-constraint/>

</security-constraint>

<security-constraint>

<web-resource-collection>

<web-resource-name>Enable everything but TRACE</web-resource-name>

<url-pattern>/</url-pattern>

<http-method-omission>TRACE</http-method-omission>

</web-resource-collection>

</security-constraint>-->

3.3 將 solr-7.1.0\server\lib\ext 所有jar包,以及solr-7.1.0\server\lib 下 metrics 相關的jar ,以及solr-7.1.0\dist 下 solr-dataimporthandler 相關的jar複製到tomcat的webapps\solr\WEB-INF\lib下

3.4 在tomcat-8.5.31\webapps\solr\WEB-INF 下新建 classes文件夾。然後將solr-7.1.0\server\resources 下 log4j.properties 複製到 classes文件夾中。

3.5 回到解壓的solr-7.1.0目錄,打開文件夾:solr-7.1.0\server\solr,複製所有內容到E:\solrhome,把 solr-7.1.0 下 dist和contrib 文件夾 複製到 E:\solrhome下。 這樣solrhome就和tomcat中的solr 完成了加載關聯。

3.6 運行 apache-tomcat\bin 下 startup.bat 啓動tomcat,看到一下日誌說明啓動成功了。

3.7 訪問solr http://localhost:8888/solr/index.html ,見到如下頁面纔算真正安裝成功。

3.8 下面介紹兩種新建核心的方法,第一種: 下圖新建testCore,這時候可以根據業務,架構創建多個核心,這裏就體現了爲什麼我們要用7+版本的solr ,就是因爲 7+版本支持多核心搜索。這裏需要注意的是,並不是全自動創建~還需要你先建好文件夾,把solrconfig.xml丟進去才行,所以這裏不建議這種方式創建。不過你可以點一下試一試~

第二種 :不通過web頁面,直接手動配置。在 E:\solrhome 下新建testCore/conf

將solr-7.1.0\server\solr\configsets\_default\conf 下所有文件放置到 新建的testCore/conf 下

然後修改 solrconfig.xml ,可以用相對路徑,或者絕對路徑。這裏用了絕對路徑。

<lib dir="E:/solrhome/contrib/extraction/lib" regex=".*\.jar" />

<lib dir="E:/solrhome/dist/" regex="solr-cell-\d.*\.jar" />

<lib dir="E:/solrhome/contrib/clustering/lib/" regex=".*\.jar" />

<lib dir="E:/solrhome/dist/" regex="solr-clustering-\d.*\.jar" />

<lib dir="E:/solrhome/contrib/langid/lib/" regex=".*\.jar" />

<lib dir="E:/solrhome/dist/" regex="solr-langid-\d.*\.jar" />

<lib dir="E:/solrhome/contrib/velocity/lib" regex=".*\.jar" />

<lib dir="E:/solrhome/dist/" regex="solr-velocity-\d.*\.jar" />

然後在solrhome\testCore下新建data文件見。顧名思義這裏放數據的,當然是無法看懂的文件。關於底層的實現方式,見如下鏈接 ,講的比較清晰

https://blog.csdn.net/u014209975/article/details/53263642

這時候還需要 在 solrhome\testCore ,新建  core.properties 文件,寫入以下內容(注意這裏有坑 config=conf/solrconfig.xml後面不能有空格 否則啓動會報錯):

#Written by CorePropertiesLocator

#Sat May 26 16:41:44 CST 2018

name=testCore

config=conf/solrconfig.xml

schema=conf/managed-schema

dataDir=data

3.9 重啓tomcat,再訪問首頁,就可以選擇我們新建的testCore了,後面再建core,可以直接複製這一份改改~我老是把core 打成code~ 真是天生的程序員。這是我的testCode手動創建的。以前用過solr 的朋友可能會發現,conf下面沒有schema.xml,1.6以前是schema.xml ,之後版本用的是managed-schema與schema.xml 基本一致,之後所有提到managed-schema都等同於schema.xml。

 

4.solr 的配置文件

solr 最主要的配置文件就是上面提到過的solrconfig.xml 以及managed-schema,要對這兩個文件有一定的瞭解,尤其是managed-schema ,才能真正的把solr應用到業務中。

4.1 solrconfig.xml , solrconfig.xml配置文件主要定義了solr的一些處理規則,包括索引數據的存放位置,更新,刪除,查詢的一些規則配置。相當於是基礎配置文件。值得注意的是,文件中不能有中文。~否則會報錯,註釋也不行

4.2 managed-schema是在使用solr建立core時的配置(core連接配置和索引庫),solr根據它確定如何對文檔建立索引到索引庫中,每個core在建立前都需要設計好managed-schema。

詳細的配置講解,網上非常多,也非常專業,就不贅述了,提供一個我之前參考的鏈接,solrconfig.xml 以及 managed-schema 詳細介紹見: https://blog.csdn.net/vtopqx/article/details/73224510

 

5.solr 的使用

5.1數據導入

5.1.1上面已經介紹了core的創建,下面說下怎麼導入數據。在solrhome\testCore\conf下 創建文件data-config.xml,寫入如下內容:

<dataConfig>

<dataSource type="JdbcDataSource"

driver="com.mysql.jdbc.Driver"

url="jdbc:mysql://123.59.41.168:3306/db_yxj_studio"

user="yxj"

password="yxj@2015" />

<document>

<entity name="solr_test" transformer="DateFormatTransformer"

query="SELECT sbtid as id ,master_intro, tags, srpid, department FROM t_subject WHERE sbtid >= ${dataimporter.request.sbtid}">

</entity>

</document>

</dataConfig>

dataConfig 標籤中,子標籤,dataSource 配置數據源,上面是以mysql爲例,配置了數據源。其中entity 標籤 定義了 操作名稱,以及sql ,其中${dataimporter.request.id}

中自定義了id字段,值得注意的是必須指定id字段,因爲我使用的表中沒有ID 所以 我使用了as的寫法。另外還有一點,要把sql中用到的字段名,在managed-schema中進行編寫fields。以我的sql爲例,managed-schema寫法如下。

<!-- 自定義字段-->

<!-- t_subject -->

<field name="sbtid" type="plong" indexed="true" stored="true"/>

<field name="master_intro" type="string" indexed="true" stored="true"/>

<field name="tags" type="string" indexed="true" stored="true"/>

<field name="srpid" type="plong" indexed="true" stored="true"/>

<field name="department" type="string" indexed="true" stored="true"/>

 

5.1.2接下來把solrhome\testCore\conf 下的 solrconfig.xml,寫入如下內容:

<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler"> <lst name="defaults"> <str name="config">data-config.xml</str> </lst> </requestHandler>

5.1.3最後 把數據庫驅動丟到apache-tomcat\webapps\solr\WEB-INF\lib 中 ,如果你使用的pgSql 就丟對應的jar~

 

5.1.4重啓tomcat ,導入數據,並檢索,見下圖

 

導入成功

 

5.1.5 檢索,見下圖,整個solr 安裝、配置、使用 就都OK了。最後對查詢語法介紹,引用如下:

https://blog.csdn.net/zhufenglonglove/article/details/51518846

 

 

 

6.solr 分詞器

6.1 K分詞器,因爲IK是開源的分詞器,也支持擴展,網上分詞器很多,使用方法也大同小異。首先要下載IK的jar包。solr7.0+要用5.0+的IK分詞器。

IKAnalyzer2012FF_u1-6.51.jar

可以私信我,CSDN不能,上傳JAR~

6.2 把IK jar包放到放到apache-tomcat\webapps\solr\WEB-INF\lib 下,配置solrhome\testCore\conf 下的managed-schema 文件 ,分別寫入

<field name="text_ik" type="text_ik" indexed="true" stored="true" multiValued="true" />

<!-- copyField就引出了solr的一個全文檢索的概念,如果我要實現一個搜索,而我要搜索的屬性有很多個那麼應該使用如下配置方法-->

<copyField source="master_intro" dest="text_ik"/>

<copyField source="tags" dest="text_ik"/>

<copyField source="department" dest="text_ik"/>

<!--IK分詞器 -->

<fieldType name="text_ik" class="solr.TextField" positionIncrementGap="100">  
         <analyzer type="index">    
            <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" />       
         </analyzer>    
         <analyzer type="query">    
             <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" />     
         </analyzer>    
    </fieldType>  

1.其中useSmart是指分詞的細粒度,可以分別制定index索引和query查詢的分詞細粒度,建議將index的useSmart設置爲false,這樣就採用最細分詞,是索引更精確,查詢時儘量能匹配,而將query的useSmart設置爲true,採用最大分詞,這樣能夠使查詢出來的結果更符合用戶的需求。

2.positionIncrementGap 一個doc中的屬性有多個值時候,設置每個屬性之間的增量值和multiValued屬性配合使用(避免錯誤匹配)。

6.3重啓tomcat

 

這裏是未使用分詞器的效果。

 

選用IK分詞以後,效果很明顯

 

7.solr 與springboot 的集成(這裏有坑)

7.1 通過solrj 來操作solr,maven 引入 。 注意一下 ,JAR衝突的問題,我發現spring-boot-starter-test 包含的 spring-test-4.3.6.RELEASE 包下面 和solr7.1.0有衝突 ,爲了解決這個問題,只能放棄最新的solr-solrj jar 的使用,改用5.3之後的版本,切兼容springboot的。 等日後springboot升級在做更替。我試驗了 老版本不影響solr的使用。是指在7.1.0版本 有一些方法是棄用的。但還是兼容的。如果你使用的是springMvc可以嘗試用最新版本的jar包。

一般,我都會在這裏找jar: http://mvnrepository.com/

 

 

 

<!--solr客戶端solrj的依賴 -->

<dependency>

<groupId>org.apache.solr</groupId>

<artifactId>solr-solrj</artifactId>

<!--<version>7.1.0</version>-->

</dependency>

7.2 java 實現 增刪改查 ,這裏我用多線程測試過,100W數據用我的破機器,3分鐘就跑完了。

相關參數

#solr

#服務器地址

solr.httpSolrClientUrl=http://localhost:8888/solr/

#等待結果超時 這個參數設定的是HTTP連接成功後,等待讀取數據或者寫數據的最大超時時間,單位爲毫秒 如果設置爲0,則表示永遠不會超時

solr.soTimeOut=5000

#接超時時間 HTTP 超時時間 單位爲毫秒 如果設置爲0,則表示永遠不會超時

solr.connectionTimeout=1000

package com.ysz.studio.solr.service;

import java.util.List;
import java.util.Map;

import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;

public interface SolrService {

    
    /**
     * 按條件查詢搜索引擎
     * 
     * @author  [email protected]
     * @param coreName
     * @param query
     * @return
     * @since
     */
    public SolrDocumentList querySolrIndex(String coreName, String query);
    
    /**
     * 向solr插入數據
     * 
     * @author  [email protected]
     * @param coreName
     * @param input
     * @return
     * @since
     */
    public boolean pushDataIntoSolr(String coreName, List<SolrInputDocument> input);


    /**
     * 根據ID 刪除數據
     * 
     * @author [email protected]
     * @param coreName
     * @param ids
     * @return
     * @since
     */
    public boolean deleteSolrByIds(String coreName, List<String> ids);
    
    /**
     * 
     * 
     * @author  [email protected]
     * @param coreName
     * @param id
     * @param maps 屬性名稱,屬性值鍵值對
     * @return
     * @since
     */
    public boolean updateSolrById(String coreName, String id, Map<String, String> maps);

}
package com.ysz.studio.solr.service.impl;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.ysz.studio.solr.service.SolrService;

@Service
public class SolrServiceImpl implements SolrService {

    private Logger logger = LoggerFactory.getLogger(SolrServiceImpl.class);

    @Value("${solr.httpSolrClientUrl}")
    private String httpSolrClientUrl;
    // 這個參數設定的是HTTP連接成功後,等待讀取數據或者寫數據的最大超時時間,單位爲毫秒 如果設置爲0,則表示永遠不會超時
    @Value("${solr.soTimeOut}")
    private int soTimeOut;
    // HTTP 超時時間 單位爲毫秒 如果設置爲0,則表示永遠不會超時
    @Value("${solr.connectionTimeout}")
    private int connectionTimeout;

    private static HttpSolrClient solr;


    private HttpSolrClient connetHttpSolrClientServer(String coreName) {
        HttpSolrClient httpSolrClient = new HttpSolrClient(httpSolrClientUrl + coreName);
        httpSolrClient.setConnectionTimeout(connectionTimeout);
        httpSolrClient.setSoTimeout(soTimeOut);
        // solr服務器地址+庫   JAR包 衝突 導致 無法使用最新的 方法
        // new HttpSolrClient.Builder(httpSolrClientUrl +
        // coreName).withConnectionTimeout(connectionTimeout).withSocketTimeout(soTimeOut).build();
        return httpSolrClient;
    }
    
    @Override
    public boolean pushDataIntoSolr(String coreName, List<SolrInputDocument> input) {
        boolean flag = false;
        try {
            solr = this.connetHttpSolrClientServer(coreName);
            
            solr.add(input);
            solr.commit();
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
        } finally {
            try {
                solr.close();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e.getMessage());
            }
        }
        return flag;
    }


    @Override
    public SolrDocumentList querySolrIndex(String coreName, String query) {
        SolrDocumentList list = null;
        try {
            solr = this.connetHttpSolrClientServer(coreName);
            QueryResponse rsp = null;
            SolrQuery queryStr = new SolrQuery(query);

            // 高亮顯示 start
//            queryStr.setHighlight(true); // 開啓高亮組件或用query.setParam("hl", "true");
//            queryStr.addHighlightField("master_intro");// 高亮字段
//            queryStr.setHighlightSimplePre("<font color='red'>");// 標記,高亮關鍵字前綴
//            queryStr.setHighlightSimplePost("</font>");// 後綴
            /*
             * 獲取高亮分片數,一般搜索詞可能分佈在文章中的不同位置,其所在一定長度的 語句即爲一個片段,默認爲1,但根據業務需要有時候需要多取出幾個分片。 -
             * 此處設置決定下文中titleList, contentList中元素的個數
             **/
            // queryStr.setHighlight(true).setHighlightSnippets(1);
            /*
             * 每個分片的最大長度,默認爲100。 適當設置此值,如果太小,高亮的標題可能會顯不全; 設置太大,摘要可能會太長。
             **/
            // queryStr.setHighlightFragsize(150);
            // 高亮顯示 end

            // 指定返回哪些字段,用逗號或空格分隔,注意:字段區分大小寫,例如,fl= id,title,sort
            // queryStr.addField(field);

            // 返回結果的第幾條記錄開始,一般分頁用,默認0開始
            // queryStr.setStart((Math.max(page, 1) - 1) * rows);
            // // 指定返回結果最多有多少條記錄,默認值爲 10,配合start實現分頁
            // queryStr.setRows(rows);

            // 排序方式,例如id desc 表示按照 “id” 降序
            // List<SortClause> sortList = new ArrayList<SortClause>();
            // SortClause s = new SortClause("", ORDER.asc);
            // sortList.add(s);
            // queryStr.setSorts(sortList);

            // 過慮查詢,提供一個可選的篩選器查詢。返回在q查詢符合結果中同時符合的fq條件的查詢結果,例如:q=id:1&fq=sort:[1 TO 5],找關鍵字id爲1
            // 的,並且sort是1到5之間的。
            // queryStr.setFilterQueries(fq);

            // 默認的查詢字段,一般默認指定。
            // queryStr.set("df", "master_intro");
            // 指定返回結果字段。以空格“ ”或逗號“,”分隔。
//            queryStr.set("fl", "master_intro");
            rsp = solr.query(queryStr);
            list = rsp.getResults();
        } catch (IOException | SolrServerException e) {
            e.printStackTrace();
            logger.error(e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
        } finally {
            try {
                solr.close();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e.getMessage());
            }
        }
        return list;
    }


    
    @Override
    public boolean deleteSolrByIds(String coreName, List<String> ids) {
        boolean flag = false;
        try {
            solr = this.connetHttpSolrClientServer(coreName);
            solr.deleteById(ids);
            solr.commit();
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
        } finally {
            try {
                solr.close();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e.getMessage());
            }
        }
        return flag;
    }

    @Override
    public boolean updateSolrById(String coreName, String id, Map<String, String> maps) {
        boolean flag = false;
        try {
            solr = this.connetHttpSolrClientServer(coreName);
            Set<String> keys = maps.keySet();
            SolrInputDocument doc = new SolrInputDocument();
            doc.addField("id", id);
            for (String key : keys) {
                HashMap<String, Object> oper = new HashMap<String, Object>();
                oper.put("set", maps.get(key));
                doc.addField(key, oper);
            }
            solr.add(doc);
            solr.commit();
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error(e.getMessage());
        } finally {
            try {
                solr.close();
            } catch (IOException e) {
                e.printStackTrace();
                logger.error(e.getMessage());
            }
        }
        return flag;
    }



}


 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章