目前在系統(tǒng)中涉及到搜索的解決方案都是通過數(shù)據(jù)庫自帶特性解決,如通過mysql5.7自帶的全文檢索功能實現(xiàn)資源的搜索。
這樣實現(xiàn)的好處是方便,無需額外開發(fā)和維護成本。但是隨著業(yè)務(wù)的發(fā)展和數(shù)據(jù)的增加,性能和可擴展方面很容易出現(xiàn)瓶頸。
結(jié)合本次方案庫需求的契機,決定引入spring boot + solr 為主要架構(gòu)基礎(chǔ)的前置平臺用于應(yīng)對日漸旺盛的搜索服務(wù)需求。
前置平臺基于spring boot開發(fā),主要看中spring boot的微服務(wù)思想,方便開發(fā)和部署。同時可以為以后的微服務(wù)架構(gòu)做技術(shù)熱身。
通過spring boot搭建的前置平臺會處理請求接入,限流,監(jiān)控,安全等非功能性需求。
搜索端結(jié)合了最新的apache solr服務(wù)器端(6.6版本),使用自帶的smart-cn中文分詞組件,提供搜索服務(wù)的基礎(chǔ)支持。
架構(gòu)實現(xiàn)部分主要通過具體實踐來驗證架構(gòu)的可行性,不涉及具體業(yè)務(wù)細節(jié)和實際數(shù)據(jù),
架構(gòu)實現(xiàn)的操作描述力求做到可復(fù)制。
首先確保本機安裝了jdk8+,然后就進入eclipse,創(chuàng)建一個maven project。
POM文件包含以下內(nèi)容:
org.springframework.boot spring-boot-starter-parent 2.0.0.BUILD-SNAPSHOT 2.1.1.RELEASE org.springframework.data spring-data-solr ${spring.data.solr.version} org.springframework.boot spring-boot-starter-web org.springframework.data spring-data-solr
Maven結(jié)構(gòu)搭好后就是搭建你的項目架構(gòu),如圖:
Application.java 對應(yīng)了項目的入口,通過一段很簡單的代碼就可以啟動一個jetty服務(wù)了。
package app; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import sample.Example; @SpringBootApplication public class Application { public static void main(String[] args) throws Exception { SpringApplication.run(Example.class, args); } }
運行示意圖:
首先到官方網(wǎng)站下載最新的安裝包,當前版本是6.6,下載zip包就可以了。
解壓后的文件夾有以下幾個目錄是首先需要關(guān)注的:
bin: 啟動腳本目錄,通過這里面的命令來啟動關(guān)閉服務(wù)器
server:solr服務(wù)器目錄,配置文件和jar包以及索引數(shù)據(jù)都是在這個目錄里面的
contrib:這個里面放的是隨版本發(fā)布的一些可選包,我們后面用到的中文分詞包就在里面
由于我們是驗證架構(gòu)所以所有的配置都是基于單機的。
下一步要做的是創(chuàng)建一個core,在solr-6.6.0\server\solr目錄下新建一個文件夾sample_solr,包含如下文件夾
conf 配置文件目錄,初始版本從solr-6.6.0\example\example-DIH\solr\db\conf 復(fù)制
data 數(shù)據(jù)文件目錄,手工創(chuàng)建
core.properties 手工創(chuàng)建目錄,內(nèi)容如下:
name=sample_solr |
創(chuàng)建完成core后需要修改一下core里面的配置文件,
在solr-6.6.0\server\solr\sample_solr\conf目錄下面,有三個文件,按照順序修改
solrconfig.xml
找到data import的request handler修改為
solr-data-config.xml
solr-data-config.xml
通過這個文件來配置你的data source和文檔字段,下面是我的配置
有幾個地方需要注意的,
batchSize
官方文檔建議針對mysql數(shù)據(jù)庫使用-1來迫使mysql使用Integer.MIN_VALUE作為fetch size,實際操作中設(shè)置成-1時我使用mysql-connector-java-5.1.24(這個驅(qū)動如果沒有需要自行下載并發(fā)到solr-6.6.0\server\lib目錄)作為驅(qū)動會出現(xiàn)result set close的錯誤,所以這邊設(shè)置成10,具體有沒有用還待驗證
后來在mysql的bug list找到了一個相似的問題,供參考
https://bugs.mysql.com/bug.php?id=83027
entity的PK
在deltaQuery的時候會用到,雖然deltaQuery的語句是通過update_time> xxx來獲取增量數(shù)據(jù),實際最后查詢的時候還是通過pk in (ids) 這樣的方式,所以如果需要用到deltaQuery,PK需要設(shè)置成數(shù)據(jù)庫表的主鍵
field的定義
這邊可以看到我定義了一個tag字段,可是當你去搜索的時候,結(jié)果里面死活只出現(xiàn)id和name。
最后發(fā)現(xiàn)文檔中的字段都是要通過定義的,只不過solr為自己的sample預(yù)留了一些字段定義剛好包含id和name,這也算是個相當坑的地方。
managed-schema
上面說倒field需要通過定義,那么這個文件就是用來定義文檔中使用到的字段和字段類型了。Solr正是通過scheme定義來構(gòu)建索引。
這個scheme文件包含四種元素:
field type
字段的類型如文本,數(shù)字浮點等,定義貼切的類型有利于solr更準確的識別字段并輸出結(jié)果
field
字段,用于組成solr文檔的的基本單位。如果從面向?qū)ο蠼嵌葋砜?,一個文檔是一個對象,相應(yīng)的字段就是這個對象的屬性
dynamicField
動態(tài)字段,solr除了提供一些默認字段之外還預(yù)留了一些通配符字段定義,如下:
結(jié)合我們上面的tag字段,如果我們覺得每個字段都要定義太麻煩,那么可以在entity里面直接使用dynamic field,
重新建立索引后,我們的搜索結(jié)果如圖:
copyField
從名字就可以看出來這是一個復(fù)制字段功能,從定義來看也很明顯的發(fā)現(xiàn)有source有dest。一個主要的用途就是全文檢索,將需要檢索的字段都copy到一個字段,之后對這個字段的搜索不就是全文檢索了嗎?這個和早期數(shù)據(jù)庫里面將幾個字段組合起來后來個模糊查詢就是全文搜索是一個道理。
這個要注意的是如果source有幾個字段,那么目標字段的multiValued需要設(shè)置為true
更詳細的含義建議參考官方文檔,我們主要涉及field type,field和copyField的定義,這里就基于我們的例子來看看。
field type在一般情況下不需要擴展,因為solr已經(jīng)自帶了很多的類型了,這里我們?yōu)榱酥С种形姆衷~,新增一個字段類型如下
可以看出一個field type由兩部分構(gòu)成,index和query。Index負責建立索引的時候?qū)τ谧侄蔚慕馕龆鴔uery負責查詢的時候。同時為了中文分詞我們需要從solr-6.6.0\contrib\analysis-extras\lucene-libs中拷貝lucene-analyzers-smartcn-6.6.0.jar這個jar包到webapp\WEB-INF\lib
field的配置如下:
1 |
主要是對需要支持中文的字段type配置成我們之前定義的text_smart
copyField
通過上面的配置我們一個solr服務(wù)器端就可以正常運作了,我們回顧一下我們的過程
最后我們進入命令行,通過solr.cmd start來啟動
基于我們前面兩個章節(jié)的內(nèi)容,這時候要做的就是在spring boot項目里面提供solr服務(wù)器的搜索接口封裝以及索引的維護。
首先我們需要創(chuàng)建solr的配置,通過兩個文件
1, application.properties
在src/main/resource目錄下面新建一個properties文件,內(nèi)容如下
spring.data.solr.host=http://127.0.0.1:8983/solr/sample_solr |
2, SolrConfig.java
通過注解將properties中定義的屬性注入到bean中
package sample; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "spring.data.solr") public class SolrConfig { private String host; private String zkHost; private String defaultCollection; //getter setter }
接下來就是通過一個controller來通過restful的方式將用戶接口和solr script連接起來。
下面是我們的一個查詢controller
package sample; //import section @RestController @EnableAutoConfiguration public class Example { @Autowired private SolrClient client; @RequestMapping("/query/name/{name}") public String queryByName(@PathVariable String name) throws IOException, SolrServerException { ModifiableSolrParams params =new ModifiableSolrParams(); params.add("q",name); params.add("hl","on"); params.add("hl.fl","name,tag"); params.add("ws","json"); params.add("start","0"); params.add("rows","10"); QueryResponse response=null; try{ response=client.query(params); SolrDocumentList results = response.getResults(); for (SolrDocument document:results) { System.out.println( document); } }catch(Exception e){ e.getStackTrace(); } return response.toString(); } }
啟動spring boot服務(wù),在瀏覽器輸入我們的查詢指令后就可以得到結(jié)果了
http://localhost:8080/query/name/測試
通過架構(gòu)實現(xiàn)部分的驗證,基于spring boot + solr的前置服務(wù)架構(gòu)是可行的。但是作為一個前置平臺來說,我們還需要關(guān)注哪些點呢?
安全性
前置平臺很多時候是暴露在通用防火墻之外的,所以危險系數(shù)往往也是很高的。我們主要從兩個方面來加強防范
限流
通過限流和適當?shù)姆?wù)降級,保證服務(wù)可用性以及避免可能的流量***。具體實施可以參照線程池的思想,不具體展開。
認證
通過認證體系結(jié)合加密算法保證信息傳輸?shù)谋C苄院屯暾?/p>
可靠性
可靠性是指系統(tǒng)的可用程度,涵蓋系統(tǒng)持續(xù)運行時間,宕機時間,服務(wù)回復(fù)時間等因素。我們通過預(yù)防和監(jiān)控兩個途徑來保證。
預(yù)防
通過部署集群服務(wù)從前置,搜索服務(wù)角度去除單點
監(jiān)控
通過獨立的監(jiān)控系統(tǒng)對前置系統(tǒng)和搜索服務(wù)器進行監(jiān)控,設(shè)定合理的閾值和報警點
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。