Solr及Spring-Data-Solr入門學習

Solr的安裝與配置html

多數搜索引擎應用都必須具備某種搜索功能,而搜索功能每每大量的消耗資源致使應用程序運行緩慢。爲此,出現了各類用於構建搜索的應用程序,咱們要學習的solr正是其中的一款開源搜索平臺。前端

Apache Solr 是創建在Lucene(全文搜索引擎)之上,幫助我從大量的數據中尋找所需信息。不只限於搜索,Solr也可用於儲存目的。像其餘NoSQL數據庫同樣,它是一種非關係數據儲存和處理技術。java

<!--more-->git

下面咱們開始喜聞樂見的手摸手教學,教你優雅的整合SSM框架和Solr搜索框架。github

  • 項目開源地址: 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>節點下的配置。

  • 七、啓動Tomcat,在瀏覽器中訪問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/文件夾下。

  • 八、重啓Tomcat服務器,發現仍是沒有出現新的core,點擊No cores那裏點擊add core,此時就會完整的建立一個新的core,在solrhome/new_core文件夾下會生成新的文件:

  • 至此Solr已經安裝完成。

<br/>

中文分詞器

上面咱們成功的安裝了solr,下面就要進行相關的配置。由於solr是一個開源的搜索平臺,主要功能就是把用戶輸入的搜索信息分類彙總並進行數據庫的查詢,而中文衆所周知語義比較複雜,並且中文所佔的字節和英文也有所不一樣,因此就出現了中文分詞器,實現模擬中文語義對數據進行分詞衍化。IK Analyzer正是其中的一種分詞器。

IK Analyzer在solr工程中的配置以下:

  • 一、下載ikanalyzer相關配置文件,由於Maven倉庫中的ikanalyzer版本太老,solr5以上的版本都不支持,因此這裏提供一個新版本: 傳送門
  • 二、將下載的jar文件copy到webapps/solr/WEB-INF/lib文件夾下
  • 三、在webapps/solr/WEB-INF/下建立classes文件夾,將上面下載的文件夾中的ext.dicIKAnalyzer.cfg.xmlstopword.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>
  • 六、重啓Tomcat服務器,從新訪問項目,點擊new_core下的Schema功能,在select下拉框中輸入text_ik若是出現剛建立的text_ik,說明IK中文分詞器安裝成功。

測試

未使用分詞器效果:

使用了分詞器的效果顯而易見:

<br>

配置域

solr和其餘NoSQL數據庫同樣能夠實現數據存儲,因此咱們能夠以數據庫的思想一想象一下solr,以前咱們新建立的core就相似一個數據庫,那麼下面要配置的就至關於數據庫的表字段,所以要手動的去定義系統中須要的字段Field(域)。

一般咱們建立的一種Field分別對應這一類數據,用戶對同一種數據進行相同的操做。域經常使用的屬性有:

  • name: 指定域的名稱
  • type: 指定域的類型
  • indexed: 是否索引
  • stored: 是否儲存
  • required: 是否必須
  • multiValued: 是否多值

域的介紹

如上面的介紹,相似數據庫中的表字段,而咱們作項目時數據庫的字段都是根據項目需求建立的,因此也是如此,它是根據搜索平臺須要搜索的信息對應的數據庫表字段來建立的。

好比,在淘寶商城購買商品,咱們可能會搜索:一、品牌(對應數據庫中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/>

Spring Data Solr入門

通過上面的安裝和配置你們應該已經知道如何配置Solr,那麼就會思考一個問題了:這個solr項目和咱們實際的項目查詢有什麼關係呢?是怎麼結合的呢?

solr官方提供了solrj API,就是一個jar文件,咱們能夠經過solr官方提供的接口來實現本地項目和solr項目的交互;而這裏咱們要介紹的是Spring Data Solr,它是Spring Data家族對solrj進行封裝後的框架。

  • 注意 上面咱們在Tomcat中部署的solr項目是不須要再進行位置上的變更的,也就是他必須是已經在Tomcat中部署好的,而咱們本身的項目啓動時不能再使用8080端口(由於solr自己就佔用了Tomcat的端口,而咱們的項目是能夠改變運行端口的,總之二者不管是否是在同一個Tomcat服務器中部署都不能使用同一端口)。咱們經過配置文件就能訪問到這個指定端口的solr項目(Tomcat必須是啓動着的),經過Spring Data Solr提供的接口就能實現交互: 所謂交互 --> 等價於查詢solr中以存在的數據,而後將結果返回:
    • 用戶查詢,請求接口將查詢條件交給solr(經過Spring Data Solr提供的接口訪問Solr服務),solr對自身已存在的數據進行查找

準備

導入jar文件

<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註解

上面完成了基本的環境配置,下面則須要爲實體類中屬性添加@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; //商品賣家
}
  • 注意:舒適提示一下,你們建立實體類的時候儘可能養成一個習慣:實現Serializable序列化接口。不序列化早晚會遇到問題。

實例

本例詳細代碼請參看: Github

  1. 因爲咱們建立的是測試類,須要使用@RunWith@ContextConfiguration註解加載配置文件。

  2. 在測試類中用注入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(); //提交
}

實現數據的添加:

  1. 實例化一個實體類,並添加數據。
  2. 調用solrTemplatesaveBean()方法;這個saveBean()是用來添加普通對象類型數據到Solr索引庫的,若是是List集合這種類型,使用saveBeans()方法。
  3. 調用solrTemplatecommit()方法,提交更改;相似於咱們請求數據庫時須要關閉鏈接同樣,必須調用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.

相關文章
相關標籤/搜索