一个Solr搜索实例,增删改查+高亮+分页

今天个人coding的模块测试,所以闲暇之余继续研究solr,然后顺带写了一个实例,随便搞的,solr真心不熟,期待认识热爱搜索的朋友,共同进步.

1.配置schema.xml文件[solr\collection1\conf\目录下]

因为schema默认定义了一些Field,我们这里选取[id,title,description, author]这几个属性,将id主键type配置为string,其它几个type配置为自定义的ik分词器

   <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
   <field name="title" type="text_ik" indexed="true" stored="true" multiValued="true"/>
   <field name="description" type="text_ik" indexed="true" stored="true"/>
   <field name="author" type="text_ik" indexed="true" stored="true"/>
   <field name="keywords" type="text_ik" indexed="true" stored="true"/>

Ik分词器定义如下

    <!--定义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>

2. 编写solr操作类SearchEngine.java,solrJ操作索引参看文章: http://www.cnblogs.com/dennisit/p/3623974.html3.这里演示solrj搜索高亮

/**
     * solrJ搜索 高亮显示
     *
     * @author pudongping
     *
     * @param server
     *                     solr客户端
     * @param queryString
     *                     查询串
     * @param pageNum
     *                     分页 页码
     * @param pageSize
     *                     每页显示大小
     * @return
     */
    public static Page<QzoneArticle> queryComHighlight(SolrServer server, String queryString, int pageNum,int pageSize){
        SolrQuery query = new SolrQuery();
        query.setQuery(queryString);
        query.setHighlight(true);//开启高亮功能
        query.addHighlightField("description");//高亮字段
        query.addHighlightField("keywords");
        query.setHighlightSimplePre("<font color=‘red‘>");//渲染标签
        query.setHighlightSimplePost("</font>");//渲染标签
        query.setStart((pageNum-1)*pageSize);
        query.setRows(pageSize);
        QueryResponse response = null;
        try {
            response = server.query(query);
        } catch (SolrServerException e) {
            e.printStackTrace();
            return null;
        }
        //查询结果集
        SolrDocumentList lists = response.getResults();

        //对象结果集
        List<QzoneArticle> items = new ArrayList<QzoneArticle>();

        //查询到的记录总数
        long totalRow = Long.valueOf(response.getResults().getNumFound()).intValue();

        String tmpId = "";

        Map<String,Map<String,List<String>>> highlightMap=response.getHighlighting();
         for (SolrDocument solrDocument : lists) {
             QzoneArticle at = new QzoneArticle();
             tmpId=solrDocument.getFieldValue("id").toString();
             at.setId(tmpId);
             at.setAuthor(solrDocument.getFieldValue("author").toString());
             List<String> descList=highlightMap.get(tmpId).get("description");
             List<String> keywsList=highlightMap.get(tmpId).get("keywords");
             if(descList!=null && descList.size()>0){
                 at.setDescription(descList.get(0));
             }else{
                 //获取并设置高亮的字段title
                 at.setDescription(solrDocument.getFieldValue("description").toString());
             }
             if(keywsList!=null && keywsList.size()>0){
                 at.setKeywords(keywsList.get(0));
             }else{
                 at.setKeywords(solrDocument.getFieldValue("keywords").toString());
             }
             items.add(at);
         }

        //填充page对象
        return new Page<QzoneArticle>(pageNum, pageSize, totalRow, items);

    }

搜索高亮是找到关键字所在的记录域,然后追加前后缀,重新填充到对象,这里拆开来将是两个步骤,第一步设置高亮域,第二步查询结果追加渲染标记,填充到对象.所以这个可以抽取出来写成一个公用的方法

