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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章