一、Solr基礎(chǔ)
介紹
Solr是一個文檔儲存與檢索引擎。
Solr是基于Lucene做的,Lucene是一套信息檢索工具包,但并不包含搜索引擎系統(tǒng),它包含了索引結(jié)構(gòu)、讀寫索引工具、相關(guān)性工具、排序等功能,因此在使用Lucene時你仍需要關(guān)注搜索引擎系統(tǒng),例如數(shù)據(jù)獲取、解析、分詞等方面的東西。
Solr的目標(biāo)是打造一款企業(yè)級的搜索引擎系統(tǒng),因此它更接近于我們認識到的搜索引擎系統(tǒng),它是一個搜索引擎服務(wù),通過各種API可以讓你的應(yīng)用使用搜索服務(wù),而不需要將搜索邏輯耦合在應(yīng)用中。而且Solr可以根據(jù)配置文件定義數(shù)據(jù)解析的方式,更像是一個搜索框架,它也支持主從、熱換庫等操作。

什么是文檔
每個文檔包含一個或者多個字段,提交到Solr處理的每份數(shù)據(jù)都是文檔。
文檔可以是一篇報道,一份簡歷,一段話,甚至是一本書。
倒排索引
Lucene是一個Java類庫,用于倒排索引的構(gòu)建與管理,倒排索引是專門用于匹配查詢詞項與文本文檔的數(shù)據(jù)結(jié)構(gòu)。
倒排索引構(gòu)建過程如下圖:

Solr創(chuàng)建索引過程
索引的創(chuàng)建過程可以分為:1、分詞組件 2、語言處理組件 3、索引組件
一、把原始文檔交給分詞組件(Tokenizer)
1、將文檔分成一個一個單獨的單詞
2、去除標(biāo)點符號
3、去除停詞(stop word)
二、詞匯單元(Token)傳給語言處理組件(Linguistic Processor)
1、變?yōu)樾?/strong>(Lowercase)。
2、將單詞縮減為*詞根形式,如”cars”到”car”等。這種操作稱為:stemming。
3、將單詞轉(zhuǎn)變?yōu)樵~根形式,如”drove”到”drive”等。這種操作稱為:lemmatization
三、 得到的詞(Term)傳遞給索引組件(Indexer)
1、利用得到的詞(Term)創(chuàng)建字典
2、對字典按字母順序排序
3、合并相同的詞(Term)成為文檔倒排(Posting List)鏈表
Solr查詢過程
1、對查詢內(nèi)容進行詞法分析、語法分析、語言處理
2、搜索索引,得到符合語法樹的文檔集合
3、根據(jù)查詢語句與文檔的相關(guān)性,對結(jié)果進行排序
如何儲存
為了加快查找速度,倒排表無論是文檔號及詞頻,還是位置信息,都是以跳躍表的結(jié)構(gòu)存在的。
https://www.cnblogs.com/bonelee/p/6394920.html

Solr和ES區(qū)別
1、solr利用zookeeper進行分布式管理,而es自身帶有分布式系統(tǒng)管理功能
2、solr官網(wǎng)提供的功能更多,而es本身更注重于核心功能,高級功能有多個第三方插件
3、solr是傳統(tǒng)搜索應(yīng)用的有力解決方案,但是es更適合用于新興的實時搜索應(yīng)用。solr不考慮建索引的同時進行搜索,速度更快。
4、Solr 支持更多格式的數(shù)據(jù),而 Elasticsearch 僅支持json文件格式;
https://zhuanlan.zhihu.com/p/24286279
為什么ES實時性強
Lucene使用Searcher來執(zhí)行索引的讀取,一次提交不足以保證新索引被搜索到,出于性能考慮,Lucen延遲了耗時的刷新(Searcher重新打開)。
Searcher會每秒刷新一次,ES提供了強制刷新API。

一個Index由若干段組成,搜索的時候按段搜索,我們索引一條段后,每個段會通過fsync 操作持久化到磁盤,而fsync 操作比較耗時,如果每索引一條數(shù)據(jù)都做這個full commit(rsync)操作,提交和查詢的時延都非常之大,所以在這種情況下做不到實時的一個搜索。
針對這個問題的解決是在Elasticsearch和磁盤之間引入一層稱為FileSystem Cache的系統(tǒng)緩存,正是由于這層cache的存在才使得es能夠擁有更快搜索響應(yīng)能力。
然后在es中新增的document會被收集到indexing buffer區(qū)后被重寫成一個segment寫入filesystem cache中,這個操作相對耗時較少,之后經(jīng)過一定的間隔或外部觸發(fā)后才會被flush到磁盤上,這個操作非常耗時。但只要sengment文件被寫入cache后,這個sengment就可以打開和查詢,從而確保在短時間內(nèi)就可以搜到,而不用執(zhí)行一個full commit也就是fsync操作,這是一個非常輕量級的處理方式而且是可以高頻次的被執(zhí)行,而不會破壞es的性能。
相關(guān)度
1、默認相似度
Solr的相關(guān)度得分是基于Similarity類的,Similarity是Java類,它根據(jù)給定查詢定義了搜索結(jié)果相關(guān)度得分的計算方法。
2、詞項頻次
3、反向文檔頻次
4、詞項權(quán)重
5、規(guī)范化因子
查準(zhǔn)率與查全率
1、查準(zhǔn)率
查詢的結(jié)果是不是我想要?
查準(zhǔn)率 = 正確匹配的文檔數(shù)量 / 返回的文檔數(shù)量
2、查全率
查全率衡量的是搜索結(jié)果的全面性。
查全率 = 返回的正確匹配的文檔數(shù) / 全部正確匹配的文檔數(shù)。
3、查準(zhǔn)率與查全率之間的平衡
最大限度提升查準(zhǔn)率與查全率是絕大多數(shù)搜索相關(guān)度優(yōu)化的最終目標(biāo)。
大部分技術(shù)更傾向于提高返回完整文檔集的查全率。
Solr和Lucene的區(qū)別?
Lucene是一個基于Java的全文信息檢索工具包,局限于Java調(diào)用,而Solr底層的核心技術(shù)是使用Lucene來實現(xiàn)的,是一個跨平臺的搜索應(yīng)用,而且提供了一個HTTP的管理頁面。
倒排索引和全文檢索
倒排索引就是講數(shù)據(jù)中的詞拆分構(gòu)建一個大表,將關(guān)鍵字拆出來,后面帶上這個文章的documentid號,例如中間這個就是倒排索引了。
全文檢索就比較好理解的,就是當(dāng)我們輸入“全瓦解”,會被拆分成”全”,“瓦解”2個此,用2個詞去倒排索引里面去檢索數(shù)據(jù),檢索到的數(shù)據(jù)返回。整個過程就叫做全文檢索
什么是全文檢索?
數(shù)據(jù)總體分為兩類:結(jié)構(gòu)化數(shù)據(jù)和非結(jié)構(gòu)化數(shù)據(jù)。
- 結(jié)構(gòu)化數(shù)據(jù):指具有固定格式或有限長度的數(shù)據(jù),如數(shù)據(jù)庫,元數(shù)據(jù)等。
- 非結(jié)構(gòu)化數(shù)據(jù):指不定長或無固定格式的數(shù)據(jù)。非結(jié)構(gòu)化數(shù)據(jù)又一種叫法叫全文數(shù)據(jù)。
對結(jié)構(gòu)化數(shù)據(jù)的搜索:如對數(shù)據(jù)庫的搜索,用SQL語句。再如對元數(shù)據(jù)的搜索,如利用windows搜索對文件名,類型,修改時間進行搜索等。
對非結(jié)構(gòu)化數(shù)據(jù)的搜索:如利用windows的搜索也可以搜索文件內(nèi)容,Linux下的grep命令,再如用Google和百度可以搜索大量內(nèi)容數(shù)據(jù)。
全文檢索:即先建立索引,再對索引進行搜索。索引是從非結(jié)構(gòu)化數(shù)據(jù)中提取出之后重新組織的信息。
倒排索引和常規(guī)索引區(qū)別
常規(guī)索引:
文檔——>關(guān)鍵詞 但是這樣檢索關(guān)鍵詞的時候很費力,要一個文檔一個文檔的遍歷一遍。
倒排索引:倒排索引是關(guān)鍵詞到文檔的映射
關(guān)鍵詞——>文檔 這樣,只要有關(guān)鍵詞,立馬就能找到她在那個文檔里出現(xiàn)過,然后就可以查出整個文檔。
中文分析器 IK Analyzer
IK Analyzer 是一個開源的,基亍 java 語言開發(fā)的輕量級的中文分詞工具包??梢宰约禾砑訑U展詞典和停用詞典。
配置域
域相當(dāng)于數(shù)據(jù)庫的字段
域的常用屬性:
name:指定域的名稱
type:指定域的類型
indexed:是否索引
stored:是否存儲
required:是否必須
multiValued:是否多值
我們根據(jù)自己的需求自定義域,例如:id,標(biāo)題,價格,品牌,商家名稱,分類名稱,商品的SKU的ID,圖片地址等。
復(fù)制域
復(fù)制域的作用在于將某一個 Field 中的數(shù)據(jù)復(fù)制到另一個域中,就是說可以將域進行組合
我們把標(biāo)題、品牌、分類名稱、商品放進復(fù)制域中,用來后續(xù)的組合查詢
注意:復(fù)制域不需要存儲,只是邏輯上進行組合,屬性就選擇Ik分詞器,需要建立索引搜索
動態(tài)域
將兩個域的域名復(fù)制到一個text文本域中。
我們數(shù)據(jù)庫中的規(guī)格字段,存儲的是動態(tài)的值,不固定的,需要動態(tài)拼接,在末尾+*號表示。
我們?yōu)槭裁匆褂肧olr來進行查詢,而不用MySQL呢?
- 數(shù)據(jù)庫中不能分詞
- 在數(shù)據(jù)庫中我們只能使用Like來模糊搜索,太低效,太慢
- 在電商項目中,使用搜索會承擔(dān)很大的壓力,每一個人過來搜一下,數(shù)據(jù)庫扛不住壓力
- 所以我們需要使用更專業(yè)的工具來實現(xiàn)搜索功能,我們要把數(shù)據(jù)庫中的內(nèi)容導(dǎo)入到Solr的索引庫中,并且要隨著數(shù)據(jù)庫中的變化而變化
批量數(shù)據(jù)導(dǎo)入
思路:通過Mybatis來查詢數(shù)據(jù)庫中的數(shù)據(jù),在調(diào)用批量添加的方法到Solr索引庫
SolrCloud
SolrCloud(solr 云)是 Solr 提供的分布式搜索方案,當(dāng)你需要大規(guī)模,容錯,分布式索引和檢索能力時使用 SolrCloud。當(dāng)一個系統(tǒng)的索引數(shù)據(jù)量少的時候是不需要使用 SolrCloud的,當(dāng)索引量很大,搜索請求并發(fā)很高,這時需要使用 SolrCloud 來滿足這些需求。 SolrCloud 是基于 Solr 和Zookeeper的分布式搜索方案,它的主要思想是使用 Zookeeper作為集群的配置信息中心。
Zookeeper 作為集群的配置信息中心。
它有幾個特色功能:
- 集中式的配置信息
- 自動容錯
- 近實時搜索
- 查詢時自動負載均衡
Solr Cloud的結(jié)構(gòu)
solrcloud為了降低單機的處理壓力,需要由多臺服務(wù)器共同來完成索引和搜索任務(wù)。實現(xiàn)的思路是將索引數(shù)據(jù)進行Shard分片,每個分片由多臺服務(wù)器共同完成,當(dāng)一個索引或搜索請求過來時會分別從不同的Shard的服務(wù)器中操作索引。
solrcloud是基于solr和zookeeper部署,zookeeper是一個集群管理軟件,solrcloud需要由多臺solr服務(wù)器組成,然后由zookeeper來進行協(xié)調(diào)管理。
物理結(jié)構(gòu)和邏輯結(jié)構(gòu)
一個Solr Cloud集群從架構(gòu)方面來講分成物理結(jié)構(gòu)和邏輯結(jié)構(gòu)進行理解.
物理結(jié)構(gòu):
一個Solr Cloud集群,由多臺solr服務(wù)器(安裝了solr對應(yīng)的tomcat服務(wù)器的郵件服務(wù)器)組成,每一臺solr服務(wù)器又是可以安裝多個tomcat,每個tomcat中安裝一個solr.war.每個solr.war對應(yīng)一個solrhome,每個solrhome只需要配置一個solrcore.
邏輯結(jié)構(gòu):
一個Solr Cloud從邏輯上可以看成是一個collection(索引集合).一個collection可以從邏輯上被分為多個片shard,每個片又可以由多個solrcore組成,一個片的多個solrcore需要有一個master,其他的都是slave.
Solr Cloud架構(gòu)的優(yōu)勢:
高擴展:1、solrcloud集群中使用分片的架構(gòu),每片提供搜索和索引的內(nèi)容是不一樣的。這樣架構(gòu)的好處是可以高擴展。(分片)
高可用:2、solrcloud集群中同一片由不同的solrcore組成,這樣如果一臺solrcore失敗,是不會影響使用,這樣就解決了高可用。而且還可以解決高并發(fā)。(副本集)