4.抽取高亮操作,实现公用方法

    /**
     * 根据关键字查询 [测试通过 - 使用 solr内部转换机制]
     * @param <T>
     * @param server    solr客户端
     * @param keyword    搜索关键字
     * @param pageNum    当前页码
     * @param pageSize    每页显示的大小
     * @param clzz        对象类型
     * @return
     */
    public static <T>Page<T> queryHighter(SolrServer server,String solrql,
            int pageNum,int pageSize,List<String> hlField, String preTag,String postTag,Class<T> clzz,String idName){
        SolrQuery query = new SolrQuery();
        query.setQuery(solrql);
        //设置高亮显示
        query.setHighlight(true);
        //添加高亮域
        for(String hlf : hlField){
            query.addHighlightField(hlf);
        }
        //渲染标签
        query.setHighlightSimplePre(preTag);
        query.setHighlightSimplePost(postTag);
        //分页查询
        query.setStart((pageNum-1)*pageSize);
        query.setRows(pageSize);
        QueryResponse response = null;
        try {
            response = server.query(query);
        } catch (SolrServerException e) {
            e.printStackTrace();
            return null;
        }

        //查询到的记录总数
        long totalRow = Long.valueOf(response.getResults().getNumFound()).intValue();
        //查询结果集
        List<T> items = new ArrayList<T>();

        //查询结果集
        SolrDocumentList solrDocuments = response.getResults();
        try {
            Object obj = null;
            Method m = null;
            Class<?> fieldType = null;
            Map<String,Map<String,List<String>>> highlightMap=response.getHighlighting();
            for(SolrDocument solrDocument : solrDocuments) {
                    obj = clzz.newInstance();
                    Collection<String> fieldNames = solrDocument.getFieldNames();            //得到所有的属性名
                    for (String fieldName : fieldNames) {
                        //需要说明的是返回的结果集中的FieldNames()比类属性多
                        Field[] filedArrays = clzz.getDeclaredFields();                        //获取类中所有属性
                        for (Field f : filedArrays) {
                            //如果实体属性名和查询返回集中的字段名一致,填充对应的set方法
                            if(f.getName().equals(fieldName)){

                                //获取到的属性名
                                //private java.lang.String com.test.model.Article.id
                                f = clzz.getDeclaredField(fieldName);    

                                //属性类型
                                //private java.lang.String com.test.model.Article.id
                                fieldType = f.getType();    

                                //构造set方法名  setId
                                String dynamicSetMethod = dynamicMethodName(f.getName(), "set");

                                //获取方法
                                //public void com.test.model.Article.setId(java.lang.String)
                                m = clzz.getMethod(dynamicSetMethod, fieldType);

                                //获取到的值
                                LOG.info(f.getName() + "-->" + dynamicSetMethod+ "=" + fieldType.cast(solrDocument.getFieldValue(fieldName)));

                                //获取fieldType类型
                                fieldType = getFileType(fieldType);

                                //获取到的属性
                                m.invoke(obj, fieldType.cast(solrDocument.getFieldValue(fieldName)));

                                for(String hl : hlField){
                                    if(hl.equals(fieldName)){
                                        String idv = solrDocument.getFieldValue(idName).toString();
                                        List<String> hlfList=highlightMap.get(idv).get(fieldName);
                                        if(null!=hlfList && hlfList.size()>0){
                                            //高亮添加
                                            m.invoke(obj, fieldType.cast(hlfList.get(0)));
                                        }else{
                                            //正常添加
                                            m.invoke(obj, fieldType.cast(solrDocument.getFieldValue(fieldName)));
                                        }
                                    }
                                }

                            }

                        }

                    }
                    items.add(clzz.cast(obj));
            }

        } catch (Exception e) {
            LOG.error("highlighter query error." + e.getMessage(), e);
            e.printStackTrace();
        }

        //填充page对象
        return new Page<T>(pageNum, pageSize, totalRow, items);
    }

    public static Class<?> getFileType(Class<?> fieldType){
        // 如果是 int, float等基本类型,则需要转型
        if (fieldType.equals(Integer.TYPE)) {
            return Integer.class;
        } else if (fieldType.equals(Float.TYPE)) {
            return Float.class;
        } else if (fieldType.equals(Double.TYPE)) {
            return  Double.class;
        } else if (fieldType.equals(Boolean.TYPE)) {
            return  Boolean.class;
        } else if (fieldType.equals(Short.TYPE)) {
            return  Short.class;
        } else if (fieldType.equals(Long.TYPE)) {
            return  Long.class;
        } else if(fieldType.equals(String.class)){
            return  String.class;
        }else if(fieldType.equals(Collection.class)){
            return  Collection.class;
        }
        return null;
    }

需要说明的是,这里的方法定义并不是很完善,因为反射的属性可能是一个集合,所以在利用反射转换之前,需要进行更精确地判断,这实例中实体对象中的属性为简单类型,所以这个方法可以处理.

5.junit测试

package com.test.search;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.apache.solr.client.solrj.SolrServer;
import org.junit.Before;
import org.junit.Test;

import com.plugin.page.Page;
import com.plugin.solr.client.SolrClient;
import com.plugin.solr.engine.SolrEngineHandler;
import com.test.model.QzoneArticle;

public class SolrTest {

    private SolrServer server;

    @Before
    public void init(){
        String solrURL = "http://localhost:8888/solr";
        server = SolrClient.getHttpSolrServer(solrURL);
    }

    @Test
    public void qzoneAdd(){
        List<QzoneArticle> lists = new ArrayList<QzoneArticle>();
        QzoneArticle qz1 = new QzoneArticle();
        qz1.setId(UUID.randomUUID().toString());
        qz1.setAuthor("苏若年");
        qz1.setDescription("Java程序猿, 爱音乐,爱生活,爱文字");
        qz1.setKeywords("Java,音乐,生活,文字");

        QzoneArticle qz2 = new QzoneArticle();
        qz2.setId(UUID.randomUUID().toString());
        qz2.setAuthor("林云熙");
        qz2.setDescription("文字控,我无悔,纵是情殇离人泪");
        qz2.setKeywords("文字");

        lists.add(qz1);
        lists.add(qz2);

        SearchEngine.addBeans(server, lists);
    }

    @Test
    public void qzoneDeLId(){
        String id = "4f1b6b87-c824-4e38-a431-9a8f50e7af0c";
        SolrEngineHandler.deleteById(server, "id", id);
    }

    @Test
    public void qzoneDeLIds(){
        List<String> ids = new ArrayList<String>();
        ids.add("d026e3ef-b89a-4ce2-9fbb-aa195ed2070b");
        ids.add("9deb98ca-5a65-424d-95ad-91e87c2bde2c");
        ids.add("5576650d-5517-43d5-987c-6d7135588e1f");
        SolrEngineHandler.deleteByIds(server, "id", ids);
    }

    @Test
    public void qzoneDeLAll(){
        SolrEngineHandler.deleteAllIndex(server);
    }

    @Test
    public void qzoneHLQuery(){
        String solrql = "keywords:文字";
        List<String> hlFields = new ArrayList<String>();
        hlFields.add("description");
        hlFields.add("keywords");
        String preTag = "<font color=‘red‘>";
        String postTag = "</font>";
        Page<QzoneArticle> page = SearchEngine.queryHighter(server,solrql , 1, 10, hlFields, preTag, postTag, QzoneArticle.class, "id");
        formatPrint(page, solrql);
    }

    //测试通过
    @Test
    public void qzoneCommonHLQuery(){
        String solrql = "description:文字";
        Page<QzoneArticle> page = SearchEngine.queryComHighlight(server, solrql , 1, 10);
        formatPrint(page, solrql);
    }

    @Test
    public void qzoneQuery(){
        String solrql = "文字";
        Page<QzoneArticle> page = SearchEngine.query(server,solrql , 1, 10,QzoneArticle.class);
        formatPrint(page, solrql);
    }

    @Test
    public void qzoneUpdate(){
        QzoneArticle qz = new QzoneArticle();
        qz.setId("5576650d-5517-43d5-987c-6d7135588e1f");
        qz.setAuthor("林云熙");
        qz.setDescription("文字控,我无悔,纵是情殇离人泪");
        qz.setKeywords("文字");
        SearchEngine.updateBean(server, qz, "id");
    }

    @Test
    public void pingSolr(){
        System.out.println("ping solr result: " +SolrEngineHandler.ping(server));
    }

    public void formatPrint(Page<QzoneArticle> page,String solrql){
        System.out.println("查询: " + solrql
                + "\t\t页码" + page.getPageNum()
                + "/" + page.getTotalPage()
                + ",总共找到" + page.getTotalRow()+"条符合的记录.\n");

        for(QzoneArticle qz: page.getItems()){
            System.out.println("作者:" + qz.getAuthor());
            System.out.println("描述:" + qz.getDescription());
            System.out.println("关键字:" + qz.getKeywords() + "\n\n");
        }
    }

}

搜索结果集展示如下:

查询: keywords:文字        页码1/1,总共找到2条符合的记录.

作者:林云熙
描述:<font color=‘red‘>文字</font>控,我无悔,纵是情殇离人泪
关键字:<font color=‘red‘>文字</font>

作者:苏若年
描述:Java程序猿, 爱音乐,爱生活,爱<font color=‘red‘>文字</font>
关键字:Java,音乐,生活,<font color=‘red‘>文字</font>

时间: 2024-08-27 21:55:49

一个Solr搜索实例,增删改查+高亮+分页的相关文章

SpringBoot-Vue实现增删改查及分页小DEMO

