全文搜索引擎Solr原理和实战教程
Solr簡介
1.Solr是什么?
Solr它是一種開放源碼的、基于 Lucene Java 的搜索服務器,易于加入到 Web 應用程序中。Solr 提供了層面搜索(就是統計)、命中醒目顯示并且支持多種輸出格式(包括XML/XSLT 和JSON等格式)。Solr是一個高性能,采用Java開發,
基于Lucene的全文搜索服務器。同時對其進行了擴展,提供了比Lucene更為豐富的查詢語言,同時實現了可配置、可擴展并對查詢性能進行了優化,并且提供了一個完善的功能管理界面,是一款非常優秀的全文搜索引擎。
Solr是一個獨立的企業級搜索應用服務器,它對外提供類似于Web-service的API接口。用戶可以通過http請求,向搜索引擎服務器提交一定格式的XML文件,生成索引;也可以通過Http Get操作提出查找請求,并得到XML格式的返回結果。
Solr易于安裝和配置,而且附帶了一個基于HTTP 的管理界面。可以使用 Solr 的表現優異的基本搜索功能,也可以對它進行擴展從而滿足企業的需要。
Solr架構圖
Solr的特性
高效、靈活的緩存功能,垂直搜索功能,高亮顯示搜索結果,通過索引復制來提高可用性,提供一套強大Data Schema來定義字段,類型和設置文本分析,提供基于Web的管理界面等.
· 高級的全文搜索功能
· 專為高通量的網絡流量進行的優化
· 基于開放接口(XML和HTTP)的標準
· 綜合的HTML管理界面
· 可伸縮性-能夠有效地復制到另外一個Solr搜索服務器
· 使用XML配置達到靈活性和適配性
· 可擴展的插件體系
2. Lucene 是什么?
Lucene是一個基于Java的全文信息檢索工具包,它不是一個完整的搜索應用程序,而是為你的應用程序提供索引和搜索功能。Lucene 目前是 Apache Jakarta(雅加達) 家族中的一個開源項目。也是目前最為流行的基于Java開源全文檢索工具包。目前已經有很多應用程序的搜索功能是基于 Lucene ,比如Eclipse 幫助系統的搜索功能。Lucene能夠為文本類型的數據建立索引,所以你只要把你要索引的數據格式轉化的文本格式,Lucene 就能對你的文檔進行索引和搜索。
3. Solr vs Lucene
Solr與Lucene 并不是競爭對立關系,恰恰相反Solr 依存于Lucene,因為Solr底層的核心技術是使用Lucene 來實現的,Solr和Lucene的本質區別有以下三點:搜索服務器,企業級和管理。Lucene本質上是搜索庫,不是獨立的應用程序,而Solr是。Lucene專注于搜索底層的建設,而Solr專注于企業應用。Lucene不負責支撐搜索服務所必須的管理,而Solr負責。所以說,一句話概括 Solr: Solr是Lucene面向企業搜索應用的擴展。
Solr與Lucene架構圖:
Solr使用Lucene并且擴展了它!
· 一個真正的擁有動態字段(Dynamic Field)和唯一鍵(Unique Key)的數據模式(Data Schema)
· 對Lucene查詢語言的強大擴展!
· 支持對結果進行動態的分組和過濾
· 高級的,可配置的文本分析
· 高度可配置和可擴展的緩存機制
· 性能優化
· 支持通過XML進行外部配置
· 擁有一個管理界面
· 可監控的日志
· 支持高速增量式更新(Fast incremental Updates)和快照發布(Snapshot Distribution)
下載安裝
下載
https://mirrors.tuna.tsinghua.edu.cn/apache/lucene/solr/8.5.1/solr-8.5.1.tgz
解壓即可.目錄結構:
啟動命令
- cd ~/solr/bin 回車
- solr start -p 8983 回車,等待啟動成功
- solr stop -p 8983 這個是停止solr命令
啟動成功后,訪問 http://127.0.0.1:8983/solr/#/
可以看到Solr的管理界面:
JVM Runtime Oracle Corporation Java HotSpot(TM) 64-Bit Server VM 1.8.0_40 25.40-b25 Processors 12 Args -DSTOP.KEY=solrrocks-DSTOP.PORT=7983-Djetty.home=/Users/jack/soft/solr-8.5.1/server-Djetty.port=8983-Dsolr.data.home=-Dsolr.default.confdir=/Users/jack/soft/solr-8.5.1/server/solr/configsets/_default/conf-Dsolr.install.dir=/Users/jack/soft/solr-8.5.1-Dsolr.jetty.https.port=8983-Dsolr.jetty.inetaccess.excludes=-Dsolr.jetty.inetaccess.includes=-Dsolr.log.dir=/Users/jack/soft/solr-8.5.1/server/logs-Dsolr.log.muteconsole-Dsolr.solr.home=/Users/jack/soft/solr-8.5.1/server/solr-Duser.timezone=UTC-XX:+AlwaysPreTouch-XX:+ParallelRefProcEnabled-XX:+PerfDisableSharedMem-XX:+PrintGCApplicationStoppedTime-XX:+PrintGCDateStamps-XX:+PrintGCDetails-XX:+PrintGCTimeStamps-XX:+PrintHeapAtGC-XX:+PrintTenuringDistribution-XX:+UseG1GC-XX:+UseGCLogFileRotation-XX:+UseLargePages-XX:GCLogFileSize=20M-XX:MaxGCPauseMillis=250-XX:NumberOfGCLogFiles=9-XX:OnOutOfMemoryError=/Users/jack/soft/solr-8.5.1/bin/oom_solr.sh 8983 /Users/jack/soft/solr-8.5.1/server/logs-Xloggc:/Users/jack/soft/solr-8.5.1/server/logs/solr_gc.log-Xms512m-Xmx512m-Xss256k-verbose:gc啟動并重新啟動 Solr
您可以使用 start 命令來啟動 Solr,使用 restart 命令允許您在 Solr 已經運行或者已經停止的情況下重新啟動 Solr。
該 start 和 restart 命令有多種選擇,讓您在 SolrCloud 模式下運行,使用一個示例配置集,從一個不是默認的主機名或端口開始并指向本地的 ZooKeeper 集合。
bin/solr start [options] bin/solr start -help bin/solr restart [options] bin/solr restart -help使用 restart 命令時,必須傳遞您在啟動 Solr 時最初傳遞的所有參數。在幕后,啟動了一個停止請求,所以 Solr 將在被再次啟動之前停止。如果沒有節點已經運行,則重新啟動將跳過此步驟停止并繼續啟動 Solr。
啟動參數
bin/solr 腳本提供了許多選項,允許您以常見的方式自定義服務器,例如更改偵聽端口。但是,大多數默認設置對于大多數 Solr 安裝都是足夠的,特別是剛開始時。
-a "<string>"
使用額外的 JVM 參數(例如以 -X 開頭的參數)啟動 Solr。如果您正在傳遞以 “-D” 開頭的 JVM 參數,則可以省略 -a 選項。例如:
bin/solr start -a "-Xdebug -Xrunjdwp:transport=dt_socket, server=y,suspend=n,address=1044"-cloud
以 SolrCloud 模式啟動 Solr,該模式也將啟動 Solr 附帶的嵌入式 ZooKeeper 實例。
這個選項可以簡單地縮短為-c。
如果您已經在運行您想要使用的 ZooKeeper 集合,而不是嵌入式(單節點)ZooKeeper,則還應該傳遞 -z 參數。
有關更多詳細信息,請參閱下面的 SolrCloud 模式部分。例如:
bin/solr start -c -d <dir>定義一個服務器目錄,默認為server(如,$SOLR_HOME/server)。重寫此選項的情況并不常見。在同一臺主機上運行多個 Solr 實例時,更常見的是為每個實例使用相同的服務器目錄,并使用 -s 選項使用唯一的Solr主目錄更為常見。例如:
bin/solr start -d newServerDir應用示例
Building and Running SolrJ Applications: put the following dependency in the project’s pom.xml:
<dependency><groupId>org.apache.solr</groupId><artifactId>solr-solrj</artifactId><version>x.y.z</version> </dependency>Single node Solr client
String urlString = "http://localhost:8983/solr/techproducts"; SolrClient solr = new HttpSolrClient.Builder(urlString).build();SolrCloud client
// Using a ZK Host String String zkHostString = "zkServerA:2181,zkServerB:2181,zkServerC:2181/solr"; SolrClient solr = new CloudSolrClient.Builder().withZkHost(zkHostString).build();// Using already running Solr nodes SolrClient solr = new CloudSolrClient.Builder().withSolrUrl("http://localhost:8983/solr").build();Once you have a SolrClient, you can use it by calling methods like query(), add(), and commit().
客戶端API簡介
Solr的核心是一個Web應用程序,但是由于它是建立在開放的協議之上的,任何類型的客戶端應用程序都可以使用Solr。
HTTP是客戶端應用程序和Solr之間使用的基本協議。客戶端提出請求,Solr做一些工作并提供響應。客戶使用請求來請求Solr執行查詢或索引文件等操作。
客戶端應用程序可以通過創建HTTP請求和解析HTTP響應到達Solr。客戶端API封裝了發送請求和解析響應的大部分工作,這使得編寫客戶端應用程序變得更加容易。
客戶使用Solr的五個基本操作來與Solr一起工作。這五個操作分別是:查詢、索引、刪除、提交和優化。
查詢通過創建一個包含所有查詢參數的URL來執行。Solr檢查請求URL,執行查詢并返回結果。其他操作是相似的,雖然在某些情況下,HTTP請求是一個POST操作,并包含除請求URL中包含的任何信息之外的信息。例如,索引操作可能包含請求正文中的文檔。
Solr 還具有一個 EmbeddedSolrServer,它提供了一個 Java API 而不需要 HTTP 連接。
Setting XMLResponseParser
SolrJ uses a binary format, rather than XML, as its default response format. If you are trying to mix Solr and SolrJ versions where one is version 1.x and the other is 3.x or later, then you MUST use the XML response parser. The binary format changed in 3.x, and the two javabin versions are entirely incompatible. The following code will make this change:
solr.setParser(new XMLResponseParser());Performing Queries
Use query() to have Solr search for results. You have to pass a SolrQuery object that describes the query, and you will get back a QueryResponse (from the org.apache.solr.client.solrj.response package).
SolrQuery has methods that make it easy to add parameters to choose a request handler and send parameters to it. Here is a very simple example that uses the default request handler and sets the query string:
SolrQuery query = new SolrQuery(); query.setQuery(mQueryString);To choose a different request handler, there is a specific method available in SolrJ version 4.0 and later:
query.setRequestHandler("/spellCheckCompRH");You can also set arbitrary parameters on the query object. The first two code lines below are equivalent to each other, and the third shows how to use an arbitrary parameter q to set the query string:
query.set("fl", "category,title,price"); query.setFields("category", "title", "price"); query.set("q", "category:books");Once you have your SolrQuery set up, submit it with query():
QueryResponse response = solr.query(query);The client makes a network connection and sends the query. Solr processes the query, and the response is sent and parsed into a QueryResponse.
The QueryResponse is a collection of documents that satisfy the query parameters. You can retrieve the documents directly with getResults() and you can call other methods to find out information about highlighting or facets.
SolrDocumentList list = response.getResults();Indexing Documents
Other operations are just as simple. To index (add) a document, all you need to do is create a SolrInputDocument and pass it along to the SolrClient’s `add() method. This example assumes that the SolrClient object called 'solr' is already created based on the examples shown earlier.
SolrInputDocument document = new SolrInputDocument(); document.addField("id", "552199"); document.addField("name", "Gouda cheese wheel"); document.addField("price", "49.99"); UpdateResponse response = solr.add(document);// Remember to commit your changes!solr.commit();Uploading Content in XML or Binary Formats
SolrJ lets you upload content in binary format instead of the default XML format. Use the following code to upload using binary format, which is the same format SolrJ uses to fetch results. If you are trying to mix Solr and SolrJ versions where one is version 1.x and the other is 3.x or later, then you MUST stick with the XML request writer. The binary format changed in 3.x, and the two javabin versions are entirely incompatible.
solr.setRequestWriter(new BinaryRequestWriter());Lucence工作原理
lucence 是一個高性能的java全文檢索工具包,他使用倒排序文件索引結構,改結構和相應的生成算法如下:
一、設有兩篇文章1和2
文章1的內容為:Tom lives in guangzhou,i live in guangzhou too
文章2的內容為:He once lived in shanghai
由于lucence是基于關鍵詞索引和查詢的,因此我們首先要取得這兩篇文章的關鍵詞。通常我們要做一下處理:
a.我們現在有的是文章內容,即一個字符串,我們先要找出字符串中的所有單詞,即分詞。英文單詞由于用空格分隔,比較好處理。中文單詞間是連在一起的需要特殊的分詞處理。
b.文章中的”in”, “once” “too”等詞沒有什么實際意義,中文中的“的”“是”等字通常也無具體含義,這些不代表概念的詞可以過濾掉
c.用戶通常希望查“He”時能把含“he”,“HE”的文章也找出來,所以所有單詞需要統一大小寫。
d.用戶通常希望查“live”時能把含“lives”,“lived”的文章也找出來,所以需要把“lives”,“lived”還原成“live”
e.文章中的標點符號通常不表示某種概念,也可以過濾掉
在lucene中以上措施由Analyzer類完成
經過上面處理后,
文章1的所有關鍵詞為:[tom] [live] [guangzhou] [live] [guangzhou]
文章2的所有關鍵詞為:[he] [live] [shanghai]**
| guangzhou | 1 |
| he | 2 |
| i | 1 |
| live | 1,2 |
| shanghai | 2 |
| tom | 1 |
通常僅知道關鍵詞在哪些文章中出現還不夠,我們還需要知道關鍵詞在文章中出現次數和出現的位置,通常有兩種位置:a)字符位置,即記錄該詞是文章中第幾個字符(優點是關鍵詞亮顯時定位快);b)關鍵詞位置,即記錄該詞是文章中第幾個關鍵詞(優點是節約索引空間、詞組(phase)查詢快),lucene 中記錄的就是這種位置。
加上“出現頻率”和“出現位置”信息后,我們的索引結構變為:
| guangzhou | 1[2] | 3,6 |
| he | 2[1] | 1 |
| i | 1[1] | 4 |
| live | 1[2],2[1] | 2,5,2 |
| shanghai | 2[1] | 3 |
| tom | 1[1] | 1 |
以live 這行為例我們說明一下該結構:live在文章1中出現了2次,文章2中出現了一次,它的出現位置為“2,5,2”這表示什么呢?我們需要結合文章號和出現頻率來分析,文章1中出現了2次,那么“2,5”就表示live在文章1中出現的兩個位置,文章2中出現了一次,剩下的“2”就表示live是文章2中第 2個關鍵字。
以上就是lucene索引結構中最核心的部分。我們注意到關鍵字是按字符順序排列的(lucene沒有使用B樹結構),因此lucene可以用二元搜索算法快速定位關鍵詞。
實現時 lucene將上面三列分別作為詞典文件(Term Dictionary)、頻率文件(frequencies)、位置文件 (positions)保存。其中詞典文件不僅保存有每個關鍵詞,還保留了指向頻率文件和位置文件的指針,通過指針可以找到該關鍵字的頻率信息和位置信息。
Lucene中使用了field的概念,用于表達信息所在位置(如標題中,文章中,url中),在建索引中,該field信息也記錄在詞典文件中,每個關鍵詞都有一個field信息(因為每個關鍵字一定屬于一個或多個field)。
為了減小索引文件的大小,Lucene對索引還使用了壓縮技術。首先,對詞典文件中的關鍵詞進行了壓縮,關鍵詞壓縮為<堉?綴長度,后綴>,例如:當前詞為“阿拉伯語”,上一個詞為“阿拉伯”,那么“阿拉伯語”壓縮為<3,語>。其次大量用到的是對數字的壓縮,數字只保存與上一個值的差值(這樣可以減小數字的長度,進而減少保存該數字需要的字節數)。例如當前文章號是16389(不壓縮要用3個字節保存),上一文章號是16382,壓縮后保存7(只用一個字節)。
下面我們可以通過對該索引的查詢來解釋一下為什么要建立索引。
假設要查詢單詞 “live”,lucene先對詞典二元查找、找到該詞,通過指向頻率文件的指針讀出所有文章號,然后返回結果。詞典通常非常小,因而,整個過程的時間是毫秒級的。
而用普通的順序匹配算法,不建索引,而是對所有文章的內容進行字符串匹配,這個過程將會相當緩慢,當文章數目很大時,時間往往是無法忍受的。
參考資料
https://lucene.apache.org/solr/guide/8_5/solr-tutorial.html
https://lucene.apache.org/solr/
https://www.jianshu.com/p/be9e4accb486
https://www.w3cschool.cn/solr_doc/solr_doc-emn62fs5.html
https://lucene.apache.org/solr/guide/6_6/using-solrj.html#UsingSolrJ-SettingXMLResponseParser
https://www.cnblogs.com/senlinyang/p/8064202.html
Kotlin開發者社區
專注分享 Java、 Kotlin、Spring/Spring Boot、MySQL、redis、neo4j、NoSQL、Android、JavaScript、React、Node、函數式編程、編程思想、"高可用,高性能,高實時"大型分布式系統架構設計主題。
High availability, high performance, high real-time large-scale distributed system architecture design。
分布式框架:Zookeeper、分布式中間件框架等
分布式存儲:GridFS、FastDFS、TFS、MemCache、redis等
分布式數據庫:Cobar、tddl、Amoeba、Mycat
云計算、大數據、AI算法
虛擬化、云原生技術
分布式計算框架:MapReduce、Hadoop、Storm、Flink等
分布式通信機制:Dubbo、RPC調用、共享遠程數據、消息隊列等
消息隊列MQ:Kafka、MetaQ,RocketMQ
怎樣打造高可用系統:基于硬件、軟件中間件、系統架構等一些典型方案的實現:HAProxy、基于Corosync+Pacemaker的高可用集群套件中間件系統
Mycat架構分布式演進
大數據Join背后的難題:數據、網絡、內存和計算能力的矛盾和調和
Java分布式系統中的高性能難題:AIO,NIO,Netty還是自己開發框架?
高性能事件派發機制:線程池模型、Disruptor模型等等。。。
合抱之木,生于毫末;九層之臺,起于壘土;千里之行,始于足下。不積跬步,無以至千里;不積小流,無以成江河。
總結
以上是生活随笔為你收集整理的全文搜索引擎Solr原理和实战教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入理解java虚拟机
- 下一篇: 友华PT925E,电信天翼网关3.0,光