ASP.NET SignalR 與 LayIM2.0 配合輕松實現Web聊天室(七) 之 歷史記錄查詢(時間,關鍵字,圖片,文件),關鍵字高亮顯示。


前言

  上一篇講解了如何自定義右鍵菜單,都是前端的內容,本篇內容就一個:查詢。聊天歷史紀錄查詢,在之前介紹查找好友的那篇博客里已經提到過 Elasticsearch,今天它又要上場了。對於Elasticsearch不感冒的同學呢,本篇可以不用看啦。

  from baidu:

  ElasticSearch是一個基於Lucene的搜索服務器。它提供了一個分布式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java開發的,並作為Apache許可條款下的開放源碼發布,是當前流行的企業級搜索引擎。設計用於 雲計算中,能夠達到實時搜索,穩定,可靠,快速,安裝使用方便。
我們建立一個網站或應用程序,並要添加搜索功能,令我們受打擊的是:搜索工作是很難的。我們希望我們的搜索解決方案要快,我們希望有一個零配置和一個完全免費的搜索模式,我們希望能夠簡單地使用JSON通過HTTP的索引數據,我們希望我們的搜索服務器始終可用,我們希望能夠一台開始並擴展到數百,我們要實時搜索,我們要簡單的多租戶,我們希望建立一個雲的解決方案。Elasticsearch旨在解決所有這些問題和更多的問題。

DEMO演示

  隨便聊聊天:

    

  圖片類型過濾

  

  文件類型過濾

  

  關鍵字查詢

  

  時間段查詢(截圖略)

實戰講解

  layim 已經給我們提供了打開歷史紀錄頁面的接口。不過查詢歷史紀錄頁面需要自己布局。由於html+css不是我的強項,我就直接把聊天室的結構拿過去了。聊天歷史紀錄頁面上就一個ajax請求,還有數據綁定,這些都不多做介紹。主要是講一下后台如何進行數據查詢和細節注意事項。主要還是講到了Elasticsearch,對於Elasticsearch不感興趣的小伙伴可以略過本篇。

  首先呢,想要查詢歷史紀錄,要先保存數據。那么在之前的LayIMHub中的接受消息方法中,我們已經把數據順便在ES中存儲一份。(實例代碼如下)

  

 //保存消息
            Task.Run(() => {
                MessageFactory.CreateInstance(ChatMessageSaveType.SearchEngine).Send(message);
            });
            ChatInfo chatInfo;
            var mine = message.mine;
//聊天記錄model chatInfo
= new ChatInfo { addtime = message.addtime, avatar = mine.avatar, content = mine.content, nickname = mine.username, qq = mine.id, timespan = message.addtime.ToTimestamp(), roomid = message.roomid, isfile = mine.content.IndexOf("file(") > -1, isimg = mine.content.IndexOf("img[") > -1 };
//在es中,index是索引的意思,相當於數據庫中的表
bool result= es.Index(chatInfo); return new SendMessageResult(result);

  於是,我們用戶聊天的時候,將數據就保存到了ES當中,正如SQL Server做搜索一樣,想用ES搜索,它也需要保存一份。我們打開客戶端看一下數據,如果你也安裝了ES和head插件,那么瀏覽器輸入 127.0.0.1:9200/_plugin/head就可以看數據了。

  

  那么數據已經有了,我們看一下查詢條件。 1,關鍵字查詢 2,類型查詢 3,時間段查詢 4,聊天室id查詢(最基本,A和B聊天不能查詢A和C的歷史紀錄)

  他們之間的查詢關系是and條件,如果用sql表示的話就是   select * from chathistory where roomid=1 and content like '%誅仙%' and 。。。

  那么我們就需要把SQL翻譯成ES的語法。最終結果是這樣的。

  

