一、Solr是什么?
- Solr是一個開源的、獨立的、快速的、高性能、高可擴展的企業級搜索應用服務器,用于構建搜索應用程序。它是基于Lucene(全文搜索引擎)的Java搜索應用服務器(是一套war程序),是Lucene的更高一層的擴展封裝,底層使用易于擴展和修改的Java 來實現。服務器通信使用標準的HTTP 和XML。同時也易于加入到Web應用程序中。
- Solr提供了層面搜索(即統計)、命中醒目顯示并且支持多種輸出格式(包括XML/XSLT、JSON、.CSV等格式)。它易于安裝和配置,而且通過基于HTTP的webapp服務器實現可視化管理界面,方便使用人員配置、訪問和調用。Solr已經在眾多大型的網站中使用,較為成熟和穩定。
- Solr 包裝并擴展了 Lucene的Java API(即內部集成了Lucene,apache提供的一些對搜索引擎做支持的jar包),所以Solr的基本上沿用了Lucene的相關術語。更重要的是,Solr 創建的索引與 Lucene 搜索引擎庫完全兼容。
- 通過對Solr 進行適當的配置,某些情況下可能需要進行編碼,Solr 可以閱讀和使用構建到其他 Lucene 應用程序中的索引。
- 此外,很多 Lucene 工具(如Nutch、 Luke)也可以使用Solr 創建的索引。可以使用 Solr 的表現優異的基本搜索功能,也可以對它進行擴展從而滿足企業的需要。
- 使用Solr構建的應用程序非常復雜,可提供高性能。
總之,Solr是一個可擴展、可部署、搜索/存儲引擎,優化搜索大量以文本為中心的數據。
二、Solr的特性
- 高級、強大的全文搜索功能;
- 專為高通量的網絡流量進行的優化;
- 基于開放接口(XML和HTTP)的標準;
- 綜合的HTML管理界面;
- 可伸縮性 -- 能夠有效地復制到另外一個Solr搜索服務器;
- 使用XML配置達到靈活性和適配性;
- 高可擴展的插件體系;
- 高亮顯示檢索結果
- 動態集群;
- 數據庫接口和電子文檔(Word ,PDF 等)的處理;
- 數據存儲和處理;
三、Lucene是什么?
Lucene 是一個基于 Java 的全文信息檢索工具包,它不是一個完整的搜索應用程序,而是為你的應用程序提供索引和搜索功能。Lucene 目前是 Apache Jakarta(雅加達) 家族中的一個開源項目。也是目前最為流行的基于 Java 開源全文檢索工具包。目前已經有很多應用程序的搜索功能是基于 Lucene ,比如 Eclipse 幫助系統的搜索功能。Lucene 能夠為文本類型的數據建立索引,所以你只要把你要索引的數據格式轉化的文本格式,Lucene 就能對你的文檔進行索引和搜索。
四、Solr vs Lucene
Solr與Lucene 并不是競爭對立關系,恰恰相反Solr 依存于Lucene,因為Solr底層的核心技術是使用 Apache Lucene 來實現的,簡單的說Solr是Lucene的服務器化。
需要注意的是Solr 并不是簡單的對Lucene 進行封裝,它所提供的大部分功能都區別于Lucene 。
Solr和Lucene的本質區別有以下三點:搜索服務器,企業級和管理。Lucene本質上是搜索庫,不是獨立的應用程序,而Solr是。Lucene專注于搜索底層的建設,而Solr專注于企業應用。Lucene不負責支撐搜索服務所必須的管理,而Solr負責。所以說,一句話概括 Solr:
Solr是Lucene面向企業搜索應用的擴展。
Solr 和 Lucene的架構圖:(此圖是借用的別的博客上的,后面會寫上鏈接)
這個圖很繁瑣,看不懂,大家不要灰心,在后面的代碼里你就能夠了解了這個圖所講的。
不難看出,綠色的就是lucene的模塊,而藍色的就是solr擴展了lucene。從圖上可以看出以下幾點:
- 一個真正的擁有動態字段(Dynamic Field)和唯一鍵(Unique Key)的數據模式(Data Schema)
- 對Lucene查詢語言的強大擴展!
- 支持對結果進行動態的分組和過濾
- 高級的,可配置的文本分析
- 高度可配置和可擴展的緩存機制
- 性能優化
- 支持通過XML進行外部配置
- 擁有一個管理界面
- 可監控的日志
- 支持高速增量式更新(Fast incremental Updates)和快照發布(Snapshot Distribution)
五、solr兩種部署模式介紹
- Standalone Server 獨立服務器模式(單機啟動模式):適用于數據規模不大的場景;
- SolrCloud 分布式集群模式(集群啟動模式):適用于數據規模大,高可靠、高可用、高并發的場景;
solr的簡介就到此結束了,相信大家也對solr有了初步的了解,下面讓我們開始安裝、使用Solr吧,在使用過程中也順便介紹一下solr的常用屬性。
Solr軟件的安裝與使用
一、環境介紹
- 系統:Linux、Windows、MacOS;
- JDK需在JDK1.7+ 版本(運行標準Solr 服務只需要安裝JRE 即可,但如果需要擴展功能或編譯源碼則需要下載JDK 來完成。從solr6開始只能使用jdk1.8+。);
- maven需在Maven3+ 版本;
- tomcat服務器建議在tomcat7+ 版本;
- mysql數據庫需在mysql5+ 版本;
- solr需在solr4+ 版本(solr5.0以上建議tomcat服務器在tomcat8以上);
注意:
solr4.x版本的核心類及常用的屬性,和solr5.0以上的差不多,但是還有細微的區別,請注意!
我這里使用的是MacOS10.14.5、JDK1.8.0_212、Maven3、tomcat9.0.20、mysql5.7、solr8.1.1。
二、安裝Solr
- 通過brew安裝
- 通過brew安裝的,命令如下:
$ brew search solr # 搜索一下是否有可用的solr軟件
$ brew install solr # 安裝solr
- 運行以下命令,啟動Solr服務器。命令如下:
$ solr start # 開始運行Solr服務器,默認是8983端口
$ solr stop # 停止運行Solr服務器
啟動成功,說明Solr安裝成功。
- 在瀏覽器中,輸入“http://localhost:8983/solr/”訪問solr服務。出現如下圖頁面,說明服務器已經成功啟動了。
Solr Admin.png
- Solr官網下載Solr壓縮包
- 在Solr官網 下載Solr 壓縮包。
- 解壓縮Solr壓縮包到目標目錄。
- 運行solr命令啟動Solr服務器(默認是
8983
端口)。 - 在瀏覽器中,輸入“http://localhost:8983/solr/”訪問solr服務。
三、創建Core Admin/Collections
一個solr服務是可以有多個core的。
-
通過終端命令創建Core
通過終端命令的方式創建Core,會自動幫你創建基本的conf、data文件夾及相關文件、core.properties文件。創建命令如下:
$ solr create -c testdemo
- 通過Solr可視化管理界面創建Core
- 我們先要在“server/solr”目錄下創建必要的配置信息,那么讓我們先進入到solr安裝的目錄下,找到server目錄,然后進入到server下的solr 目錄(solr目錄是存放創建的Core的目錄),在solr目錄下創建一個名為
testdemo2
的文件夾,然后將server/solr/configsets/_default
目錄下的conf
文件夾及文件拷貝到testdemo2文件夾中(conf文件夾及文件可以手動創建,我這里就簡單粗暴一點了),然后再在testdemo2下創建一個名為data的空文件夾,到這里準備工作就完成了。文件結構如下:
從其他文件夾中拷貝conf文件夾及文件.png
- 在Solr可視化管理界面中,選擇
Core Admin
選項,然后點擊Add Core
按鈕,添加Core,填寫要求的基本信息。如下圖:
Add Core.png
在添加的彈窗下方有個提示信息:instanceDir and dataDir need to exist before you can create the core
,意思就是在創建Core之前要保證instanceDir和dataDir這兩個輸入框中填寫的文件夾一定是已經存在的,否則就會報錯添加失敗。
在實踐中,dataDir輸入框中填寫的data(可自定義)文件夾可以不存在,它會自動幫你創建名為data
的文件夾及其下的文件,但是其他輸入框中的文件是必須要存在的。否則報類似如下錯誤:
- 點擊
?? Add Core
按鈕,添加testdemo2核心。至此就完成了界面添加Core的過程,如下圖:
添加核心testdemo2成功.png
四、配置中文分詞器
solr雖然功能非常強大,但是solr還是存在一些不足的,下面我們就說說其中一個較大的問題那就是分詞問題,特別是中英文的混合分詞,處理起來非常棘手。在Solr中如果不配置中文分詞器,則默認是不支持中文分詞的。如圖搜索解析:
中文分詞的算法:基于字符串配置,基于統計以及機器學習的分詞方式。
這里我們使用兩種方式解決。
-
使用Solr自帶的Smartcn中文分詞器
Smartcn是Lucene自帶的一款基于統計規則來分詞的中文分詞器。
-
在
libexec?/contrib?/analysis-extras?/?lucene-libs?
目錄下找到Smartcn的jar包,如下圖:
smartcn的jar包.png -
將Smartcn的jar包拷貝到
?server?/solr-webapp?/webapp?/WEB-INF??/lib?
目錄下,如下圖:
粘貼smartcn的jar到WEB-INF:lib目錄下.png 切換到創建的Core testdemo目錄下,配置conf目錄下的managed-schema文件(模式配置文件),在文件中添加如下信息,并保存。
<fieldType name="text_cn" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory" />
</analyzer>
<analyzer type="query">
<tokenizer class="org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory" />
</analyzer>
</fieldType>
- 添加完成,在終端運行
$ solr restart -force
命令重啟solr服務。 -
回到Solr管理界面,重新加載testdemo Core。然后再次進行搜索解析,如下圖:
重新加載testdemo Core.png
-
使用IK-Analyzer中文分詞器
雖然solr自帶了支持中文分詞的Smartcn,但是其效果不是很好,擴展性比較差不能自定義擴展中文詞庫,所以推薦使用IK-Analyzer進行分詞,IK-Analyzer支持屏蔽關鍵詞、新詞匯的配置。
- 下載IK-Analyzer分詞器的jar包。然后將jar包拷貝到
server/solr-webapp/webapp/WEB-INF/lib
目錄下(如果使用了tomcat,那么該jar包應該拷貝到apache-tomcat-9.0.20/webapps/solr/WEB-INF/lib/
目錄下)。 - 配置
server/solr/testdemo/conf
目錄下的managed-schema
文件,在文件中添加如下內容:
<fieldType name="text_ik" class="solr.TextField">
<!-- 生成索引時使用的分詞器 -->
<analyzer type="index">
<tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" conf="ik.conf" />
<filter class="solr.LowerCaseFilterFactory" />
</analyzer>
<!-- 查詢時使用的分詞器 -->
<analyzer type="index">
<tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="true" conf="ik.conf" />
<filter class="solr.LowerCaseFilterFactory" />
</analyzer>
</fieldType>
- 添加完成,在終端運行
$ solr restart -force
命令重啟solr服務。 -
回到Solr管理界面,重新加載testdemo Core。然后再次進行搜索解析
IKAnalyzer搜索解析結果.png
五、DIH導入索引數據并創建索引文件
DIH簡介:
DIH全稱是Data Import Handler 數據導入處理器,顧名思義這是向solr中導入數據的,我們的solr目的就是為了能讓我們的應用程序更快的查詢出用戶想要的數據,而數據存儲在應用中的各種地方入xml、pdf、關系數據庫中,那么solr首先就要能夠獲取這些數據并在這些數據中建立索引來達成快速搜索的目的,這里就列舉我們最常用的從關系型數據庫中向solr導入索引數據。
- 使用Solr可視化管理界面到如數據
將
libexec/dist
目錄下的solr-dataimporthandler-8.1.1.jar
和solr-dataimporthandler-extras-8.1.1.jar
兩個jar包拷貝到server/solr-webapp/webapp/WEB-INF/lib
目錄下。進入testdemo Core目錄下的conf目錄,然后在
solrconfig.xml
文件中配置DIH,配置信息如下:
<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
<lst name="defaults">
<str name="config">db-dataconfig.xml</str> <!-- 數據庫配置文件的路徑,根據你的配置文件的位置填寫路徑,可是寫相對路徑,也可以寫絕對路徑 -->
</lst>
</requestHandler>
- 創建
db-dataconfig.xml
數據庫配置文件,然后配置數據庫信息,
<dataConfig>
<!-- 配置數據庫,參數之間需要用 & 連接 -->
<dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/artbase_30?useUnicode=true&characterEncoding=utf8&useSSL=false" user="xxx" password="xxx" />
<document>
<!-- 配置entity( entity的name可以隨便起),可以把它當作與數據庫中一個表對應,在query中書寫查詢sql -->
<entity name="art_course_info" query="select Member_ID,Course_Name,Add_Time from art_course_info where Member_ID=0099">
<field column="Course_ID" name="id"/>
<field column="Member_ID" name="memberID"/>
<field column="Course_Name" name="courseName"/>
<field column="Synopsis" name="synopsis"/>
<field column="Course_Photo" name="coursePhoto"/>
</entity>
</document>
</dataConfig>
注意:
這里容易與schema中的配置混淆,我的理解是schema中配置的是創建索引的配置,而索引的創建需要有數據基礎,而現在講的數據導入文件就是建立索引的數據基礎,他是創建索引的元數據。現在配置文件完成后可以用DIH命令執行了。
- 配置
managed-schema
文件,此文件中需要配置我們的業務域(即需要存儲的數據結構),配置信息如下:
<!-- 配置字段域 -->
<field name="id" type="string" indexed="false" stored="true" required="true" multiValued="false" />
<field name="memberID" type="string" indexed="true" stored="true" />
<field name="courseName" type="string" indexed="true" stored="true" />
<field name="synopsis" type="string" indexed="true" stored="true" />
<field name="coursePhoto" type="string" indexed="true" stored="true" />
<!-- 關鍵詞 定義復制域字段,將課程名稱和課程描述都復制到 course_keywords這一個字段上 -->
<field name="course_keywords" type="text" indexed="false" stored="false" multiValued="true" />
<copyField source="courseName" dest="course_keywords" />
<copyField source="synopsis" dest="course_keywords" />
注意:
配置的name的值必須與db-dataconfig.xml文件中的name一致。
- 以上文件配置完成,
重啟solr服務
。然后訪問Solr可視化管理后臺,在界面左側的下拉框中選擇testdemo
Core,然后選擇Dataimport
選項,然后選擇你的 Entity(即在db-dataconfig.xml文件中定義的entity的name) ,點擊execute
按鈕,在右側查看信息。具體如下圖:
導入數據.png
如果導如失敗,會在Raw Status-Output
下的statusMessages
參數下提示"Full Import Failed": 2019-07-05 09:11:52
。
執行導入操作后,會自動生成索引文件、日志文件和dataimport屬性文件,如下圖:
- 選擇
Query
選項,查詢導入的數據,操作如下圖:
查詢所有的數據.png
六、solrJ的集成和使用
solrJ是一個用來訪問solr的java客戶端,提供了索引和搜索的方法(將一些常用的命令封裝進去了),通過solrJ提供的API 接口來操作solr服務。
在solr5系之后跟solr4最大的區別是被發布成了一個獨立的應用。而不再需要tomcat等容器。在其內部集成了jetty服務器,他可以通過bin目錄的腳本直接運行啟動。solr5有兩種運行模式,獨立模式和云模式,獨立模式是以core來管理,云模式是以collection來管理。
-
構建solrJ應用程序
我這里使用Maven集成的solrJ 8.1.1,具體代碼如下:
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>8.1.1</version>
</dependency>
如果需要連接數據庫、注解等jar包,請自行添加依賴,這里只對solrJ做簡單的使用。
- solrJ的使用
- 創建一個名為
CourseInfo
的Entity,CourseInfo
中聲明的變量是和managed-schema
中定義的field(字段域)的name是一致的。代碼如下:
public class CourseInfo {
// 課程id
@Field("id") // 如果field中的name和entity中的變量名不一致,則需要建立映射
private String courseID;
// 會員id
@Field
private String memberID;
// 課程名稱
@Field
private String courseName;
// 課程簡介
@Field
private String synopsis;
// 課程logo
@Field
private String coursePhoto;
/**
* set / get 方法
*/
public void setCourseID(String courseID) {
this.courseID = courseID;
}
public String getCourseID() {
return courseID;
}
public void setMemberID(String memberID) {
this.memberID = memberID;
}
public String getMemberID() {
return memberID;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public String getCourseName() {
return courseName;
}
public void setSynopsis(String synopsis) {
this.synopsis = synopsis;
}
public String getSynopsis() {
return synopsis;
}
public void setCoursePhoto(String coursePhoto) {
this.coursePhoto = coursePhoto;
}
public String getCoursePhoto() {
return coursePhoto;
}
/**
* 空構造函數
*/
public CourseInfo() {}
/**
* 有參構造函數
* @param courseID
* @param memberID
* @param courseName
* @param synopsis
* @param coursePhoto
*/
public CourseInfo(String courseID, String memberID, String courseName, String synopsis,
String coursePhoto) {
super();
this.courseID = courseID;
this.memberID = memberID;
this.courseName = courseName;
this.synopsis = synopsis;
this.coursePhoto = coursePhoto;
}
}
- 創建
CourseController
,并使用solrJ。
2.1 聲明需要的常量和變量
// Solr的基鏈接
private static final String SOLR_URL = "http://localhost:8983/solr";
private static final String SOLR_CORE = "testdemo";
// 聲明solrJ客戶端
private HttpSolrClient solrClient;
2.3 創建solr客戶端的方式
// 不同solr版本solrj 的創建方式有所不同
// solr4創建方式
SolrServer solrServer = new HttpSolrServer("http://127.0.0.1:8080/solr");
// solr5創建方式,在url中指定core名稱:core1
HttpSolrClient solrServer=new HttpSolrClient("http://127.0.0.1:8080/solr/core1");
// solr7/8創建方式,在url中指定core名稱:core1
HttpSolrClient solrServer= new HttpSolrClient.Builder("http://127.0.0.1:8080/solr/core1").build();
2.2 添加/創建索引
/**
* 添加索引(創建索引)
* @param courseInfo
* @throws Exception
*/
public void addDocument(CourseInfo courseInfo) throws Exception {
// 創建solrJ客戶端實例,并指定與solr通信的連接和讀取的超時時間,不指定走默認配置
solrClient = new HttpSolrClient.Builder(SOLR_URL).withConnectionTimeout(10000).withSocketTimeout(60000).build();
// 創建SolrInputDocument,并添加
SolrInputDocument solrInputDocument = new SolrInputDocument();
// 添加內容
solrInputDocument.addField("id", "2342131");
solrInputDocument.addField("Member_ID", "10");
solrInputDocument.addField("Course_Name", "dfadf");
solrInputDocument.addField("synopsis", "簡介的方框拉風的靜安寺附近為餓哦就我if抗菌素到哪里去卡");
solrInputDocument.addField("coursePhoto", "http://www.dsdf.com/1234.png");
// 添加到client
solrClient.add(SOLR_CORE, solrInputDocument);
// 索引文檔必須commit
solrClient.commit(SOLR_CORE);
// 關閉資源
solrClient.close();
}
2.4 查詢信息
/**
* solrJ之查詢
* @param condition
* @throws Exception
*/
public void query() throws Exception {
// 創建solrJ客戶端實例,并指定與solr通信的連接和讀取的超時時間,不指定走默認配置
solrClient = new HttpSolrClient.Builder(SOLR_URL).withConnectionTimeout(10000).withSocketTimeout(60000).build();
// 封裝查詢參數
SolrQuery solrQuery = new SolrQuery("*:*");
// 添加需要回顯得內容
solrQuery.addField("id");
solrQuery.addField("courseName");
solrQuery.addField("synopsis");
// 設置每頁顯示多少條
solrQuery.setStart(0);
solrQuery.setRows(20);
// 執行查詢返回QueryResponse
QueryResponse queryResponse = solrClient.query(SOLR_CORE, solrQuery);
// 獲取doc文檔
SolrDocumentList documentList = queryResponse.getResults();
// 內容遍歷
for (SolrDocument document: documentList) {
System.out.println("courseID: " + document.get("id")
+ "\t memberID: " + document.get("memberID")
+ "\t courseName: " + document.get("courseName")
+ "\t synopsis: " + document.get("synopsis")
+ "\t coursePhoto: " + document.get("coursePhoto"));
}
// 關閉資源
solrClient.close();
}
2.5 刪除數據
/**
* solrJ之單個id 的刪除索引(一)
* @param id
* @throws Exception
*/
public void deleteById(String id) throws Exception {
// 創建solrJ客戶端實例,并指定與solr通信的連接和讀取的超時時間,不指定走默認配置
solrClient = new HttpSolrClient.Builder(SOLR_URL).withConnectionTimeout(10000).withSocketTimeout(60000).build();
// 通過id刪除
solrClient.deleteById("1002");
// 提交
solrClient.commit(SOLR_CORE);
// 關閉資源
solrClient.close();
}
/**
* solrJ之多個id 的list集合 刪除索引(二)
* @param id
* @throws Exception
*/
public void deleteById2(String id) throws Exception {
// 創建solrJ客戶端實例,并指定與solr通信的連接和讀取的超時時間,不指定走默認配置
solrClient = new HttpSolrClient.Builder(SOLR_URL).withConnectionTimeout(10000).withSocketTimeout(60000).build();
// 通過多個id刪除
ArrayList<String> ids = new ArrayList<String>();
ids.add("1002");
ids.add("1003");
solrClient.deleteById(SOLR_CORE, ids);
// 提交
solrClient.commit(SOLR_CORE);
// 關閉資源
solrClient.close();
}
/**
* solrJ之通過deleteByQuery刪除索引(三)
* @param query
* @throws Exception
*/
public void deleteByQuery(String query) throws Exception {
// 創建solrJ客戶端實例,并指定與solr通信的連接和讀取的超時時間,不指定走默認配置
solrClient = new HttpSolrClient.Builder(SOLR_URL).withConnectionTimeout(10000).withSocketTimeout(60000).build();
// 執行刪除
solrClient.deleteByQuery(SOLR_CORE, "id:1002");
// 提交操作
solrClient.commit(SOLR_CORE);
// 關閉資源
solrClient.close();
}
參考文章:
solr教程
Solr Apache Solr 初級教程(介紹、安裝部署、Java接口、中文分詞)
項目中如何使用solr
solr-部署詳解(solr兩種部署模式介紹、獨立服務器模式詳解、SolrCloud分布式集群模式詳解)
Centos7安裝配置單機solr-8.1.1+ik-analyzer8.1.0+mysql中文分詞