如果你的項目中用到了搜索囤官,現(xiàn)在的選擇就奔上就是Solr或者Elasticsearch了冬阳,今天我們就來看看Solr,當然我一般是不會在博客中講什么原理的党饮,因為講原理是我自己的理解肝陪,我怕誤導大家,好了開始吧
一刑顺、簡介
- 為什么要使用搜索呢氯窍?
- 我們知道,一個大型網(wǎng)站蹲堂,用戶的搜索是一個及其消耗服務器性能的事情狼讨,如果在這點上處理不好,將會使得用戶體驗度大打折扣柒竞,甚至拖垮整個應用政供!
- Solr
- 講到Solr其實肯定就會提到Lucene,兩者的區(qū)別在于Lucene是一個底層的API實現(xiàn)朽基,而Solr是在應用的層面上封裝了Lucene布隔。
- Solr是Apache旗下的一款快速的,高度可擴展踩晶,可提供高性能执泰,以文本為中心的開源搜索服務器枕磁。它基于HTTP請求訪問渡蜻,也就是說跨平臺性得到了保障;主要用于構建搜索應用程序计济。Yonik Seely于2004年創(chuàng)建茸苇,并于2006年1月成為Apache軟件基金會下的一個開源項目;
- Solr的另一大可以說是特性就是可以和Hadoop一起使用沦寂,也就是說不僅限于搜索学密,Solr也可以用于數(shù)據(jù)的存儲和數(shù)據(jù)處理,是一種非關系數(shù)據(jù)存儲和處理技術传藏;
- 如果你想知道Elasticsearch和Solr的區(qū)別腻暮,可以查看這篇
二彤守、Solr的安裝
-
在Win上的安裝
-
Solr5之前的版本安裝
- 這里我選擇的是4.9.1起宽,即5之前的最后一個版本;
- 解壓之后把dist之中的solr-4.9.1.war復制到Tomcat的webapp下济榨;
- 啟動坯沪,等待解壓,完成后把下載包中的\example\lib\ext中所有的jar拷貝到Tomcat\webapps\solr\WEB-INF\lib中腿短,主要是給solr提供一個日志方面的包屏箍;
- 配置索引庫:把解壓包中的\example\solr到電腦中的一個位置,如我放在D:\Documents\SolrHome橘忱,我把solr重命名為SolrHome赴魁,把D:\Documents\SolrHome配置到Solr應用的web.xml中的env-entity中;
- 啟動Tomcat钝诚,訪問:http://localhost:8080/solr颖御,安裝完成
-
Solr5及其之后的版本安裝
- // TODO 有時間補
三、配置中文分詞器
- 這里我們使用IKAnalyzer來做中文分詞凝颇,單獨使用請參考我的另一片文章中文分詞器 ~ IK Analyzer潘拱;
- 在Solr中使用的步驟如下:
- 文章中文分詞器 ~ IK Analyzer中的配置;
- 修改 SolrHome 中的 schema.xml 文件拧略,配置一個 FieldType芦岂,使Solr采用 IKAnalyzer作為默認的文本分詞器:
<fieldType name="text_ik" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType>
- 配置完成后啟動服務器
四、域
- 域垫蛆,即字段禽最,在Solr的配置schema.xml文件中對應的標簽是field;還有一個就是fieldType袱饭,這個指的是域的數(shù)據(jù)類型川无;
- 我們一般是要在數(shù)據(jù)庫中搜索數(shù)據(jù)的,盡管Solr的配置中已經(jīng)為我們提供了相當多的域虑乖,但是我們在做項目的時候還是要根據(jù)我們的需求自定義添加一些域懦趋,并給這些域設置相應的屬性,常見的屬性如下:
- name:指定域的名稱疹味,自定義仅叫,一般是數(shù)據(jù)表中的字段名
- type:指定域的類型帜篇,即fieldType
- indexed:是否索引,取值true/false
- stored:是否存儲诫咱,取值true/false
- required:是否必須坠狡,取值true/false
- multiValued:是否多值,取值true/false
- 自定義域
- 分析需要搜索的字段遂跟;
- 在SolrHome的schema.xml文件中添加字段field逃沿,根據(jù)業(yè)務需求添加這些域,同時設置上面的屬性幻锁;
- 復制域
- 我們在搜索的時候摁釘還會遇到一種情況凯亮,用戶在搜索的時候可以填寫很多信息,而這些信息對應數(shù)據(jù)庫的很多字段哄尔,難道我們要把分詞的結果全部在數(shù)據(jù)庫中笛卡爾積式 'LIKE' 嗎假消?Solr中為我們解決了這個問題,解決的途徑就是使用復制域來解決岭接;
- 復制域schema.xml文件中對應的標簽是copyField富拗,含有兩個屬性:
- source:來源域的name屬性
- dest:目標域,即:將source域復制到該目標域進行搜索)
- 動態(tài)域
- 動態(tài)域主要用來解決項目表中存儲的數(shù)據(jù)是是動態(tài)類型的情況鸣戴,比如我們常用的字典表就是這一類型啃沪,某列的值是根據(jù)當前記錄的類型決定的;
- 動態(tài)域的配置與普通的字段域大部分相同窄锅,為疑似不同的就是在name屬性上提供通配符 *创千;
五、SolrJ
- SolrJ是Solr官方提供的Java客戶端入偷,它提供了增刪改查Solr索引的Java接口追驴。SolrJ針對Solr提供了Rest 的HTTP接口進行了封裝, SolrJ底層是通過使用httpClient中的方法來完成Solr的操作的疏之;
- Solr是一個應用殿雪,SolrJ是一個請求Solr應用的客戶端,之間使用HTTP進行通訊锋爪;
- 使用參考這篇文章丙曙;
六、SpringDataSolr
- SpringDataSolr其實就是Spring對SolrJ的一個封裝几缭;
- 使用步驟
- 引入Maven庫
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-solr</artifactId> <version>3.0.11.RELEASE</version> </dependency>
- 添加配置文件:application-solr.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="https://www.springframework.org/schema/beans" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- Solr Server配置方式1 --> <solr:solr-server id = "solrServer" url = "<solr-access-url>" /> <!-- Solr Server配置方式2 --> <bean id = "solrServer" class = "org.apache.solr.client.solrj.impl.HttpSolrServer"> <constructor-arg index="0" value = "<solr-access-url>" /> </bean> <!-- Solr Server集群配置方式 --> <bean id = "solrServer" class = "org.apache.solr.client.solrj.impl.CloudSolrServer"> <constructor-arg index="0" value="<ip-port-comma>" /> <property name="defaultCollection" value="<collection-name>" /> </bean> <!-- Solr Template --> <bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate"> <constructor-arg ref="solrServer" /> </bean> </beans>
- 關聯(lián)數(shù)據(jù)庫字段與Solr搜索字段
- 關聯(lián)直接使用注解@org.apache.solr.client.solrj.beans.Field作用在實體類上即可河泳,如果數(shù)據(jù)庫字段名和Solr搜索字段不相同則在參數(shù)中執(zhí)行即可沃呢;
- 動態(tài)域在關聯(lián)實體類的時候需要添加注解@Dynamic年栓,凡是需要關聯(lián)的實體字段是使用@Field,注解@Field是SolrJ提供的薄霜,而@Dynamic是SpringDataSolr提供的某抓,所以在pom引用的時候直接引用SpringDataSolr即可纸兔,底層的框架會自動引入;
- 編碼初始化Solr數(shù)據(jù)
- 編碼的時候直接使用solrTemplate的save/delete/deleteById/queryForPage/getById等方法即可實現(xiàn)數(shù)據(jù)的增刪改查否副,但是要注意的是汉矿,增刪改語句后必須添加事務的提交語句
solrTemplate.commit();
,否則數(shù)據(jù)不會受影響的备禀; - 具體的請查看API提示即可洲拇;
- Query:分頁查詢的封裝類,請看代碼:
Query query = new Query("*:*"); query.setOffset(<start>); query.setRows(<page-size>); query.setCriteria(<criteria>); // 封裝查詢條件 ScoredPage page = solrTemplate.queryForPage(query, <Bean>.class); List<<bean>> beansOfThisPage = page.getContent(); System.out.println("一頁數(shù)據(jù):" + beansOfThisPage); System.out.println("總條數(shù):" + page.getTotalElements()); System.out.println("總頁數(shù):" + page.getTotalPages()); System.out.println("總頁數(shù):" + page.getSize());
- 使用上面的方法結合MyBatis把數(shù)據(jù)庫中的數(shù)據(jù)保存到Solr索引中曲尸;具體就不在贅述赋续;
- 編碼的時候直接使用solrTemplate的save/delete/deleteById/queryForPage/getById等方法即可實現(xiàn)數(shù)據(jù)的增刪改查否副,但是要注意的是汉矿,增刪改語句后必須添加事務的提交語句
- 引入Maven庫
- 關鍵字搜索
- 根據(jù)上面SolrTemplate的查詢方法編寫查詢Solr的服務;
- Solr增量更新(參考這里和這里)
- 我們可以手動編寫導入代碼結合定時器完成另患,但是SpringDataSolr已經(jīng)幫我們做了一部分工作纽乱,配置一下即可;如下:
- 導入solr數(shù)據(jù)更新的pom:
<dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-dataimporthandler</artifactId> <version>6.6.5</version> </dependency>
- 在SolrHome目錄下新建一個文件夾conf,再在conf文件夾下新建dataimport.properties文件昆箕,其內(nèi)容為:
################################################# # # # dataimport scheduler properties # # # ################################################# # to sync or not to sync # 1 - active; anything else - inactive syncEnabled=1 # which cores to schedule # in a multi-core environment you can decide which cores you want syncronized # leave empty or comment it out if using single-core deployment syncCores=test,hotel # solr server name or IP address # [defaults to localhost if empty] server=localhost # solr server port # [defaults to 80 if empty] port=8083 # application name/context # [defaults to current ServletContextListener's context (app) name] webapp=solr # 增量索引的參數(shù) # URL params [mandatory] # remainder of URL params=/dataimport?command=delta-import&clean=false&commit=true # 重做增量索引的時間間隔 # schedule interval # number of minutes between two runs # [defaults to 30 if empty] interval=1 # 重做全量索引的時間間隔鸦列,單位分鐘,默認7200鹏倘,即5天; # 為空,為0,或者注釋掉:表示永不重做索引 #reBuildIndexInterval=7200 # 重做索引的參數(shù) reBuildIndexParams=/dataimport?command=full-import&clean=true&commit=true # 重做索引時間間隔的計時開始時間薯嗤,第一次真正執(zhí)行的時間=reBuildIndexBeginTime+reBuildIndexInterval*60*1000; # 兩種格式:2012-04-11 03:10:00 或者 03:10:00纤泵,后一種會自動補全日期部分為服務啟動時的日期 reBuildIndexBeginTime=03:10:00
- 增加增量更新監(jiān)聽器应民。即在Solr服務的web.xml加入監(jiān)聽器:
<listener> <listener-class> org.apache.solr.handler.dataimport.scheduler.ApplicationListener </listener-class> </listener>
- 編寫增量更新SQL:在Solr的conf\data-config.xml中<entity>標簽加入兩個屬性:
deltaImportQuery="<data-query-sql>'" deltaQuery="<primary-key-query-sql>"
- 屬性介紹:
query是獲取全部數(shù)據(jù)的SQL
deltaImportQuery是獲取增量數(shù)據(jù)時使用的SQL
deltaQuery是獲取主鍵的SQL
parentDeltaQuery是獲取父Entity的主鍵的SQL - Full Import工作原理:
- 執(zhí)行本Entity的Query,獲取所有數(shù)據(jù)夕吻;
- 針對每個行數(shù)據(jù)Row诲锹,獲取主鍵,組裝子Entity的Query涉馅;
- 執(zhí)行子Entity的Query归园,獲取子Entity的數(shù)據(jù)。
- Delta Import工作原理:
- 查找子Entity稚矿,直到?jīng)]有為止庸诱;
- 執(zhí)行Entity的deltaQuery,獲取變化數(shù)據(jù)的主鍵晤揣;
- 合并子Entity parentDeltaQuery得到的主鍵桥爽;
- 針對每一個主鍵 Row,組裝父Entity的parentDeltaQuery昧识;
- 執(zhí)行parentDeltaQuery钠四,獲取父Entity的主鍵;
- 執(zhí)行deltaImportQuery跪楞,獲取自身的數(shù)據(jù)缀去;
- 如果沒有deltaImportQuery侣灶,就組裝Query;
- 限制:
? 子Entity的query必須引用父Entity的主鍵缕碎;
? 子Entity的parentDeltaQuery必須引用自己的主鍵褥影;
? 子Entity的parentDeltaQuery必須返回父Entity的主鍵;
? deltaImportQuery引用的必須是自己的主鍵咏雌;
- 屬性介紹: