Monthly Archives: January 2012

Solr Suggest实现搜索智能提示

智能提示简介

搜索的智能提示目前是各大搜索的标配应用,主要作用是避免用户输入错误的搜索词,同时将用户引导到相应的关键词搜索上

Solr Suggestion智能提示模块

作为一个应用广泛的搜索引擎系统,Solr内置了智能提示功能,它在Solr里叫做Suggest模块.该模块可选择基于提示词文本做智能提示,还支持通过针对索引的某个字段建立索引词库做智能提示。在诸多文档中都推荐使用基于索引来做智能提示,因此我们目前的实现也是采取该方案。

Solr Suggest的配置要点

Suggest字段的选择

因为现在整个平台是基于SPU的构建的,因此决定采用SPU关键属性组合及类目名称来做Suggest的索引字段。首先在schema.xml中添加存储Suggest的新字段,如下:

 <field name="suggestion" type="string" indexed="true" stored="true"
        termVectors="true" multiValued="true"/>

在该field的配置中,FieldType的选择非常关键,通常建议智能提示字段的FieldType不需要配置复杂的Analyzer,避免因为分词导致智能提示的词失控。

配置Suggest模块

在solrconfig.xml文件中配置Suggest模块,其中Suggest依赖于SpellChecker模块,所以这两个都需要配置。具体配置如下:

 <searchComponent class="solr.SpellCheckComponent" name="suggest">
        <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">suggestion</str>
            <!-- the indexed field to derive suggestions from -->
            <float name="threshold">0.0001</float>
            <str name="spellcheckIndexDir">spellchecker</str>
            <str name="comparatorClass">freq</str>
            <str name="buildOnOptimize">true</str>

            <!--<str name="buildOnCommit">true</str>-->
        </lst>
    </searchComponent>
    <requestHandler class="org.apache.solr.handler.component.SearchHandler"
                    name="/suggest">
        <lst name="defaults">
            <str name="spellcheck">true</str>
            <str name="spellcheck.dictionary">suggest</str>
            <str name="spellcheck.onlyMorePopular">true</str>
            <str name="spellcheck.extendedResults">false</str>
            <str name="spellcheck.count">10</str>
            <str name="spellcheck.collate">true</str>
        </lst>
        <arr name="components">
            <str>suggest</str>
        </arr>
    </requestHandler>
    <queryConverter name="phraseQueryConverter"
                    class="com.hqb360.solr.suggest.PhraseQueryConverter"/>

上述配置的具体说明可参照solr的官方文档,下面对其中几个容易疑惑的地方做一下说明

  • queryAnalyzerFieldType 配置参数
    queryAnalyzerFieldType参数指定访问suggest的SearchHandler处理查询参数的Analyzer,如果指定的Analyzer很复杂的话,会导致suggest返回的结果不符合预期。在这们项目中,我们现希望Analyzer不对查询做任何的改变,因此选择string。
  • spellcheck.dictionary的值必须与searchComponent中spellchecker标签下<str name=”name”>suggest</str>配置对应。
  • Suggest返回结果的排序
    spellchecker组件中的comparatorClass参数可配置Suggest返回结果的排序,目前有如下几种可选方案:

    • Empty – in which case the default is used.
    • score – explicitly choose the default case
    • freq – Sort by frequency first, then score.
    • A fully qualified class name – Provide a custom comparator that implements Comparator<SuggestWord>.
      可查看SuggestWordScoreComparator类了解更多细节
  • QueryConverter定制
    上面的配置中,我们定制了自己的QueryConverter,主要原因是Solr默认的SpellQueryConvert是根据空格对查询参数做分隔,导致 “nokia e”这样的字符被当作“nokia”,“e”这样的两个字符处理,不符合我们的要求。定制的PhraseQueryConverter代码,需要打成jar包,放到Solr能访问到的目录下,在我们系统中是${solr.solr.home}/lib目录。

Suggest测试

