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

jopen 10年前

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.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);                }

</div>

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

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;      }

</div>

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

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(UUID.randomUUID().toString());          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");          }      }        }

</div>

搜索结果集展示如下:


查询: keywords:文字        页码1/1,总共找到2条符合的记录.    作者:林云熙  描述:<font color='red'>文字</font>控,我无悔,纵是情殇离人泪  关键字:<font color='red'>文字</font>      作者:苏若年  描述:Java程序猿, 爱音乐,爱生活,爱<font color='red'>文字</font>  关键字:Java,音乐,生活,<font color='red'>文字</font>
出处:[http://www.cnblogs.com/dennisit/p/3623984.html]
</div>