Solr的安裝與配置html
多數搜索引擎應用都必須具備某種搜索功能,而搜索功能每每大量的消耗資源致使應用程序運行緩慢。爲此,出現了各類用於構建搜索的應用程序,咱們要學習的solr正是其中的一款開源搜索平臺。前端
Apache Solr 是創建在Lucene(全文搜索引擎)之上,幫助我從大量的數據中尋找所需信息。不只限於搜索,Solr也可用於儲存目的。像其餘NoSQL數據庫同樣,它是一種非關係數據儲存和處理技術。java
<!--more-->git
下面咱們開始喜聞樂見的手摸手教學,教你優雅的整合SSM框架和Solr搜索框架。github
項目中使用了SSM + Shiro + Redis + Solr + Vue.JS + ElementUI技術,優雅的整合了SSM框架階段幾個常見的企業框架;並用Vue.js + ElementUI寫了超漂亮的前端頁面;若是以爲能夠,就點亮右上角star吧(#^.^#)。web
若是你對Shiro+用戶-角色-權限整合不是很懂,你或許能夠看下個人這個項目: 手摸手教你SSM整合Shiro框架後的開發。redis
平常學習記錄,若是想支持我,但願能在Github上看到你點亮的星星(#^.^#)。spring
<br/>數據庫
<br/>apache
在 Apache Solr官網 下載最新版的Solr,在 Apache Tomcat官網 下載Tomcat。
解壓solr,發現其中有以下目錄結構
新版本的Solr和老版本的不一樣,老版本中直接提供的是war文件,新版本則是提供了直接可運行的項目;其次須要導入項目中的的文件也有所不一樣的。下面咱們介紹一下完整的配置和Solr項目的啓動:
solr-7.4.0/server/solr-webapp/
下的webapp
文件夾拷貝到Tomcat下的webapps
目錄下(並重命名爲solr)。solr-7.4.0/server/lib/ext/
下的全部Jar文件所有拷貝到Tomcat下webapps/solr/WEB-INF/lib
目錄下。solr-7.4.0/server/lib
下全部metrics
開頭的jar文件所有拷貝到webapps/solr/WEB-INF/lib
目錄下。solr/7.4.0/server/solr
文件夾複製到任意一個位置並重命名爲solrhome
。tomcat/webapps/solr/WEB-INF/web.xml
文件的第41行,指定solrhome所在的目錄。webapps/solr/WEB-INF/web.xml
下的第125行出添加註釋,也就是註釋<security-constraint></secirity-constraint>
節點下的配置。http://localhost:8080/solr/index.html
便可訪問到solr Admin
如上所示,你會發現其左下角顯示的是No cores
,這和老版本的可能又有所差異,因此咱們點擊No cores
,建立一個新的cores
,那麼會在咱們指定的solrhome
文件夾內產生一個new_core
的空文件夾,而且頁面會報錯:Can't find resource 'solrconfig.xml' in xxx
,表示的就是在這個新core下的conf文件夾下沒有找到solrconfig.xml文件:
咱們須要將複製來的configsets/_default/conf
這個文件夾(或者solr-7.4.0/server/solr/configsets/_default/conf
文件夾)複製到solrhome/new_core/
文件夾下。
No cores
那裏點擊add core
,此時就會完整的建立一個新的core,在solrhome/new_core
文件夾下會生成新的文件:<br/>
上面咱們成功的安裝了solr,下面就要進行相關的配置。由於solr是一個開源的搜索平臺,主要功能就是把用戶輸入的搜索信息分類彙總並進行數據庫的查詢,而中文衆所周知語義比較複雜,並且中文所佔的字節和英文也有所不一樣,因此就出現了中文分詞器,實現模擬中文語義對數據進行分詞衍化。IK Analyzer正是其中的一種分詞器。
IK Analyzer在solr工程中的配置以下:
webapps/solr/WEB-INF/lib
文件夾下webapps/solr/WEB-INF/
下建立classes
文件夾,將上面下載的文件夾中的ext.dic
、IKAnalyzer.cfg.xml
、stopword.dic
三個文件複製到webapps/solr/WEB-INF/classes/
文件夾下。solrhome/conf/
目錄下咱們發現並無schema.xml文件,這和老版本又有所不一樣,老版本直接生成好了schema.xml文件,在新版本中咱們能夠發現/conf
文件夾中存在一個managed-schema
文件,這個其實就是咱們要的schema.xml
文件。可是咱們又不能直接用,具體緣由參考 博文managed-schema
文件重命名爲schema.xml
。並在schema.xml
的最後添加<fieldType>
節點:<fieldType name="text_ik" class="solr.TextField"> <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/> </fieldType>
new_core
下的Schema功能,在select下拉框中輸入text_ik
若是出現剛建立的text_ik
,說明IK中文分詞器安裝成功。未使用分詞器效果:
使用了分詞器的效果顯而易見:
<br>
solr和其餘NoSQL數據庫同樣能夠實現數據存儲,因此咱們能夠以數據庫的思想一想象一下solr,以前咱們新建立的core
就相似一個數據庫,那麼下面要配置的域
就至關於數據庫的表字段,所以要手動的去定義系統中須要的字段Field(域)。
一般咱們建立的一種Field分別對應這一類數據,用戶對同一種數據進行相同的操做。域經常使用的屬性有:
如上面的介紹,域
相似數據庫中的表字段,而咱們作項目時數據庫的字段都是根據項目需求建立的,因此域
也是如此,它是根據搜索平臺須要搜索的信息對應的數據庫表字段來建立的。
好比,在淘寶商城購買商品,咱們可能會搜索:一、品牌(對應數據庫中brand
字段);二、價格(對應數據庫中price
字段);三、商品介紹名稱(對應數據庫中title
字段)等等...
每一中域(字段)都用<field>
字段設定,好比如上的搜索數據,咱們能夠設置爲:
<field name="item_title" type="text_ik" indexed="true" stored="true"/> <field name="item_price" type="pdouble" indexed="true" stored="true"/> <field name="item_image" type="string" indexed="false" stored="true" /> <field name="item_category" type="string" indexed="true" stored="true" /> <field name="item_seller" type="text_ik" indexed="true" stored="true" /> <field name="item_brand" type="string" indexed="true" stored="true" />
在新版本的solr中,type
屬性不能單單設置爲基本的數據類型名稱了,具體用法要參考schema.xml
文件中以前已存在的配置,例如:long要寫成plong,double要寫爲pdouble,否則就會報錯。
注意:
你會奇怪域的設定不就是根據用戶搜索的數據分類來設定的嗎,那爲什麼還要指定indexed="true",緣由:可能有些數據是否是用戶輸入的查詢的,可是仍是須要在用戶搜索的同時檢索出來。
你會奇怪爲什麼要設定stored,緣由:大多數域都是要進行存儲的,可是也有不須要存儲的,好比複製域。
複製域的做用在於將某一個Field中的數據複製到另外一個域中。 因爲用戶輸入的數據多是查詢的價格,也多是商品的title,又或者是商品的品牌等... 咱們沒法預測用戶要查詢的是什麼,由此出現了搜索引擎平臺,幫助咱們對查詢數據進行分類。 因此,solr的目標是實現兩種不一樣的域能夠在同一個域中查詢(發送一次請求),而複製域
的出現正可解決這一問題。
如此,咱們爲上面要查詢的字段設定複製域:
<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/> <copyField source="item_title" dest="item_keywords"/> <copyField source="item_category" dest="item_keywords"/> <copyField source="item_seller" dest="item_keywords"/>
其中的source
屬性值要和<field>
中的name
保持一致。
在項目中,商品的數據可能會動態的添加或減小,好比原來沒有的數據,可是後來又完善添加上去了,那麼就須要動態的配置從而實現用戶能及時查詢到。
<dynamicField name="item_conf_*" type="string" indexed="true" stored="true">
<br/>
通過上面的安裝和配置你們應該已經知道如何配置Solr,那麼就會思考一個問題了:這個solr項目和咱們實際的項目查詢有什麼關係呢?是怎麼結合的呢?
solr官方提供了solrj API
,就是一個jar文件,咱們能夠經過solr官方提供的接口來實現本地項目和solr項目的交互;而這裏咱們要介紹的是Spring Data Solr,它是Spring Data家族對solrj進行封裝後的框架。
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-solr</artifactId> <version>1.5.5.RELEASE</version> </dependency>
既然是Spring家族的框架,固然要進行配置使用了,建立spring-solr.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:solr="http://www.springframework.org/schema/data/solr" xsi:schemaLocation="http://www.springframework.org/schema/data/solr http://www.springframework.org/schema/data/solr/spring-solr-1.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- solr服務器地址 --> <solr:solr-server id="solrServer" url="http://127.0.0.1:8080/solr/new_core"/> <!-- solr模板,使用solr模板可對索引庫進行CRUD的操做 --> <bean id="solrTemplate" class="org.springframework.data.solr.core.SolrTemplate"> <constructor-arg ref="solrServer"/> </bean> </beans>
必定要注意solr配置中solr服務器地址的配置,這個url
必定是solr項目訪問地址
+ /core
實例名稱組合的路徑。通常咱們新建的core實例名稱就是new_core
。
上面完成了基本的環境配置,下面則須要爲實體類中屬性添加@Field
註解標識。
通常咱們定義的實體類屬性名稱和數據庫的字段名稱類似,可是,若是使用了Solr搜索,每次查詢數據將再也不查詢數據庫,那麼Solr怎麼獲取到你要查詢的是商品的title仍是price呢?
這裏就須要使用@Field
註解,保證明體類屬性名稱和Solr索引庫中定義的Field
域名稱對應,若是當前屬性名稱和Solr索引庫域Field名稱相同,就添加@Field
名稱,若是不相同就添加@Field("域名稱")
註解。
這裏咱們這樣定義實體類 Goods
public class Goods implements Serializable{ @Field private Long id; //商品ID @Field("item_title") private String title; //商品標題 @Field("item_price") private String price; //商品價格 @Field("item_image") private String image; //商品圖片 @Field("item_category") private String category; //商品類別 @Field("item_brand") private String brand; //商品品牌 @Field("item_seller") private String seller; //商品賣家 }
本例詳細代碼請參看: Github
因爲咱們建立的是測試類,須要使用@RunWith
和@ContextConfiguration
註解加載配置文件。
在測試類中用注入Spring Data Solr操做Solr索引庫的核心類SolrTemplate
@Autowired private SolrTemplate solrTemplate;
@Test public void testAdd() { Goods goods = new Goods(1L, "IPhone SE", "120", "手機", "Apple", "Apple"); solrTemplate.saveBean(goods); solrTemplate.commit(); //提交 }
實現數據的添加:
solrTemplate
的saveBean()
方法;這個saveBean()
是用來添加普通對象類型數據到Solr索引庫的,若是是List集合這種類型,使用saveBeans()
方法。solrTemplate
的commit()
方法,提交更改;相似於咱們請求數據庫時須要關閉鏈接同樣,必須調用commit()
方法才能保存修改。@Test public void testFindById() { Goods goods = solrTemplate.getById(1, Goods.class); System.out.println("--------" + goods.getTitle()); }
@Test public void testDeleteById() { solrTemplate.deleteById("1"); solrTemplate.commit(); //提交 }
@Test public void testAddList() { List<Goods> list = new ArrayList<Goods>(); //循環插入100條數據 for (int i = 0; i < 100; i++) { Goods goods = new Goods(i + 1L, "華爲Mate" + i, String.valueOf(2000 + i), "手機", "手機", "華爲專賣店"); list.add(goods); } solrTemplate.saveBeans(list); //添加集合對象,調用saveBeans();添加普通對象類型數據,使用saveBean(); solrTemplate.commit(); //提交 }
@Test public void testPageQuery() { Query query = new SimpleQuery("*:*"); query.setOffset(20); //開始索引(默認0) query.setRows(20); //每頁記錄數(默認10) ScoredPage<Goods> page = solrTemplate.queryForPage(query, Goods.class); System.out.println("總記錄數:" + page.getTotalElements()); List<Goods> list = page.getContent(); }
上面使用new SimpleQuery
方式是聲明一個Query實例,而("*:*")
表示查詢Solr索引庫中的全部數據。Solr默認查詢的數據是前十條記錄,也就是即使使用了("*:*")
查詢,也僅僅是查詢到十條記錄。 不過Solr提供了分頁查詢的方法:setOffset()
設置開始索引位置,setRows()
設置結束索引位置(默認10);調用solrTemplate.queryForPage(query, clazz)
便是分頁查詢。
分頁查詢到的結果存儲在page
對象中,使用page.getTotalElements()
能夠獲取到查詢的總記錄數,使用page.getContent()
獲取到查詢的數據。
@Test public void testPageQueryMutil() { Query query = new SimpleQuery("*:*"); Criteria criteria = new Criteria("item_title").contains("2"); criteria = criteria.and("item_title").contains("5"); query.addCriteria(criteria); ScoredPage<Goods> page = solrTemplate.queryForPage(query, Goods.class); System.out.println("總記錄數:" + page.getTotalElements()); List<Goods> list = page.getContent(); }
如上,使用分頁插件須要實例化Criteria
類添加查詢條件,查詢是根據schema.xml
中定義的Field
域名稱查詢的,至關於根據數據庫的字段名稱查詢同樣。
@Test public void deleteAll(){ Query query = new SimpleQuery("*:*"); solrTemplate.delete(query); }
<br/>
若是你們有興趣,歡迎你們加入個人Java交流羣:671017003 ,一塊兒交流學習Java技術。博主目前一直在自學JAVA中,技術有限,若是能夠,會盡力給你們提供一些幫助,或是一些學習方法,固然羣裏的大佬都會積極給新手答疑的。因此,別猶豫,快來加入咱們吧!
<br/>
If you have some questions after you see this article, you can contact me or you can find some info by clicking these links.