SSM的Solr集成使用

最近學習SSM的例子其中涉及到了Solr的使用,作爲Lucene在企業級應用中的擴展很值得研究和學習

因此記錄實踐開發中的後端實現步驟和遇到的問題

安裝Solr:

下載網址:https://lucene.apache.org/solr/downloads.html

選擇zip的windos安裝包

下載後解壓進入bin目錄(F:\solr-8.4.0\bin),打開cmd窗口

啓動命令

solr start

訪問端口爲8983,我們可以通過 localhost:8983 或者 127.0.0.1:8983 訪問 Solr 網頁

啓動後控制界面如下圖:

在圖中紅色區域,需要我們創建 Solr 的索引庫,在剛纔的命令窗口中輸入:

solr create -c mycore

其中 mycore 爲 core 的名字,然後在重啓solr

重啓命令:

solr restart -p 8983


 

在查詢之前,我們需要做一些相關的操作:

1、新建applicationContext-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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="httpSolrClient" class="org.apache.solr.client.solrj.impl.HttpSolrClient">
        <constructor-arg name="builder" value="http://localhost:8983/solr/mycore"/>
    </bean>

</beans>

2、引入依賴包

<dependency>
            <groupId>org.apache.solr</groupId>
            <artifactId>solr-solrj</artifactId>
            <version>7.3.0</version>
        </dependency>

3、編寫測試類插入數據


import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.common.SolrInputDocument;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;

import javax.ws.rs.core.Context;

@ContextConfiguration(locations = {"classpath:applicationContext-solr.xml"})
public class TestSolrJ extends AbstractJUnit4SpringContextTests {
    @Autowired
    private SolrClient solrServer;

    @Test
    public void testSave() throws Exception {
        SolrInputDocument inputDocument = new SolrInputDocument();
        inputDocument.addField( "id","35");
        inputDocument.addField("item_title","ssm項目開發實戰");
        inputDocument.addField( "item_content", "ssm指的是:Srping MVC + Spring + Mybatis" );
        inputDocument.addField("item_image","www.ssm.png");
        inputDocument.addField( "author", "wly" );

        solrServer.add( inputDocument );
        solrServer.commit();
    }
}

5、修改配置文件

進入F:\solr-8.4.0\server\solr\mycore\conf,修改managed-schema

將我們將我們導入的字段類型改成string

然後再重啓,重新進入控制界面,選擇剛纔我們創建的索引庫,就可以查詢到對應的數據

 

solr聯合多個字段進行檢索

在我們的應用中經常會有這種情形:當用戶輸入某個字符串查找時,需要如果在標題及內容中存在這個字會串時均要把記錄加載出來,通過引入copyField及multiValue這兩個標籤便可解決這種問題。

配置文件:

<field name="id" type="string" multiValued="false" indexed="true" required="true" stored="true"/>
  <field name="item_image" type="string" stored="false" docValues="false"/>
  <field name="item_content" type="string"/>
  <field name="author" type="string"/>
  <field name="item_title" type="string"/>
  <field name="item_title_str" type="string" indexed="true" stored="false" multiValued="true"/> 

 

<copyField source="item_title" dest="item_title_str" maxChars="256"/>
  <copyField source="item_content" dest="item_title_str" maxChars="256"/>

展示圖如下:

 

IKAnalyzer 分詞器

Solr 可通過自帶的分詞器 smartcn 或者第三方分詞器 IKAnalyzer 來實現,IKAnalyzer 分詞效果較好,所以這裏使用 IKAnalyzer 分詞器。

下載 IKAnalyzer 分詞器 Jar 包

ik-analyzer-solr5-5.x.jar

solr-analyzer-ik-5.1.0.jar

將其中的兩個 Jar 包放入 F:\solr-8.4.0\server\solr-webapp\webapp\WEB-INF\lib 下

修改  F:\solr-8.4.0\server\solr\mycore\conf 下的 managed-schema文件

<!-- 添加ik分詞器 -->
    <fieldType name="text_ik" class="solr.TextField"> 
      <analyzer type="index" isMaxWordLength="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/> 
      <analyzer type="query" isMaxWordLength="true"  class="org.wltea.analyzer.lucene.IKAnalyzer"/> 
    </fieldType>

type="index" 代表創建索引時的分詞

type="query" 代表查詢時的分詞

<!-- 需要分詞的字段 -->
    <field name="title" type="text_ik" indexed="true" stored="true" required="true" multiValued="false" />

我們對文章標題進行分詞查詢

配置其它字段名和類型,否則會查詢出集合類型的數據

    <field name="comment_num" type="string"/>
    <field name="downvote" type="string"/>
    <field name="upvote" type="string"/>
    <field name="nick_name" type="string"/>
    <field name="img_url" type="string"/>
    <field name="rpt_time" type="pdate"/>
    <field name="content" type="text_general"/>
    <field name="category" type="string"/>
    <field name="u_id" type="string"/>
    <field name="personal" type="string"/>

注意:content 字段不能設置爲 String 類型,否則內容過多會超出範圍,報異常。除了日期和 content 字段外其它都設置爲 String類型。

然後重啓solr

開始在項目中進行引用

在 web.xml 中引入 applicationContext-solr.xml 配置文件

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
      classpath:spring-mybatis.xml,
      classpath:applicationContext-redis.xml,
      classpath:applicationContext-activemq.xml,
      classpath:applicationContext-solr.xml
    </param-value>
    </context-param>

新建SolrService 接口,包含了基本的查詢,刪除等操作

public interface SolrService {
    /**
     * 根據關鍵字搜索文章並分頁
     * @param keyword
     * @return
     */
    PageHelper.Page<UserContent> findByKeyWords(String keyword, Integer pageNum, Integer pageSize);

    /**
     * 添加文章到solr索引庫中
     * @param userContent
     */
    void addUserContent(UserContent userContent);

    /**
     * 根據solr索引庫
     * @param userContent
     */
    void updateUserContent(UserContent userContent);

    /**
     * 根據文章id刪除索引庫
     * @param id
     */
    void deleteById(Long id);
}

創建其實現類SolrServiceImpl 

查詢步驟,先是設置查詢條件,設置分頁信息,然後獲取結果集,遍歷結果集創建文檔對象,然後封裝到對應的實體類中

再進行分頁組合數據格式,如果發生異常則返回 null。

public class SolrServiceImpl implements SolrService {

