Solr4 智能提示Suggest

 

一、背景

  搜索的智能提示是一个搜索应用的标配,主要作用是避免用户输入错误的搜索词,并将用户引导到相应的关键词上,提升用户体验。

  由于中文的特点,如果搜索自动提示可以支持拼音的话会给用户带来更大的方便,免得切换输入法。

二、目标

    • 基于用户的历史搜索关键字进行提示
    • 同时支持汉字,拼音输入
    • 支持前缀匹配,比如输入“ch”可能提示出“重庆”
    • 支持缩写输入,比如输入“cq”能提示出“重庆”
    • 多音字支持,比如输入“chongqing”或者“zhongqing”都能提示出“重庆”
    • 输出结果,根据用户查询关键字的频率进行排序,暂时不考虑个性化需求

三、分析与解决方案

       假设我们的搜索应用是基于solrcloud实现的,主要是对商家信息进行搜索,包括商家名称(store_name)、商家地址(address)。

       (1). 用户每天输入大量的查询关键字,我们把查询的关键字记录下来,目前通过异步队列写入到mysql中,后期考虑写入到hbase中

       (2). 用户输入的关键字可能是汉字、数字,英文,拼音,特殊字符等等,由于需要实现拼音提示,所以我们需要把汉字转换成拼音,java中考虑使用pinyin4j组件实现转换。

       (3). 汉字转换拼音的过程中,顺便提取出拼音缩写,如“chongqing”,"zhongqing"--->"cq","zq"

       (4). 要支持多音字提示,对查询串转换成拼音后,需要实现一个全排列组合,考虑到查询串可能比较长导致全排列比较的,具体算法需要做限制处理。

 

Solr Suggest实现智能提示

     首先Solr作为一个应用广泛的搜索引擎系统,它内置了智能提示功能,叫做Suggest模块。该模块有两种可选方案做智能提示:

      (1)、基于提示词文本做智能提示

      (2)、基于索引中得某个字段建立索引词库做智能提示

     suggest的配置相对简单, 下面开始写 主要是使方式, 自定义的建议词文本,放在跟solrconfig.xml同一级目录下即可

     例如:solr\solr_home\collections\collection1\conf\suggest.txt 

 

下面给出suggest在solrconfig.xml里配置的代码(中文信息注意删去)   配置如下:

<searchComponent name="suggest" class="solr.SpellCheckComponent">  

    <str name="queryAnalyzerFieldType">string</str>  

    <lst name="spellchecker">    

        <str name="name">suggest</str>    

        <str name="classname">org.apache.solr.spelling.suggest.Suggester</str>    

        <str name="lookupImpl">org.apache.solr.spelling.suggest.tst.TSTLookup</str>    

        <str name="field">my_word</str>  

        <float name="threshold">0.0001</float> 

        <!-- 使用自定义suggest词库词--> 

        <str name="sourceLocation">suggest.txt</str> 

        <str name="spellcheckIndexDir">spellchecker</str>

        
<str name="comparatorClass">freq</str> <str name="buildOnOptimize">true</str> <str name="buildOnCommit">true</str> </lst> </searchComponent> <requestHandler name="/suggest" class="org.apache.solr.handler.component.SearchHandler"> <lst name="defaults"> <str name="spellcheck">true</str> <str name="spellcheck.dictionary">suggest</str> <str name="spellcheck.count">10</str> <str name="spellcheck.onlyMorePopular">true</str> <str name="spellcheck.extendedResults">false</str> <str name="spellcheck.collate">true</str> <!--<str name="spellcheck.build">true</str> --> </lst> <arr name="components"> <str>suggest</str> </arr> </requestHandler>

说明:

 1.solr的suggest基于solr.SpellCheckComponent

 2.queryAnalyzerFieldType 参数为string,在这不要定义复杂分词,如果是根据某一个索引字段,意义不大

 3.field字段名,表示基于schema中的某一个索引字段

 4.threshold限制一些不常用的词出现,值越大过滤纸越多

 5.sourceLocation用于设置字典,如果有一个字典能记录用户常搜索的字,更灵活的控制,可以存放一些高质量的query短语

 6.spellcheckIndexDir如果已经设置spellcheck,那么可以在此制定目录

 7.字典格式如下

# This is a sample dictionary file.

acquire

accidentally\t2.0

accommodate\t3.0

文本格式utf-8,#开头表示注释,被忽略

每一个词一行,后面带权重

 8.配置词典后在requestHandler中设置spellcheck.onlyMorePopular为true,可以根据权重排序

 9.spellcheck.count返回行

  配置完成重启服务后,设置参数suggest/?spellcheck.build=true来创建spellchecker的索引

 然后输入:http://ip:port/corename/suggest?q=xxx进行搜索了

 接下来就是前台js实现的问题了。

 当然也可以通过solrj来进行搜索

CommonsHttpSolrServer server = new CommonsHttpSolrServer(

                "http://ip:port/corename/");

    SolrQuery params = new SolrQuery();

        String token = "Solr";

        params.set("qt", "/suggest");

        params.set("q", token);

        params.set("spellcheck.build", "true");

        QueryResponse response = null;

        try {

            response = server.query(params);

            System.out.println("查询耗时:" + response.getQTime());

        } catch (SolrServerException e) {

            System.err.println(e.getMessage());

            e.printStackTrace();

        } catch (Exception e) {

            System.err.println(e.getMessage());

            e.printStackTrace();

        } finally {

        } 

        SpellCheckResponse spellCheckResponse = response

                .getSpellCheckResponse();

        if (spellCheckResponse != null) {

            List<Suggestion> suggestionList = spellCheckResponse

                    .getSuggestions();

            for (Suggestion suggestion : suggestionList) {

                System.out.println("Suggestions NumFound: "

                        + suggestion.getNumFound());

                System.out.println("Token: " + suggestion.getToken());

                System.out.print("Suggested: ");

                List<String> suggestedWordList = suggestion.getAlternatives();

                for (String word : suggestedWordList) {

                    System.out.println(word + ", ");

                }

                System.out.println();

            }

        }

 

-----OK

 

你可能感兴趣的:(suggest)