关于搜索功能的关键字高亮显示是如何实现的

本着学习的态度,我想问一下,如果我想为自己的博客做一个全文检索的功能,像简书,百度,不只是标题,并且包括内容,实现相同关键字匹配,并且关键字高亮显示,这个功能是该由前端来完成还是该由后端来完成

为避免大家把问题搞混淆,我分步骤来问,希望各位爷分步骤来解答写疑惑,谢谢

问题一:

如何实现关键字的匹配,当然如何,并不是简单的比如我输入 'java如何实现全文检索' ,就去类容中直接匹配 'java如何实现全文检索' 全字段,中间多个字 ,这条都匹配不到
想要的效果如下
百度:

clipboard.png

简书:

clipboard.png

当然,可能人家实现这种效果是花了大价钱,大精力的,不求和这个一模一样,能类似就好,我也不晓得有没有这种框架

问题二:

如何实现关键字高亮显示,不过傻瓜式的 全字段匹配才高亮就算了,看百度和简书,好像是拆开了,不清楚是框架有这么个功能还是说是内部技术人员自己实现的;而且我看百度里,关键字是加了"em"标签,那这个加标签的功能是由后台返回数据给前端,前端完成高亮,还是后台获取数据后,直接添加标签再返回给前端,然后前端设置"em"为红色直接显示。

阅读 8k
2 个回答

基于关键词的高亮需要由搜索引擎支持。可以从ElasticsearchSolr这两个基于lucene开源的搜索引擎选择一个学习一下。

从搜索的结果看Elasticsearch比Solr似乎要流行一些。遇到问题应该更容易找人帮忙解决。这东西还是有些复杂的,要花一段时间上手。可以看官方文档感受一下。

  • 中文的文档只有2.0版本的,已经很久没更新了,目前最新的版本已经是6.5了
  • Elasticsearch默认的分词器是满足不了中文分词需求的,需要使用中文分词器(如IK分词器)。

补充

如果后端使用的是java,并且只是想做个简单的基于关键词的高亮搜索功能,还要快速上手,那么hibernate search看起来是个不错的选择

jq中的实现方法:

//搜索结果高亮显示
function encode(s) {
    return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/([\\\.\*\[\]\(\)\$\^])/g, "\\$1");
}
function decode(s) {
    return s.replace(/\\([\\\.\*\[\]\(\)\$\^])/g, "$1").replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&");
}
function loopSearch(s, obj) {
    var cnt = 0;
    if (obj.nodeType == 3) {
        cnt = replace(s, obj);
        return cnt;
    }
    for (var i = 0, c; c = obj.childNodes[i]; i++) {
        if (!c.className || c.className != "highlight")
            cnt += loopSearch(s, c);
    }
    return cnt;
}
function replace(s, dest) {
    var r = new RegExp(s, "g");
    var tm = null;
    var t = dest.nodeValue;
    var cnt = 0;
    if (tm = t.match(r)) {
        cnt = tm.length;
        t = t.replace(r, "{searchHL}" + decode(s) + "{/searchHL}")
        dest.nodeValue = t;
    }
    return cnt;
}
function highlight(s,l) {
    if (s.length == 0) {
        return false;
    }
    s = encode(s).toLowerCase();
    var obj_li = $('#'+l+'').find('h4');//显示内容的容器id下的标题h4,可以改成你自己用的其他的标签
    obj_li.each(function (i, o) {
        var t = o.innerHTML.replace(/<span\s+class=.?highlight.?>([^<>]*)<\/span>/gi, "$1");
        o.innerHTML = t;
        var cnt = loopSearch(s, o);
        t = o.innerHTML
        var r = /{searchHL}(({(?!\/searchHL})|[^{])*){\/searchHL}/g
        t = t.replace(r, "<span class='highlight'>$1</span>");
        o.innerHTML = t;
    });
}

使用:
例如:你的内容是显示在这个div#aaaa内,搜索内容的标题是h4标签显示的,那么调用上面的方法:highlight('呵呵','aaaa'),结果内容中的呵呵就显示高亮了。

抛砖引玉

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题