地理位置搜索(GeoHash:經(jīng)緯度轉(zhuǎn)為base32的編碼,讓它來標(biāo)記區(qū)域)
geohash基本原理是將地球理解為一個二維平面,將平面遞歸分解成更小的子塊,每個子塊在一定經(jīng)緯度范圍內(nèi)擁有相同的編碼,這種方式簡單粗暴,可以滿足對小規(guī)模的數(shù)據(jù)進行經(jīng)緯度的檢索
在Solr索引將經(jīng)緯度的二位坐標(biāo)通過geoHash變成一維的字符串base32的坐標(biāo)。
比如將經(jīng)緯度(34.2,45.4)轉(zhuǎn)換base32的DRT2Y,R到D的子區(qū)域,T是R的子區(qū)域。

進入D區(qū)域,則看到又分為若干區(qū)域,而R為其子區(qū)域:

所以讓base32的編碼來標(biāo)記區(qū)域。
具體流程以(39.92324 緯度, 116.3906 經(jīng)度)為例,首先將緯度的范圍(-90, 90)平分成兩個區(qū)間(-90, 0)、(0, 90),如果目標(biāo)緯度位在(-90,0),則編碼為0,在(0,90)則編碼為1。

所以通過16輪的計算后得到經(jīng)度39.92324的編碼為:
1011 1000 1100 0111 1001
經(jīng)度也用同樣的算法,對(-180, 180)多輪的依次細分計算:

得到緯度116.3906的編碼為1101 0010 1100 0100 0100
經(jīng)緯度的編碼都計算完畢后,接下來就需要合并經(jīng)緯度的編碼,規(guī)則是以經(jīng)度開始,依次每次取一位合并成5位的新編碼,如上圖紅色字標(biāo)示順序所示:

完成合并編碼后就需要將該編碼和base32編碼表對應(yīng)起來,做法是每5位為一個十進制數(shù),以11100為例,它的十進制數(shù)是28,所以對應(yīng)的base32編碼表示W(wǎng),如下圖所示:

其他的五位編碼依次從表中找到對應(yīng)位置后,(39.92324 緯度, 116.3906 經(jīng)度)的base32編碼為:wx4g0ec1
解碼算法與編碼算法相反,先進行base32解碼,然后分離出經(jīng)緯度,最后根據(jù)二進制編碼對經(jīng)緯度范圍進行細分即可,這里不再贅述。不過由于geohash表示的是區(qū)間,編碼越長越精確,但不可能解碼出完全一致的地址
步驟總結(jié)
1、把經(jīng)度經(jīng)過16輪的計算后得到編碼為:
1011 1000 1100 0111 1001
2、緯度也一樣計算得1101 0010 1100 0100 0100
3、將經(jīng)緯度的編碼進行合并,以經(jīng)度開始得到10111 00011 00 011 11001 11010 01011 00010 00100
4、將得到編碼 每5位為一個十進制數(shù),有8個數(shù)。比如以11100的十進制數(shù)是28,所以對應(yīng)的base32編碼表示W(wǎng)。
5、然后就得到8個base32編碼