配置完成之后,重启Solr后,访问如下链接

http://192.168.100.10:8080/solr/suggest?q=motorola%20x

结果如下:

<response>
  <lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">0</int>
  </lst>
  <lst name="spellcheck">
    <lst name="suggestions">
      <lst name="motorola x">
        <int name="numFound">10</int>
        <int name="startOffset">0</int>
        <int name="endOffset">10</int>
        <arr name="suggestion">
          <str>motorola xoom 3g版</str>
          <str>motorola xt875</str>
          <str>motorola xt300</str>
          <str>motorola xt883</str>
          <str>motorola xt702</str>
          <str>motorola xt806</str>
          <str>motorola xt800</str>
          <str>motorola xt502</str>
          <str>motorola xt882</str>
          <str>motorola xt316</str>
        </arr>
      </lst>
      <str name="collation">motorola xoom 3g版</str>
  </lst>
</lst>
</response>

需要注意的点

  • 重启Solr后,第一次访问时需要在Suggest请求中添加spellcheck.build=true参数,用于创建spellchecker的索引。
  • 通过threshold参数来限制一些不常用的词不出现在智能提示列表中,当这个值设置过大时,可能导致结果太少,需要引起注意。

存在的问题

目前主要存在的问题是使用freq排序算法,返回的结果完全基于索引中字符的出现次数,没有兼顾用户搜索词语的频率,因此无法将一些热门词排在更靠前的位置。这块可定制SuggestWordScoreComparator来实现,目前还没有着手做这件事情。

参考文档

SpellCheckComponent
Suggester

遇到一个Jetty tmp的陷阱

今天碰到一个古怪的问题,运行在Jetty服务器下的一个系统,忽然爆出一个“404,页面找不到”的错误,重启系统后问题就解决。之前也碰到一个类似的问题,当时也是重启后搞定,上次事件后,查找了一下原因,没有结果,这事情也就放下了。这次再次出现同样的问题,感觉问题比较严重,必须解决这个隐患了。

出现这个问题后,到服务器上看了一下,发现这个Jetty的进程还在,同样运行的其它几个服务也都正常。分析Jetty和应用日志后,也没有发现异常情况。再次回头看一下,抛出的错误信息:

HTTP ERROR 404

Problem accessing /pages/index.jsp. Reason:

Not Found

这个错误显示是index.jsp这个文件访问不到了。于是到Jetty部署解决war的默认目录/tmp去查看,这时其实已经于事无补了,因为刚才重启过,之前目录中的文件全部会被覆盖。

初步怀疑是war解压出的文件被删除了,问了一下SA有没有cron任务在晚上运行,会不会影响/tmp目录的文件,结果他表示没有。于是继续查看Nginx日志,发现在3点36分钟时,前一个请求返回的是200,后一个就变成404了。这时另外一个同事提醒说,系统默认的tmpwatch任务会清除/tmp目录下的文件。如下:

cat /etc/cron.daily/tmpwatch
#! /bin/sh
flags=-umc
/usr/sbin/tmpwatch “$flags” -x /tmp/.X11-unix -x /tmp/.XIM-unix \
-x /tmp/.font-unix -x /tmp/.ICE-unix -x /tmp/.Test-unix \
-X ‘/tmp/hsperfdata_*’ 10d /tmp
/usr/sbin/tmpwatch “$flags” 30d /var/tmp
for d in /var/{cache/man,catman}/{cat?,X11R6/cat?,local/cat?}; do
if [ -d "$d" ]; then
/usr/sbin/tmpwatch “$flags” -f 30d “$d”
fi
done

上面的脚本表示,tmpwatch分根据文件的修改(-m)/创建(-c)时间,清理/tmp下的10天前创建或修改的文件,问题就在这里了。如何解决呢?只要让Jetty解压war文件时,不放在/tmp下就能解决这个问题了。仔细查看Jetty的关于Temporary Directories 的描述文档,原来只需要在${jetty.home}目录下创建一个work目录就行了。Jetty的这个Trick害死人,为什么不在Jetty发布包中就默认包含这个目录呢?

教训:使用开源的东西,一定要认真读一下它的文档,对于比较关键的问题,一定要非常熟悉,否则出了问题才来想办法解决,已经晚了。

参考文档:
tmpwatch使用说明: tmpwatch man
jetty临时目录的说明: Temporary Directories

2011读书小结

在2010年末入手了Kindle,当时暗暗下了个决心:2011年读完40本书。2011已经过去了,很可惜遗憾我未能完成这个目标。上半年读书时间很多,进入下半年后,工作,生活上都非常忙,又沉迷于微博,看书时间锐减,于至于读书少了许多。最终盘点下面,2011年度一共读过了28本书,比2010年的18本有所进步,分类总结一下。

对过去的事情总是有着强烈的好奇心,这是我喜欢读史的一个原因。“读史可以明智,知古可以鉴今”,这两年读史的过程中,深深地感受到这两句话的意义。历史是对过去事情的浓缩,而个人传记则是对个人生平的浓缩,优秀的个人传记是人生智慧的浓缩,从他人传记中学习做事的道理,同时也是学习他们所生活年代的社会的窗口。今年读过不少传记及史书,分列以下:

历史传记类:

水流云在

  • 水流云在
  • 英若诚 / 张放 / 中信出版社 / 2009-9-1 / 32.00元
  • 英家是真正的贵族。 这是一部英若诚自传,内容非常精彩。书中读了英若诚家族从清末发迹一直到英达的家族史。英家的家族史也是中国近代史的缩影,他们家族与教育有缘,现在好些知名大学的前身是英千里,英敛之当年捐助成立的。

巨流河

  • 巨流河
  • 齊邦媛 / 天下遠見出版股份有限公司 / 2009-7-7 / TWD 500
  • 齐邦媛自传,讲他父亲及她在台湾的经历。是抗日战争时期人民的生活及国民党败退台湾及台湾慢慢发展起来的一个小窗口。书中所述未必全面,然而从众多小人物的传记中,可以窥视历史的一斑。
  • 大江大海1949
  • 龙应台
  • 这本是禁书,里面敏感内容较多,在豆瓣上都找不到了。里面讲述许多内战时期的事情,任何战争老百姓都是最受苦的,更悲剧的是,当年的人民都被某邪教给蛊惑,以至于至今仍在身受其害
今生今世
  • 今生今世
  • 胡蘭成 / 三三書坊 / 1990 / 320台幣
  • 这是胡兰成的自传,文笔着实了得,从文中可以看出这人本质并不太坏,对某党是深恶痛疾。从这本书中描述晚清及民国末年农村的贫困生活。蒋介石上台后,只关注城市及工业建设而忽视了千百年来农村的穷困农民,这才国民党失去中国的核心原因。
活着就为改变世界
  • 活着就为改变世界
  • [美] 杰弗里·扬 / 蒋永军 / 中信出版社 / 2010-6 / 39.00元
  • 在老乔去世前读完的,不得不感叹乔布斯的伟大,也为硅谷无处不在的技术高手而折服。
乔布斯传
  • 乔布斯传
  • 王咏刚 / 上海财经大学出版社 / 2011-8 / 39.80元
  • 乔布斯去世后几天读的,书中的文字透露出来的语气让人觉得很诡异,处处要表达出作者的一种奇怪的优越感。一些作者杜撰的对话,实在是让人生厌。
八十年代访谈录
  • 八十年代访谈录
  • 查建英 主编 / 生活·读书·新知三联书店 / 2006-5 / 38.00元
  • 非常喜欢书中阿城,崔健,陈丹青的访谈。阿城的经历给我的感触是,能不被时代的喧嚣左右,独自做些自己喜欢的事情也是一件幸福的事情。
上学记
  • 上学记
  • 何兆武 口述 / 生活·读书·新知三联书店 / 2006-8 / 19.80元
  • 西南联大的那一代人真了不起。那个时代中国的学者,学生们在学术上接近世界顶尖水准。可惜后来被莽夫掌权,闭关锁国,以意识形态的方式中国最优秀的一批知识份子悉数炕害。
万历十五年
  • 万历十五年
  • [美] 黄仁宇 / 生活·读书·新知三联书店 / 1997-5 / 12.80元
  • 重新审视这个帝国,深刻体会到体制决定了一个国家的命运…

技术类书籍

Nginx HTTP Server
  • Nginx HTTP Server
  • Clément Nedelcu / Packt Publishing / 2010-7-20 / USD 44.99
  • 范读了一遍,可以作为配置手册。对于一些Nginx的核心动作原理讲述太少,只是爬Wiki写的书。还是期待agentzh写的Nginx书能尽快完成出版吧。
High Performance Web Sites
Rework
  • Rework
  • Jason Fried / Crown Business / 2010-3-9 / USD 22.00
  • 书中描述的环境在国内太难找到,简直是软件开发的理想国。在新的公司里尽量尝试着激励大家,让大家都能高效工作。
Hackers & Painters
  • Hackers & Painters
  • Paul Graham / O’Reilly Media / 2010-5-1 / GBP 13.99
  • 其中讲的许多理念非常赞同,作者确实洞察程序员的心理。Lisp教徒热爱的人物,曾经因看了其博客上的文章,了解过Lisp基本语法。当然读SICP一书时慢慢体会到Lisp其中的魔力。
Groovy in Action
  • Groovy in Action
  • Dierk Koenig / Manning Publications / 2007-1-24 / USD 49.99
  • 讲解Groovy最全面的书,其实这本书没有完全读完,不过最近在公司里号召同事们关注Groovy,这本书还得重读一遍。
Solr 1.4 Enterprise Search Server
  • Solr 1.4 Enterprise Search Server
  • David Smiley / Packt Publishing / 2009-08-19 / USD 44.99
  • 号称学习Solr的Cookbook,之前很认同,不过现在不这么认为了。具体原因可看最近写的这篇:
高性能MySQL
  • 高性能MySQL
  • 开明出版社 / 2009-4 / 86.00元
  • 非常好的一本书,讲到了MySQL的方方面面。不过由于MySQL发展太快,09年的一些论断到现在已经不适用了,不过那些基础的东西永远都不会变。

 商业相关书籍

来到深圳后,慢慢体会到行业知识对个人的发展非常重要,因此读了些关于电子商务的书。

One Billion Customers
  • One Billion Customers
  • James McGregor / Simon & Schuster / October 11, 2005 / $15.00
  • 又一本禁书,读得译言翻译的版本,对于了解这个社会的运作非常有帮助。其实看完这本书,对于我朝更加绝望。
长尾理论2.0
  • 长尾理论2.0
  • 安德森 / 中信 / 2009-5 / 42.00元
  • 07年就知道这本书,直到2011年才读完。收获很大,提供了另一个角度看商业的方法,对于电商意义重大。
轻公司
  • 轻公司
  • 李黎 / 中信出版社 / 2009-7 / 39.00元
  • 里面讲到的许多关于零售的变革及社会不断演进导致新的商业模式给我留下很深的印象,也明白了零售的一些基本知识。不过在看这本书时,大熊开玩笑的说,当时李黎写这本书时,京东,淘宝,凡客都还是“轻公司”,现在都变成“重公司”,开始搞物流了。
门后的秘密
  • 门后的秘密
  • [美] Johanna Rothmann, / 于梦瑄 / 人民邮电出版社 / 2011-1 / 29.00元
  • 管理入门书籍。在淘宝时一心想做程序员,不愿管人,来到这边后慢慢地发现自己必须承担起带领团队的任务,于是开始看这本书。书中讲的东西都非常不错,解开了许多的疑惑,不过管理这事还是得用心去做,用心体会,不断提升。
