`
zhanshenny
  • 浏览: 259047 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

搜索关键字拼音智能提示实现

 
阅读更多

一、背景

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

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

  目前大多数的电子商务网站都支持拼音提示功能。

 

二、目标

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

三、分析与解决方案

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

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

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

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

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

 

1. Solr Suggest实现智能提示

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

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

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

 配置如下:

 schema.xml:

<field name="suggest" type="suggest_text" indexed="true" stored="false" multiValued="true" />
----------------------------------------------

<copyField source="store_name" dest="suggest" />

<copyField source="address" dest="suggest" />   

 

----------------------------------------------

 

<fieldType name="suggest_text" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true">
        <analyzer type="index">
                <tokenizer class="solr.KeywordTokenizerFactory" />
                <filter class="solr.SynonymFilterFactory" 
                        synonyms="synonyms.txt" 
                        ignoreCase="true" 
                        expand="true" />
                <filter class="solr.StopFilterFactory" 
                        ignoreCase="true" 
                        words="stopwords.txt" 
                        enablePositionIncrements="true" />
                <filter class="solr.LowerCaseFilterFactory" />
                <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt" />
        </analyzer>
        <analyzer type="query">
                <tokenizer class="solr.KeywordTokenizerFactory" />
                <filter class="solr.StopFilterFactory" 
                        ignoreCase="true" 
                        words="stopwords.txt" 
                        enablePositionIncrements="true" />
                <filter class="solr.LowerCaseFilterFactory" />
                <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt" />
        </analyzer>
</fieldType>

 

 

 

solrconfig.xml

<searchComponent class="solr.SpellCheckComponent" name="suggest">
        <str name="queryAnalyzerFieldType">suggest_text</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">suggest</str>
                <float name="threshold">0</float>
                <str name="buildOnCommit">true</str>
        </lst>
        <lst name="spellchecker">
                <str name="name">default</str>
                <str name="field">suggest</str>
                <str name="classname">solr.DirectSolrSpellChecker</str>
                <str name="distanceMeasure">internal</str>
                <float name="accuracy">0.2</float>
                <int name="maxEdits">2</int>
                <int name="minPrefix">1</int>
                <int name="maxInspections">50</int>
                <int name="minQueryLength">2</int>
                <float name="maxQueryFrequency">0.01</float>
        </lst>
        <lst name="spellchecker">
                <str name="name">wordbreak</str>
                <str name="classname">solr.WordBreakSolrSpellChecker</str>
                <str name="field">suggest</str>
                <str name="combineWords">true</str>
                <str name="breakWords">true</str>
                <int name="maxChanges">10</int>
        </lst>
</searchComponent>
        
        
<requestHandler class="org.apache.solr.handler.component.SearchHandler" name="/suggest">
        <lst name="defaults">
                <str name="spellcheck">true</str>
                <str name="spellcheck.dictionary">default</str>
                <str name="spellcheck.dictionary">wordbreak</str>
                <str name="spellcheck.dictionary">suggest</str>
                <str name="spellcheck.onlyMorePopular">true</str>
                <str name="spellcheck.count">10</str>
                <str name="spellcheck.collate">true</str>
        </lst>
        <arr name="components">
                <str>suggest</str>
        </arr>
</requestHandler>

 

配置完成后,启动solrcloud:

 

solr1:
      java -Djetty.port=8983 -Dbootstrap_confdir=./solr/collection1/conf -Dcollection.configName=myconf -DzkRun -DnumShards=1 -jar start.jar &

 

solr2:
      java -Djetty.port=7574 -DzkHost=localhost:9983  -Dcollection.configName=myconf -DnumShards=1 -jar start.jar & 

 

 查询:

第一次查询时,添加spellcheck.build=true参数来触发spellckecker建立索引,

http://localhost:8983/solr/collection1/suggest?q=cq&spellcheck.build=true&distrib=false 

而后:

http://localhost:8983/solr/collection1/suggest?q=cq&distrib=false 

 

存在问题

该方法存在的问题是:

     返回的结果是基于索引中字段的词频进行排序,不是用户搜索关键字的频率,因此不能将一些热门关键字排在前面(网上有人提到定制SuggestWordScoreComparator来实现)

     拼音提示,多音字,缩写还是要另外加索引字段

 

 

2. Solrcloud建立单独的collection,利用solr前缀查询实现

配置如下:

solr.xml:

 

<cores adminPath="/admin/cores" defaultCoreName="collection1" host="${host:}" hostPort="${jetty.port:8983}" hostContext="${hostContext:solr}" zkClientTimeout="${zkClientTimeout:15000}">
    <core name="collection1" instanceDir="collection1" />
    <core name="collection2" instanceDir="collection2" />
 </cores>

 

cp -r collection1 collection2 

修改collection2中的schema.xml和solrconfig.xml

 

schema.xml:

-----------------------fields--------------------------------

   <field name="kw" type="string" indexed="true" stored="true" />

   <field name="pinyin" type="string" indexed="true" stored="false" multiValued="true"/>

   <field name="abbre" type="string" indexed="true" stored="false" multiValued="true"/>

   <field name="kwfreq" type="int" indexed="true" stored="true" />

   <field name="_version_" type="long" indexed="true" stored="true"/>

 

   <field name="suggest" type="suggest_text" indexed="true" stored="false" multiValued="true" />

------------------multiValued表示字段是多值的-------------------------------------

注:

     kw为原始关键字

     pinyin和abbre的multiValued=true,在使用solrj建此索引时,定义成集合类型即可:如关键字“重庆”的pinyin字段为{chongqing,zhongqing}, abbre字段为{cq, zq}

     kwfreq为用户搜索关键的频率,用于查询的时候排序

 

------------------uk----------------------------------

   <uniqueKey>kw</uniqueKey>

   <defaultSearchField>suggest</defaultSearchField> 

-------------------------------------------------------

  <copyField source="kw" dest="suggest" />

  <copyField source="pinyin" dest="suggest" />

  <copyField source="abbre" dest="suggest" />

 

------------------suggest_text----------------------------------

    <!-- suggest type-->

    <fieldType name="suggest_text" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true">

        <analyzer type="index">

                <tokenizer class="solr.KeywordTokenizerFactory" />

                <filter class="solr.SynonymFilterFactory" 

                        synonyms="synonyms.txt" 

                        ignoreCase="true" 

                        expand="true" />

                <filter class="solr.StopFilterFactory" 

                        ignoreCase="true" 

                        words="stopwords.txt" 

                        enablePositionIncrements="true" />

                <filter class="solr.LowerCaseFilterFactory" />

                <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt" />

        </analyzer>

        <analyzer type="query">

                <tokenizer class="solr.KeywordTokenizerFactory" />

                <filter class="solr.StopFilterFactory" 

                        ignoreCase="true" 

                        words="stopwords.txt" 

                        enablePositionIncrements="true" />

                <filter class="solr.LowerCaseFilterFactory" />

                <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt" />

        </analyzer>

    </fieldType>

 

 

启动命令:

solr1:
java -Xms1024m -Xmx1024m -Djetty.port=8983 -Dbootstrap_conf=true -DzkHost=localhost:9983 -DnumShards=1 -jar start.jar &

solr2:
java -Djetty.port=7574 -DzkHost=localhost:9983  -DnumShards=1 -jar start.jar & 

 

 

solrj前缀查询语法:

 

    private SolrQuery getSuggestQuery(String prefix, Integer limit) {

        SolrQuery solrQuery = new SolrQuery();

        StringBuilder sb = new StringBuilder();

        sb.append("kw:").append(prefix).append("*");

        sb.append(" or pinyin:").append(prefix).append("*");

        sb.append(" or abbre:").append(prefix).append("*");

        solrQuery.setQuery(sb.toString());

 

        solrQuery.addField("kw");

        solrQuery.addField("kwfreq");

        solrQuery.addSort("kwfreq", SolrQuery.ORDER.desc);

        solrQuery.setStart(0);

        solrQuery.setRows(limit);

 

        return solrQuery;

    }

 

3. mongodb实现拼音智能提示

    实现原理类似于方案2,利用mongodb强调的查询功能,数组和正则匹配。参考http://www.2cto.com/database/201203/123450.html

    经过测试,效果与方案2类似。

 

四、总结

    以上三个方案都能实现搜索关键字智能提示,方案1还需要研究完善才能实现基于用户搜索频率热词排序,方案3需要另外部署mongodb服务,不利用维护,所以本人在实际项目中采用了方案2.

 

 

 

 

 

 

 

 

 

 

分享到:
评论
3 楼 panghaoyu 2017-03-12  
不需要solr、mongodb、任何数据库、jsp\php\asp,就能实现了
2 楼 panghaoyu 2017-03-12  

其实还有其他方法,
比如可以嵌入搜索引擎的搜索自动提示js,就可以快速实现搜索框智能提示的功能
但是搜索引擎的数据不能个性化定制,很可能不适合自己的网站,
比如我输入lb,是提示萝卜呢,还是提示蜡笔小新?
92find.com提供同baidu、淘宝搜索框类似的搜索智能提示功能,可以全拼匹配、拼音首字母匹配、智能容错、模糊匹配,更重要的是,可以自定义要提示的词条及其权重
1 楼 颖宝blingbling 2017-02-16  
<div></div>

相关推荐

    VBA代码助手专业版4.4.6 AI生成VBA代码 VBA代码解释器

    关键字+空格, 神键手输入提示,代码智能补齐 双击Tab代码对齐, ALT+L字符串拼接, SHIFT+ENTER自动换行,括号自动补齐,代码区中文标点符号自动矫正,窗体控件批量生成 ,变量名及函数名中文拼音首字母输入提示, 代码行号

    VBA代码助手专业版3.7.8.0

    关键字+空格, 神键手输入提示,代码智能补齐 双击Tab代码对齐, ALT+L字符串拼接, SHIFT+ENTER自动换行,括号自动补齐,代码区中文标点符号自动矫正,窗体控件批量生成 ,变量名及函数名中文拼音首字母输入提示, 代码行号 ...

    C#开发实例大全(基础卷).软件开发技术联盟(带详细书签) PDF 下载

    实例205 实现气泡提示窗口 275 实例206 从桌面右下角显示的Popup窗口提醒 276 实例207 设置可执行文件的生成图标 278 第10章 MDI窗体和继承窗体 279 10.1 MDI窗体的使用 280 实例208 设置窗体为父窗体 280 实例209 ...

    网新中英文企业手机电脑一体化建站专业版 v4.9.rar

    2、程序智能化SEO设计:特别针对百度、谷歌等搜索引擎进行关键字优化设计,让客户快速找到您的网站; 3、程序操作简单:拥有完善的网站前台和后台全智能化管理功能,所有网站信息均可在后台进行更新,非专业人士也...

    网新中英文企业手机电脑一体化建站高级版 v4.8.rar

    2、程序智能化SEO设计:特别针对百度、谷歌等搜索引擎进行关键字优化设计,让客户快速找到您的网站; 3、程序操作简单:拥有完善的网站前台和后台全智能化管理功能,所有网站信息均可在后台进行更新,非专业人士也...

    网新中英文企业手机电脑一体化建站通用版 v4.9.rar

    2、程序智能化SEO设计:特别针对百度、谷歌等搜索引擎进行关键字优化设计,让客户快速找到您的网站; 3、程序操作简单:拥有完善的网站前台和后台全智能化管理功能,所有网站信息均可在后台进行更新,非专业人士也...

    网新中英文企业手机电脑一体化建站视频版 v5.8.rar

    2、程序智能化SEO设计:特别针对百度、谷歌等搜索引擎进行关键字优化设计,让客户快速找到您的网站; 3、程序操作简单:拥有完善的网站前台和后台全智能化管理功能,所有网站信息均可在后台进行更新,非专业人士也...

    网新中英文企业手机电脑一体化建站标准版 v4.9.rar

    2、程序智能化SEO设计:特别针对百度、谷歌等搜索引擎进行关键字优化设计,让客户快速找到您的网站; 3、程序操作简单:拥有完善的网站前台和后台全智能化管理功能,所有网站信息均可在后台进行更新,非专业人士也...

    EXCEL必备工具箱EXCELtool.rar

    人工双面打印、汉字转拼音、区域加密、个人所得税、未确认融资费用、按揭贷款/一般贷款利息、各种复利、实际利率法摊销、专业水准的套表数据汇总、穿透查询以及隐藏/取消隐藏工作表、工作表导出为文件等300多个超级...

    PinPKM-V201525(官网发布的最后一个免费无使用限制版本)

    4、对标签功能进行完善,可直接输入关键字,并支持大量标签后快捷搜索等 5、对知识点列表显示字段格式等保存进行简化 6、对界面进行一些相关功能的整合,希望让您能更方便相关功能 等等 版本8.2.0 [1]更新时间:2009...

    针式PinPKM-V201506(免费无使用限制)

    4、对标签功能进行完善,可直接输入关键字,并支持大量标签后快捷搜索等 5、对知识点列表显示字段格式等保存进行简化 6、对界面进行一些相关功能的整合,希望让您能更方便相关功能 等等 版本8.2.0 [1]更新时间:2009...

    SuperNotepad

    19) 汉字转拼音/缩写 20) 两种方式打开拖入文档 (注:请拖到[标题栏]或[状态栏],否则识别为链接; 在[设置]中可配置拖入文档打开方式[插入/新建]) 21) 支持多种格式UTF-8, BIG5, GB2321, Unicode,Unicode...

    精易模块[源码] V5.15

    2、改名“文件_搜索1”改为“文件_搜索_深度”并修正备注及深度问题,感谢易友【@小爬虫】反馈。 3、改善“时间_取现行时间戳”优化代码,提高执行效率,感谢易友【@小爬虫】反馈。 4、改善“文本_逐字分割”改善...

    Excel新增工具集

    7、按类别拆分一个工作表中的行记录(组)到新表:是指将一个工作表中的多条记录按按照某一列或某两列的类别关键(第一关键字和第二关键字)字拆分成若干个结构相同的工作表,它适合于档案数据记录的分类。...

Global site tag (gtag.js) - Google Analytics