Solr搜索實例,增刪改查+高亮+分頁

jopen 10年前發布 | 86K 次閱讀 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.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(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");
        }
    }

}

搜索結果集展示如下:


查詢: 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]
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!