{
  "query": {
    "filtered": {
      "filter": {
        "and": [  //and關系
          {
            "query": {
              "match": {
                "roomid": "FRIEND_14895_14894"  //根據聊天室id過濾
              }
            }
          },
          {
            "term": {
              "isimg": false     //是否是img
            }
          },
          {
            "range": {  //range查詢
              "addtime": {   //查詢字段是時間類型
                "gt": "2016-08-16T00:00:00"    //gt 是大於某個時間 lt 是小於某個時間
              }
            }
          }
        ]
      }
    }
  },
  "from": 0, //分頁
  "size": 50,
  "sort": { //排序
    "addtime": {
      "order": "asc"
    }
  },
  "highlight": { //高亮
    "fields": {
      "content": {} //content高亮顯示
    }
  }
}

  核心查詢方法如下:(.NET客戶端用的PlainElastic.Net,他已經對構造查詢語句做了封裝,類似ORM,但是語法我用的太蹩腳了,於是只有自己拼“SQL”了)

  public JsonResultModel SearchHistoryMsg(string groupId, DateTime? starttime = null, DateTime? endtime = null, string keyword = null, bool isfile = false, bool isimg = false, int pageIndex = 1, int pageSize = 20)
        {
            string st = starttime == null ? "" : starttime.Value.ToString("yyyy-MM-dd");
            string et = endtime == null ? "" : endtime.Value.ToString("yyyy-MM-dd");
            int from = (pageIndex - 1) * pageSize;
            //某個聊天組查詢
            string queryGroup = "{\"query\": {\"match\": { \"roomid\": \"FRIEND_14895_14894\" }}}";
            //關鍵字查詢
            string queryKeyWord = "{ \"query\": {\"match_phrase\": {\"content\": {\"query\": \"" + keyword + "\",\"slop\": 0} } }}";
            //是否圖片 查詢
            string queryImg = "{ \"term\": {\"isimg\": true }}";
            //是否包含文件查詢
            string queryFile = "{ \"term\": {\"isfile\": true }}";
            //大於小於某個時間段查詢
            string queryTimeRange = "{\"range\": {\"addtime\": { \"gt\": \""+st+"\",\"lt\": \""+et+"\" }} }";
            //大於某個時間
            string queryTimeRangeGt = "{\"range\": {\"addtime\": { \"gt\": \""+st+"\"}} }";
            //小於某個時間
            string queryTimeRangeLt = "{\"range\": {\"addtime\": { \"lt\": \"" + et + "\" }} }";
            string queryAnd = queryGroup;
            if (starttime != null&&endtime!=null) {
                queryAnd += "," + queryTimeRange;
            }
            if (starttime != null) {
                queryAnd += "," + queryTimeRangeGt;
            }
            if (endtime != null) {
                queryAnd += "," + queryTimeRangeLt;
            }
            if (!string.IsNullOrEmpty(keyword)) {
                queryAnd += "," + queryKeyWord;
            }
            if (isfile) {
                queryAnd += "," + queryFile;
            }
            if (isimg) {
                queryAnd += "," + queryImg;
            }
            //最終查詢語句
            string query = "  {\"query\": {\"filtered\": {\"filter\": {\"and\": [" + queryAnd + "] }}},\"from\": " + from + ",\"size\": " + pageSize + ",\"sort\": {\"addtime\": { \"order\": \"asc\"}},\"highlight\": {\"fields\": { \"content\": {}} }}";


            var result = eschat.QueryBayConditions(query);
            return JsonResultHelper.CreateJson(result, true);
        }

  那么,只要條件給對了,結果自然就是我們想要的結果了。

  不過,搜索也是會出現bug的,例如,如果輸入關鍵字img或者file,就會出現下面這種情況,因為數據庫里存的就是那一串html,然后到界面上又做了相應的處理,這個情況就有點蛋疼了。

  

     有同學會注意到 img旁邊有em標簽,其實這個就是關鍵字高亮的原因所在。好比,上邊的演示中,誅仙兩個字是高亮的,查看源代碼,他們每個字都會有em標簽包含,那是因為ES在查詢過程中,你可以使用高亮功能,他會把符合條件的關鍵字給你加上特殊標簽,當然我們也可以自定義標簽,例如 b,i ,tag  都可以。然后給一個樣式,比如我這里 em {color:red} 那么高亮功能就出來了。

總結

  本篇呢基本上都是圍繞Elasticsearch來講,由於屬於一些額外的功能,所以也沒講太細。搜索功能用SQL或者MySQL或者其他的一些數據庫都能實現,主要是對接layim要注意,綁定的方式以及圖片文件的html轉換等。

 

      下篇預告【中級】ASP.NET SignalR 與 LayIM2.0 配合輕松實現Web聊天室(八) 之 聊天室的小細節,你都注意到了嗎?

   

   想要學習的小伙伴,可以關注我的博客哦,我的QQ:645857874,Email:fanpan26@126.com

  GitHub:https://github.com/fanpan26/LayIM_NetClient/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM