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


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

    1.配置schema.xml文件[solrcollection1conf目录下]

    因为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.html
    3.这里演示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 
                    + "		页码" + page.getPageNum() 
                    + "/" + page.getTotalPage() 
                    + ",总共找到" + page.getTotalRow()+"条符合的记录.
    ");
            
            for(QzoneArticle qz: page.getItems()){
                System.out.println("作者:" + qz.getAuthor());
                System.out.println("描述:" + qz.getDescription());
                System.out.println("关键字:" + qz.getKeywords() + "
    
    ");
            }
        }
        
    }
    复制代码

    搜索结果集展示如下:

    复制代码
    查询: keywords:文字        页码1/1,总共找到2条符合的记录.
    
    作者:林云熙
    描述:<font color='red'>文字</font>控,我无悔,纵是情殇离人泪
    关键字:<font color='red'>文字</font>
    
    
    作者:苏若年
    描述:Java程序猿, 爱音乐,爱生活,爱<font color='red'>文字</font>
    关键字:Java,音乐,生活,<font color='red'>文字</font>
    复制代码
  • 相关阅读:
    bzoj 4245: [ONTAK2015]OR-XOR【按位贪心】
    bzoj 4247: 挂饰【dp】
    bzoj 3503: [Cqoi2014]和谐矩阵【高斯消元】
    bzoj 3029: 守卫者的挑战【概率dp】
    bzoj 3732: Network【克鲁斯卡尔+树链剖分】
    bzoj 1040: [ZJOI2008]骑士【基环树+树形dp】
    bzoj 3668: [Noi2014]起床困难综合症【贪心】
    bzoj 2157: 旅游【树链剖分+线段树】
    bzoj 4521: [Cqoi2016]手机号码【数位dp】
    bzoj 3437: 小P的牧场【斜率优化】
  • 原文地址:https://www.cnblogs.com/fx2008/p/4164557.html
Copyright © 2020-2023  润新知