    @Autowired
    HttpSolrClient solrClient;
    @Override
    public PageHelper.Page<UserContent> findByKeyWords(String keyword, Integer pageNum, Integer pageSize) {
        SolrQuery solrQuery = new SolrQuery( );
        //設置查詢條件
        solrQuery.setQuery( "title:"+keyword );
        //設置高亮
        solrQuery.setHighlight( true );
        solrQuery.addHighlightField( "title" );
        solrQuery.setHighlightSimplePre( "<span style='color:red'>" );
        solrQuery.setHighlightSimplePost( "</span>" );

        //分頁
        if (pageNum == null || pageNum < 1) {
            pageNum = 1;
        }
        if (pageSize == null || pageSize < 1) {
            pageSize = 7;
        }
        solrQuery.setStart( (pageNum-1)*pageSize );
        solrQuery.setRows( pageSize );
        solrQuery.addSort("rpt_time", SolrQuery.ORDER.desc);
        //開始查詢

        try {
            QueryResponse response = solrClient.query( solrQuery );
            //獲得高亮數據集合
            Map<String, Map<String, List<String>>> highlighting = response.getHighlighting();
            //獲得結果集
            SolrDocumentList resultList = response.getResults();
            //獲得總數量
            long totalNum = resultList.getNumFound();
            List<UserContent> list = new ArrayList<UserContent>(  );
            for(SolrDocument solrDocument:resultList){
                //創建文章對象
                UserContent content = new UserContent();
                //文章id
                String id = (String) solrDocument.get( "id" );
                Object content1 = solrDocument.get( "content" );
                Object commentNum = solrDocument.get( "comment_num" );
                Object downvote = solrDocument.get( "downvote" );
                Object upvote = solrDocument.get( "upvote" );
                Object nickName = solrDocument.get( "nick_name" );
                Object imgUrl = solrDocument.get( "img_url" );
                Object uid = solrDocument.get( "u_id" );
                Object rpt_time = solrDocument.get( "rpt_time" );
                Object category = solrDocument.get( "category" );
                Object personal = solrDocument.get( "personal" );
                //取得高亮數據集合中的文章標題
                Map<String, List<String>> map = highlighting.get( id );
                String title = map.get( "title" ).get( 0 );

                content.setId( Long.parseLong( id ) );
                content.setCommentNum( Integer.parseInt( commentNum.toString() ) );
                content.setDownvote( Integer.parseInt( downvote.toString() ) );
                content.setUpvote( Integer.parseInt( upvote.toString() ) );
                content.setNickName( nickName.toString() );
                content.setImgUrl( imgUrl.toString() );
                content.setuId( Long.parseLong( uid.toString() ) );
                content.setTitle( title );
                content.setPersonal( personal.toString() );
                Date date = (Date)rpt_time;
                content.setRptTime(date);
                List<String> clist = (ArrayList)content1;
                content.setContent( clist.get(0).toString() );
                content.setCategory( category.toString() );
                list.add( content );
            }
            PageHelper.startPage(pageNum, pageSize);//開始分頁
            PageHelper.Page page = PageHelper.endPage();//分頁結束
            page.setResult(list);
            page.setTotal(totalNum);
            return page;
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void addUserContent(UserContent cont) {
        if(cont!=null){
            addDocument(cont);
        }
    }

    @Override
    public void updateUserContent(UserContent cont) {
        if(cont!=null){
            addDocument(cont);
        }
    }

    @Override
    public void deleteById(Long id) {
        try {
            solrClient.deleteById(id.toString());
            solrClient.commit();
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void addDocument(UserContent cont){
        try {
            SolrInputDocument inputDocument = new SolrInputDocument();
            inputDocument.addField( "comment_num", cont.getCommentNum() );
            inputDocument.addField( "downvote", cont.getDownvote() );
            inputDocument.addField( "upvote", cont.getUpvote() );
            inputDocument.addField( "nick_name", cont.getNickName());
            inputDocument.addField( "img_url", cont.getImgUrl() );
            inputDocument.addField( "rpt_time", cont.getRptTime() );
            inputDocument.addField( "content", cont.getContent() );
            inputDocument.addField( "category", cont.getCategory());
            inputDocument.addField( "title", cont.getTitle() );
            inputDocument.addField( "u_id", cont.getuId() );
            inputDocument.addField( "id", cont.getId());
            inputDocument.addField( "personal", cont.getPersonal());
            solrClient.add( inputDocument );
            solrClient.commit();
        } catch (SolrServerException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

controller層的編寫

 @RequestMapping("/index_list")
    public String findAllList(Model model, @RequestParam(value = "keyword",required = false) String keyword,
                                    @RequestParam(value = "pageNum",required = false) Integer pageNum ,
                                    @RequestParam(value = "pageSize",required = false) Integer pageSize) {
        User user = (User)getSession().getAttribute("user");
        if(user!=null){
            model.addAttribute( "user",user );
        }
        if(StringUtils.isNotBlank(keyword)){
            Page<UserContent> page = solrService.findByKeyWords( keyword ,pageNum,pageSize);
            model.addAttribute("keyword", keyword);
            model.addAttribute("page", page);
        }else {
            Page<UserContent> page =  findAll(pageNum,pageSize);
            model.addAttribute( "page",page );
        }
        return "../index";
    }

單元測試類 TestSolrJ 中新建方法 testSaveAll,並將所需要的配置文件都進行加載,此步驟是將數據庫的數據加載到solr


@ContextConfiguration(locations = {"classpath:applicationContext-redis.xml","classpath:spring-mybatis.xml","classpath:applicationContext-activemq.xml","classpath:applicationContext-solr.xml"})
public class TestSolrJ extends AbstractJUnit4SpringContextTests {
    @Autowired
    private SolrClient solrServer;
    @Autowired
    private UserContentService userContentService;

   

    @Test
    public void testSaveAll() throws IOException, SolrServerException {
        List<UserContent> list = userContentService.findAll();
        if(list!=null && list.size()>0){
            for (UserContent cont : list){
                SolrInputDocument inputDocument = new SolrInputDocument();
                inputDocument.addField( "comment_num", cont.getCommentNum() );
                inputDocument.addField( "downvote", cont.getDownvote() );
                inputDocument.addField( "upvote", cont.getUpvote() );
                inputDocument.addField( "nick_name", cont.getNickName());
                inputDocument.addField( "img_url", cont.getImgUrl() );
                inputDocument.addField( "rpt_time", cont.getRptTime() );
                inputDocument.addField( "content", cont.getContent() );
                inputDocument.addField( "category", cont.getCategory());
                inputDocument.addField( "title", cont.getTitle() );
                inputDocument.addField( "u_id", cont.getuId() );
                inputDocument.addField( "id", cont.getId());
                inputDocument.addField( "personal", cont.getPersonal());
                solrServer.add( inputDocument );
            }
        }

        solrServer.commit();
    }
}

加載後可以啓動測試:

http://localhost:8983/solr/mycore/select?q=title:%E6%A2%A6&hl=true&hl.fl=title&hl.simple.pre=%3Cspan+style%3D%27color:red%27%3E&hl.simple.post=%3C/span%3E&start=0&rows=7&sort=rpt_time+desc

發佈了19 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章