前言 主要通过后端 Spring Boot 技术和前端 Vue 技术来简单开发一个demo,实现增删改查.分页功能以及了解Springboot搭配vue完成前后端分离项目的开发流程. 开发栈 前端 开发工具:WebStorm 开发框架:vue + axios 包管理工具: npm 打包工具:webpack 后端 开发工具:IDEA 开发框架:Springboot + mybatis 打包工具:maven 数据库: MySQL PS:假设以上的的工具你都安装好啦,写CRUD小DEMO时进坑了,这篇

受老师邀请给学院国创队伍培训php,以一个实战新闻cms增删改查demo为例,写的文档讲义供大家参考

PHP实战基础——以一个新闻cms的增删改查为例 一.        环境配置 二.        数据库创建 三.        增删改查demo 连接数据库 <?php $link=mysql_connect("localhost","root","root"); mysql_select_db("demo",$link); mysql_query("set names utf8"); ?>

一个初学者对于jdbc增删改查的一点看法和困惑

我们今周学习了 jdbc的增删改查,总之是各种恍然大悟然后又接着陷入新一轮的苦恼中(相信你们一定深有体会),由于本人的java基础较差,所以是在实践中是各种稀奇古怪的错误频发,接下来我列举几个这几天我犯得让我的老师哭笑不得的错误. 首先是错误:com.microsoft.sqlserver.jdbc.SQLServerException: 已生成用于更新的结果集. 这是我运行我的删除操作之后报的错误,结果是原表无变化,经打断点检查id已经上传,换句话来说程序没有问题,各位小伙伴们能从这只言片语中

用SpringBoot+MySql+JPA实现对数据库的增删改查和分页

使用SpringBoot+Mysql+JPA实现对数据库的增删改查和分页      JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中.  使用Springboot和jpa对数据库进行操作时,能够大大减少我们的工作量,在jpa中,已经在底层封装好了增删查的功能和sql语句,可以使我们进行快速开发 项目流程 一.新建一个项目 二.配置文件 #数据源配置 spring.dat

SpringBoot JPA实现增删改查、分页、排序、事务操作等功能

今天给大家介绍一下SpringBoot中JPA的一些常用操作,例如:增删改查.分页.排序.事务操作等功能.下面先来介绍一下JPA中一些常用的查询操作: //And --- 等价于 SQL 中的 and 关键字,比如 findByHeightAndSex(int height,char sex): public List<User> findByHeightAndSex(int height,char sex); // Or --- 等价于 SQL 中的 or 关键字,比如 findByHeig

web day19 Service层处理事务(利用ThreadLocal),TxQueryRunner小工具,单表练习(增删改查操作),分页

Service事务 DAO中不是处理事务的地方,因为DAO中的每个方法都是对数据库的一次操作 在Service中不应该出现Connection,它应该只在DAO中出现, 因为它是JDBC的东西,JDBC的东西是用来连接数据库的 修改JdbcUtils 我们把对事务的开启和关闭放到JdbcUtils中,在Service中调用JdbcUtils的方法来完成事务的处理, 但在Service中就不会再出现Connection这一"禁忌"了. 代码 public class JdbcUtils

springDataJPQL实现增删改查及分页,原生sql查询,根据方法命名规则实现查询

一.使用方法 1.在dao中定义开一个方法,使用方法的参数设置jpql,并且使用方法的返回值接受查询结果,在方法上添加@query注解,在注解中写jpql语句进行增删改查,测试 2.使用原生的sql语句:dao中定义一个方法,在方法中添加@query注解,在注解中添加原生sql语句,并且添加一个属性:nativeQuery=true,测试 3.方法命名规则查询: 通过以肯定的规则,定义一个方法,框架本身就可以根据方法名生成一块个sql语句进行查询,规则: 1.必须以findBy开头 2.查询某个

Spring mvc整合mybatis基于mysql数据库实现用户增删改查及其分页显示的完整入门实例【转】

Spring mvc整合mybatis例子, 基于mysql数据库实现对用户的增.删.改.查,及分页显示的完整例子. 查询显示用户 添加用户 更新用户 官方验证: 项目截图 必须修改applicationContext.xml中mysql的配置为本地的,否则启动失败. 另外jar包多一个ehcache.jar无关紧要,删除即可. 1. 使用阿里巴巴Druid连接池(高效.功能强大.可扩展性好的数据库连接池.监控数据库访问性能.支持Common-Logging.Log4j和JdkLog,监控数据库

在 idea 下搭建的第一个MyBatis项目及增删改查用法

Mybatis搭建第一个项目 1. 简介 1.1 什么是 MyBatis? MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型.接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录. 如何获取Mybatis? GitHub 源码:https://gith