solr進階八:jQuery UI Autocomplete與solr搜索結合

大致的流程:

頁面捕獲到文字 --> 傳到servletController)層,servlet層調用後臺 --> 後臺根據servlet層傳來的參數進行動態從solr中獲取數據 --> solr 數據返回到servlet層,解析 --> 展現到頁面上。

 

solr裏面新建一個core,在MySQL數據庫裏面新建一個表,從這個表導入數據到solrcore中,具體步驟可以上網查或者看我前面的教程。

SQL語句:


SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for lifeixroles
-- ----------------------------
DROP TABLE IF EXISTS `lifeixroles`;
CREATE TABLE `lifeixroles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `accountId` int(11) DEFAULT NULL,
  `level` int(11) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL,
  `accountName` varchar(255) DEFAULT NULL,
  `namePinyin` varchar(255) DEFAULT NULL,
  `l99NO` int(11) DEFAULT NULL,
  `photoPath` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of lifeixroles
-- ----------------------------
INSERT INTO `lifeixroles` VALUES ('1', '4', '38', '嶄露頭腳', 'peter', 'peter', '150104', '02/MjAwOTAzMjgyMTM1NTdfMjIwLjI0OS43OS4zNV8zMzM2MDI=.jpg');
INSERT INTO `lifeixroles` VALUES ('2', '8', '1', '小蝦米', '立方咖啡', 'lifangkafei', '150108', '20/MjAwOTAyMTYwMzQxMjBfMjIwLjI0OS43OS4zNV82MDYwNTc=..JPG');
INSERT INTO `lifeixroles` VALUES ('3', '11', '46', '名動江湖', 'nick', 'nick', '150121', '10/MjAxNDA2MTMxMTQ2MDVfMTkyLjE2OC4xOTkuNTdfNTA0NDcy.jpg');
INSERT INTO `lifeixroles` VALUES ('4', '10', '1', '小蝦米', 'oz', 'oz', '150130', '21/MjAxMjEyMjExNTA5MzlfMTgzLjM3LjM0LjI5XzIzMjA1Nw==.png');
INSERT INTO `lifeixroles` VALUES ('5', '49', '46', '李四', '立方方圓', 'li', '150163', '10/MjAwOTAyMDcxMjQwMzBfMjIwLjI0OS43OS4zNV83MjQ3ODI=..jpg');

schema.xml的部分配置參考:

分詞器:

指定數據庫配置文件:

由於新建core是拷貝solr-4.10.2\example\multicore這裏面的core,所以配置文件非常簡單。在自己的core裏面看看分詞器是否有用,結果顯示是有用的:

可是到搜索裏面搜索指定字段的部分詞語時,搜索不出,只能搜索出全名的:

查找故障很久都找不出爲什麼,包括把multiValued改爲true,雖然不知道具體原因,但是改了這個,但是沒有用,顯示出的結果帶方括號而已。

後來把這些數據導入collection1就正常了,可能是一些關鍵的東西沒有配置,因爲原來core裏面的配置是最簡單的基礎配置,這有待於後面的仔細研究學習。搜索出關鍵詞的數據:

這樣就好辦了,開始編碼!

後臺還是servletjsonjar包生成json數據返回到前臺頁面,具體步驟可以看我前面的總結教程。

對象轉換成json語句的工具類:src\com\lifeix\util\FastJsonUtil.java

package com.lifeix.util;

import com.alibaba.fastjson.JSON;

/**
 * Created by lhx on 14-12-10 下午4:15
 *
 * @project jspProject
 * @package com.lifeix.util
 * @blog http://blog.csdn.net/u011439289
 * @email [email protected]
 * @Description
 */
public class FastJsonUtil {
    /**
     * Object實體轉換爲json
     * @param object
     * @return
     */
    public static String object2json(Object object){
        JSON json = (JSON) JSON.toJSON(object);
        return json.toJSONString();
    }
}

後臺從solr服務器上獲取數據的處理類:\src\com\lifeix\util\SolrGetFtTopic2.java

package com.lifeix.util;

import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.ModifiableSolrParams;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by lhx on 14-12-9 上午10:30
 *
 * @project jspProject
 * @package com.lifeix.util
 * @blog http://blog.csdn.net/u011439289
 * @email [email protected]
 * @Description
 */
public class SolrGetFtTopic2 {
    private static final String SOLR_URL = "http://localhost:8080/solr/collection1";
    public String queryAll(String htmlWord){
        ModifiableSolrParams params = new ModifiableSolrParams();
        params.set("q","accountName:"+htmlWord);
        params.set("start",0);
        params.set("rows",10);

        params.set("sort","score desc");
        params.set("f1","*,score");

        SolrServer server = new HttpSolrServer(SOLR_URL);

        List<Map<String,Object>> listWord = new ArrayList<Map<String, Object>>();
        Map<String,Object> map = null ;
        try {
            QueryResponse response = server.query(params);
            SolrDocumentList list = response.getResults();
            for (int i = 0; i < list.size(); i++) {
                map = new HashMap<String, Object>();
                SolrDocument document = list.get(i);
                map.put("label",document.getFieldValue("l99NO") );
                map.put("value", document.getFieldValue("accountName"));
                listWord.add(map);
            }
            return  FastJsonUtil.object2json(listWord) ;
        } catch (SolrServerException e) {
            e.printStackTrace();
        }
        return null ;
    }
}

Servlet層從前臺頁面獲取輸入值,再交給後臺處理

\src\com\lifeix\servlet\JsonSolrServlet.java

package com.lifeix.servlet;


import com.lifeix.util.SolrGetFtTopic2;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;


/**
 * Created by lhx on 14-12-10 下午5:29
 *
 * @project jspProject
 * @package ${PACKAGE_NAME}
 * @blog http://blog.csdn.net/u011439289
 * @email [email protected]
 * @Description
 */
public class JsonSolrServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取網頁上文本框輸入的內容
        String htmlWord = request.getParameter("term").trim();

        String jsonStr = "" ;
        SolrGetFtTopic2 solrGetFtTopic = new SolrGetFtTopic2();
        if (!"".equals(htmlWord) && htmlWord != null){
            //傳入參數,根據參數來進行搜索
            jsonStr = solrGetFtTopic.queryAll(htmlWord);
        }

        PrintWriter pw = null;
        try {
            response.setContentType("application/json; charset=utf-8");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("Cache-Control", "no-cache");
            pw = response.getWriter();
            pw.print(jsonStr);
            pw.flush();
        }catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            if (pw != null)
                pw.close();
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request,response);
    }
}

現在是前臺頁面的jQuery UI Autocomplete代碼,這些代碼可以參考

jQuery UI Autocomplete官網的遠端緩存處理例子:

http://jqueryui.com/autocomplete/#remote-with-cache

jQuery UI AutocompletejQuery UI的自動完成組件

 

我的代碼如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Fancy Validate - jQuery UI Autocomplete</title>
<link href="jquery-ui/css/ui-lightness/jquery-ui-1.8.17.custom.css" rel="stylesheet" />
<script src="js/jquery-1.7.1.min.js"></script>
<script src="jquery-ui/js/jquery-ui-1.8.17.custom.min.js"></script>
<script src="jquery-ui/js/jquery-ui-widget-combobox.js"></script>
<style>
    body {
        font-size: 14px;
    }
    fieldset {
        width: 650px;
        margin: 0 auto;
        text-align: right;
    }
    fieldset div {
        margin: 15px auto;
    }
    .cbo .ui-button-text {
        line-height: 1.3;
        padding-top: 0;
        padding-bottom: 0;
    }
    .cbo .ui-autocomplete-input {
        width: 7.2em;
    }
</style>
<script>
    $(function() {

        var cache = {};
        $("#username").autocomplete({
            minLength: 2,
            source:function(request, response){
                var term = request.term;
                if(term in cache){
                    response(cache[term]);
                    return ;
                }
                $.getJSON('jsonsolr',request,function(data,status,xhr){
                    cache[term] = data ;
                    response(data);
                });
            }
        });

        var cache1 = {};
        $("#username1").autocomplete({
            minLength: 2,
            source:function(request, response){
                var term = request.term;
                if(term in cache1){
                    response(cache1[term]);
                    return ;
                }
                $.getJSON('jsonsolr2',request,function(data,status,xhr){
                    cache1[term] = data ;
                    response(data);
                });
            }
        });

        var cache2 = {};
        $("#l99NO").autocomplete({
            minLength: 6,
            source:function(request, response){
                var term = request.term;
                if(term in cache2){
                    response(cache2[term]);
                    return ;
                }
                $.getJSON('jsonsolrl99',request,function(data,status,xhr){
                    cache2[term] = data ;
                    response(data);
                });
            }
        });

        // 自定義source函數
        var hosts = ["gmail.com", "live.com", "hotmail.com", "yahoo.com", "cnblogs.com", "火星.com", "囧月.com"];
        $("#email1").autocomplete({
            autoFocus: true,
            source: function(request, response) {
                var term = request.term, //request.term爲輸入的字符串
                        ix = term.indexOf("@"),
                        name = term, // 用戶名
                        host = "", // 域名
                        result = []; // 結果

                result.push(term);
                // result.push({ label: term, value: term }); // json格式
                if (ix > -1) {
                    name = term.slice(0, ix);
                    host = term.slice(ix + 1);
                }
                if (name) {
                    var findedHosts = (host ? $.grep(hosts, function(value) {
                                return value.indexOf(host) > -1;
                            }) : hosts),
                            findedResults = $.map(findedHosts, function(value) {
                                return name + "@" + value; //返回字符串格式
                                // return { label: name + " @ " + value, value: name + "@" + value }; // json格式
                            });
                    result = result.concat($.makeArray(findedResults));
                }
                response(result); //呈現結果
            }
        });

        /* combobox autocomplete */
        $("#combo1").combobox();
    });
</script>
</head>
<body>
<form action="?" id="fancyform">
    <fieldset>
        <legend>jQuery UI Autocomplete</legend>
        <div>
            根據用戶名搜索(輸詞語,如:立方,提示龍號):<input id="username" type="text" />
        </div>
        <div>
            根據用戶名搜索(輸詞語,如:立方,提示用戶名):<input id="username1" type="text" />
        </div>
        <div>
            根據龍號來搜索(輸全部,如:150108):<input id="l99NO" type="text" />
        </div>
        <div>
            Email(隨便輸):<input id="email1" type="text" />
        </div>
        <div class="cbo">
            Combobox(選擇):<select id="combo1">
            <option value="">請選擇</option>
            <option value="1">地球</option>
            <option value="2">月球</option>
            <option value="3">火星</option>
        </select>
        </div>
    </fieldset>
</form>
</body>
</html>

最後的實現效果如下:

——————————————————————————————————————

————————————————————————————————————————


後記:

因爲前面改過multiValued的值,改爲true了,所以搜索返回的值是帶方括號的,導致生成的json語句不是正規的json,所以前臺頁面解析不了,通過斷點調試可以發現這個問題:

另外這個例子還有一個缺點,就是中文輸入的話,輸入詞語不能馬上觸發事件,要接着敲鍵盤或者敲一個空格鍵,jQuery纔會把文本中的文字送到後臺處理,而英文和數字沒有這個問題,這個還要處理!



資料下載:http://pan.baidu.com/s/1jG1gAHK

 

20141212日 補

 

今天上午調試了以下jQuery UI Autocomplete代碼,改爲以下的模樣:

界面輸入的時候,還是要多按一個字符才能與後臺交互。仔細一看,在漢字沒有輸入的前提下,就有了一個小下劃線:

當設置minLength: 0時,此時就開始觸發了,輸入完後默認已經觸發過一次,不會觸發,再在鍵盤上按多一個鍵,我按了空格,結果就能把按鍵之前的文本發送到後臺了。

可是,當你用其他瀏覽器的時候,居然沒有這個現象,輸入中文的時候,文本框沒有小劃線。

這是chrome瀏覽器的:

這是IE11的效果

原來這是jQuery UI Autocomplete在火狐狸上的一個bug

上網找了一下,真的有解決的方法啊!

參考:修復jQuery UI AutocompleteFF中不支持中文的BUG

我的是在jquery-ui-1.8.17.custom.min.js這個文件裏改,搜索:blur.autocomplete

127行,原代碼格式有點難看,格式化一下代碼:

然後變成:

再在此處加上:

.bind("input.autocomplete",function(){
            b.search(self.item);
        })

刷新一下火狐狸,輸入詞語,馬上就與後臺交互了:


發佈了57 篇原創文章 · 獲贊 13 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章