决策与判断
  • 决策与判断
  • 斯科特·普劳斯 / 人民邮电出版社 / 2004-9 / 28.00元
  • 了解在做决策时的一些常见误区,努力去规避。这本书看得不认真,书中内容非常不错,还得再重读一遍。
拆掉思维里的墙
  • 拆掉思维里的墙
  • 古典 / 中国书店 / 2010-9 / 29.80元
  • 励志书,其中没太大意思,刚好在找Kindle模式的书是发现有,就放进Kindle看了看。消磨时间还不错。
我是一只IT小小鸟
  • 我是一只IT小小鸟
  • 胡江堂 / 电子工业出版社 / 2009 / 29.80
  • 对其中的一些人物比较熟悉了,一直追看他们的博客。书中更喜欢徐宥的一些观点。当然这些人的成功是没有办法复制的,走出自己的一条路才是正道。

还有几本其它的杂书,没什么写的价值,不列在这里了。

2012年希望能再接再励,希望能够达到40本书的目标。不管今年会不会是世界末日,自己的计划不能被打乱。

2011年终盘点

转眼间2011就成为了过去,已经进入“世界末日”的年份。埋头忙碌了一年,是时候静下心来做个总结了。2011年对我来说是一个重大的转折点,去年4月份带着些许遗憾离开了淘宝,来到了深圳华强北在线,开始新的冒险。

从2009年进入淘宝后,在淘宝学到了许多的东西,也开阔了视野,近距离观察淘宝这样一个大型Java分布式系统是如何搭建的,思考过其中的各个组件的作用。但是遗憾的时,因为机遇的关系,对于这些都只能看看,而没有办法参与,于是在一位朋友的邀请下,来到深圳,加入正在创业中的华强北在线。

加入华强北在线后,才感觉到之前在淘宝很多看似平常的事情,都不简单。于是开始慢慢地组建团队,慢慢把在淘宝学到的有用的做事方法等在这边推动起来,慢慢地规划网站架构。因为新的公司技术还属于刚刚起步阶段,许多的东西都需要亲历亲为,包括很多技术选型的工作。在这段时间里,亲手搭建Nexus做Maven镜像,亲手测试MySQL Percona性能做测试,决定系统部署方案,许多Util类型的代码,亲自决定系统架构采用RESTful风格的接口,甚至还做一些SA的活,还有许多这样的决策。在做这些决策时,常常深感庆幸又小心翼翼,因为深知自己的能力,眼界有限,目前所能做的只是尽量把基础搭建好,让系统没有严重的设计失误,以便未来有大牛加入后,可以让他们快速在现有的基础下,发挥专长。

在处理这许多的细节问题时,才慢慢发现“细节是魔鬼”这句话的真实含义。在淘宝时有许多很多的基础设施平台,在这个平台上做开发工作,很多时候对于一些细节的东西理解并不深刻。来到这边后,需要对这些都非常清楚才能放心,于是发现这半年自己的成长非常大。

在这半年中团队规模一直没有壮大起来,现在看来这是个很大的失误。在深圳招聘时,发现这边的从事外包的Java开发太多,许多人的基础不好,导致招聘一直不顺。8月份把龙浩拉入伙,是今年做得最好的一件事了,其它的几个人也都还不错,在经过几个月的磨合后,整个团队的学习氛围和工作效率都很不错了。新年后还要继续招聘,希望能找到些对技术真正感兴趣的同学一起来把平台做大。

来到深圳后,还有一个最大的改变就是终于告别单身了。

2011年有许多的遗憾,不过都已经过去了。2012年肯定会是非常忙碌的一年,希望这一年能够是收获的一年。

最后欢迎有志于Java技术的朋友与我联系,加盟华强北在线。我们的Java团队非常专业,也非常有潜力。