`
lookdd1
  • 浏览: 47298 次
  • 性别: Icon_minigender_1
  • 来自: 日照
文章分类
社区版块
存档分类
最新评论

借助Play!framwork,lucene,taobao kissy 实现完整的前后端suggest功能

阅读更多
先上效果图:


   我是基于Play!framework开发的网站 想了解童鞋可以看看http://www.iteye.com/topic/806974这篇帖子,目前最新版本是1.1,还有童鞋没听说过play!framework吗?简单的科普一下(以下内容来自于互联网):
引用
Play Framework是一个功能完整的Java Web开发框架。采用RESTful架构设计,简便灵活。Play Framework使用MVC模式作为Web层,集成JPA构建持久层,Play Framework还使用一个基于Groovy的模板引擎。
其特征如下:
   1.  Play Framework让开发者无须重新编译打包发布应用,即可看到修改后的效果,方便开发人员调试应用。
   2. Play!Framework采用了无状态模型,是一个真正意义上的“无共享”系统,能够在多个服务器上部署多个Play!Framework的实例,所有实例都不会互相干扰。
   3. Play!Framework采用了Groovy作为模板引擎,让表示层真正做到了开发高效简洁
   4. Play!Framework拥有精确的错误定位机制,当错误发生的时候,可以精确的定位到错误代码的位置。
   5. Play!Framework的速度很快,启动快,运行的速度也十分快。

   官方网站是: [url]http://www.playframework.org/  [/url]  再广一个告:中文社区http://www.daocaozhu.com/ (刚开始弄,还希望喜欢play的童鞋一块在这里交流play!framework的使用心得,为play!framework在中国的发展贡献你的力量)
回到正题上来:要实现这样的效果,我们都知道需要两个必不可少的工具:
   1、前端suggest组件;2、中文分词以及全文检索
   Suggest组件我选择了淘宝UED团队开发的开源js库:Kissy 官方网站是:[url]https://www.github.com/kissyteam/kissy   [/url]为什么选择kissy呐,我主要是被它的suggest组件还有图片轮换的组件所吸引,而且是淘宝UED团队开发的,质量上应该有保证,当然用起来确实也不错,虽然在选型上有些激进^_^。
  全文检索毫无疑问是lucene,中文分词我用的是庖丁解牛(感谢作者的贡献)。
Play提供了很多module,而集成lucene我们就需要用到search-module:http://www.playframework.org/modules/search   使用方法很简单,下载search-module到你Play目录下的modules文件夹里(不过好像play的安装包里已经带了,忘记了^_^),然后在你项目的配置文件application.conf中 

  去掉标注为红色的那一行前面的#号,如果你将你的项目部署到服务器上,而你的服务器上没有play安装包,那你可以把search包直接放到你的项目WEB-INF(把项目打成war后)路径下,这儿改为:module.search=../search,这样就不会有找不到search module的错误了。
  Search module已经配置好了,那我们就完整的实现这个小东西:前端的东西基本上引入kissy的主文件和kissy suggest 就行(当然还少不了必要的css^_^)。我们这儿为:
 
<script type="text/javascript" src="@{'public/javascripts/kissy/kissy.js'}"></script>     
<script type="text/javascript" src="@{'/public/javascripts/kissy/suggest.js'}"></script>  

然后查询控件为:

 <form id="J_TSearchForm" action="@{Shops.search()}" name="search" target="_top"> 
          	<div class="tsearch-panel-fields ">
			<label for="q" class="">输入您想要的商品名称</label>
			<input name="q" id="q" autocomplete="off" accesskey="s">
			 <s class="rc-tp-l"></s>
			 <s class="rc-bt-l"></s>
		</div>
		<button type="submit">搜索</button> 
 </form>

代码很眼熟?好吧,我承认,我山寨的taobao的…..
加入Js 代码:

	   KISSY.ready(function(S) {
	      var sug = new S.Suggest('#q', "@{Shops.searchSuggest()}", {
	            autoFocus: true,
	            resultFormat: '约%result%个宝贝'
	        });
	   });

   开始说说后端实现的思路:  首先我们需要建立一个搜索词的词库。这个词库包含的内容有 1、检索词  2、检索次数(用于实现哪个词热度排序)3、检索词的拼音缩写版  用于输入个拼音也能给出提示。

首先说下模型类

这儿我们主要用到了两个实体:Product(商品对象)  SearchIndex(搜索建议词对象)

@Entity
@Indexed
public class SearchIndex extends Model{

	@Field
	public String name;//关键词
	
	@Field
	public long searchTimes;// 搜索次数
	
	@Field
	public String pinyin;//拼音版
	
	public SearchIndex(String name){
		this.name = name;		
		this.pinyin = Tool.cn2Spell(name);
		save();
	}

  上面是SearchIndex的大部分代码。大体说下:@Index表示这个类可以需要lucene建立索引,继承的Model类是play对CRUD的大部分封装,是以JPA为基础作的富血的Domain Model的基类。然后@Field注解表示需要索引的字段。  在构造方法中,有Tool.cn2Spell这一句,使用了Pinyin4j做的从汉字到拼音简写的转换。这段代码网上找的,我就不贴出来了。

   然后说下搜索词的词库的建立:这儿我们主要是把商品名给分词后保存到词库中建立的搜索提示词的词库。在Product的构造方法里我们加了这么一句:
  
this.addToIndexStore(name);

这个方法的实现为:

	public static void addToIndexStore(String productName){
		try {
			List<String> list =Tool.paodingAnalyzerWord(productName);
			for(String str:list){
				if(!SearchIndex.isExsist(str)){
					new SearchIndex(str);
					Logger.info("SearchIndex  添加索引:", str);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

  这儿我们用到了庖丁解牛的中文分词。Search module默认使用的分词是lucene自带的那个StandardAnalyzer,这个在处理中文上还无法满足我们的需要,所以我选用了社区中比较知名的庖丁解牛,事实上开始我选的是IK Analyzer的,但一直没有找到合适匹配Play自带的lucene的版本 ^_^ 。下载庖丁http://code.google.com/p/paoding/  因为我使用的play版本是1.0.3 其中自带的lucene版本是2.3.1  所以我们下载庖丁用那个paoding-analysis-2.0.4-beta.zip 即可 
还需要更改一下search module默认的分词:找到application.conf: 加入下面两句
  play.search.reindex=enabled
  play.search.analyser=net.paoding.analysis.analyzer.PaodingAnalyzer

第一句的作用官方文档是这样解释的:



  然后我们再来看看上面包含代码的那个图中的代码:分词的那一句是:
   Tool.paodingAnalyzerWord:看代码:
	public static List<String> paodingAnalyzerWord(String word) throws IOException{
	    PaodingAnalyzer analyzer = new PaodingAnalyzer();
	    StringBuilder sb = new StringBuilder();
	    TokenStream ts = analyzer.tokenStream("", new StringReader(word));
	    Token token;
             sb.setLength(0);
             ArrayList<String> results = new ArrayList<String>();
             while ((token = ts.next()) != null) {
                sb.append(new String(token.termBuffer()).trim()).append('/');
             results.add(new String(token.termBuffer()).trim());
        }
        if (sb.length() > 0) {
           sb.setLength(sb.length() - 1);
        }
        
        return results;
}


这段代码实现了中文分词,基本上没有啥需要解释的。
然后我们遍历分出来的词,查询下这个词是不是已经存在,存在的话就不用理它,不存在的话就加入到检索词词库中。这儿我都是和数据库直接交互,可能性能上会有问题,所以我们可以把搜索词全部加载到缓存中再做处理。

这样搜索建议词的词库就建立好了。

然后我们看看Shops.searchSuggest(上图中搜索form提交的地方)方法的实现:

    /**
     * 商品搜索提示
     */
	public static void searchSuggest(String q) throws IOException{
		
	Search.Query query = Search.search("name:"+q.trim()+"* OR pinyin:"+q.trim()+"*", SearchIndex.class);
		
	List<SearchIndex> list =query.orderBy("searchTimes").reverse().page(0, 8).fetch();
		
	List<String[]> results = new ArrayList<String[]>();
		
		
	for(SearchIndex si:list){			
	     Search.Query q2=Search.search("name:"+si.name+"*",Product.class);
	     String[] str ={si.name,String.valueOf(q2.count())};			
	     results.add(str);
	}
		
	String result =new Gson().toJson(results);		
	renderJSON("KISSY.Suggest.callback({'result':"+result.replace("\"", "\'")+"})");
	}

  解释下上面的代码:

  第一句中的Search.Query是search module中的类,主要是对lucene操作的一些封装。Search.search()中的第一个参数是lucene查询表达式。这儿表示以name或者pinyin这两个字段进行匹配查询。这个查询用于查找用户输入字的相关搜索词(suggest)。

   下面的for循环用于查询匹配这个搜索词的商品的数量。
最后返回json:注意,这儿返回的JSON串都必须是单引号包括。比如{‘name’:’zhangsan’}这种。

   这样基本上就完成了一个简单的search suggest  功能。写的比较繁杂,主要是为了力求把事情说清楚,同时掺杂了一些play的使用说明。本文主要目的是向大家展示Play!framework的灰常好用,由于个人水平有限,极有可能存在不合适的地方,所以本文参考为主,不对的还请大家多多指教
  • 大小: 41.2 KB
  • 大小: 16.9 KB
  • 大小: 23.5 KB
  • 大小: 36.4 KB
  • 大小: 30.3 KB
  • 大小: 17.3 KB
  • 大小: 49.5 KB
  • 大小: 8.1 KB
  • 大小: 53.1 KB
  • 大小: 63.4 KB
  • 大小: 122.1 KB
  • 大小: 93.4 KB
分享到:
评论
30 楼 amtea 2014-12-16  
排序没什么效果嘛!
List<SearchIndex> list =query.orderBy("searchTimes").reverse().page(0,.fetch();
29 楼 ZHH2009 2011-01-23  
<div class="quote_title">liusong1111 写道</div>
<div class="quote_div">
<div class="quote_title">lookdd1 写道</div>
<div class="quote_div">
<div class="quote_title">liusong1111 写道</div>
<div class="quote_div">据我观察,playframework和国内的斗鱼是最接近ruby on rails的java web框架,可以说代表了未来的方向。playframework已经有生产环境的成功案例了,1.1版本还集成了scala插件,方便使用scala语言进行开发,而scala的lift框架由于特意设计成有状态的,目前还不被主流web开发者所接受,scala的另一个web框架scalatra又太新,所以很多scala的爱好者们都把playframework当成首选。<br><br>我对playframework了解不深,曾找过它如何执行脱离web环境的Task,找到了Job,可以通过annotation设定定时执行的策略,但不知道如何在console下手工执行,不知道各位有没有思路?<br><br><br><br>
</div>
<br>斗鱼有一点就可以让它难以发展,不支持标准的servlet容器,我觉得在技术选型的时候这么一条就足够可以将其排除。至于脱离web环境的JOB我不知道有什么需求需要这么做,脱离web环境不可以自己单独写个独立的程序片段控制吗?使用jdk的JOB或者是使用quartz或者使用操作系统的定时作业?</div>
<br><br>那只能说斗鱼属于颠覆型作品,未见得不是好事。技术选型当然要排除这么不成熟的东西了,除非有比它的作者更强的信心和能力。<br><br>我需要的是ruby on rails中rake的对应物。一个web MVC框架,其中M层和多数环境配置跟web环境是无关的,如果仅依赖它们做一些程序片段,并能使其在console下手工执行,或配置到quartz、crond下是有意义的。其实playframework的Job很接近答案了,只是我没找到手工执行它的方法。其实playframework对于model层也只是在JPA之上做了一层封装,实在不行,我们还可以考虑加一个sh/bat,加载全局配置初始化环境,调用指定的job class,输出结果 -- 做rake所做的事 -- 当然,rake还有跟ant类似的任务依赖等等内容。</div>
<p><br><span style="font-size: large;"><br>Douyu会支持servlet容器的,2010年一直都在跟进Tomcat7.0的最新源代码,<br>目前在公司专职做servlet/jsp容器的改进工作(主要其于Tomcat)。<br><br>Douyu预计会在2011年6月初发布,敬请期待。</span></p>
<p><span style="font-size: large;">2011年我会慢慢推进Douyu在公司内部一些产品或项目</span><span style="font-size: large;">上</span><span style="font-size: large;">用起来。</span></p>
<p><span style="font-size: large;"><br>PS: 推荐一个公司刚刚开源不久的MVC框架: </span><a title="Webx3" href="http://code.taobao.org/project/view/401/"><span style="font-size: large;">Webx3</span></a><span style="font-size: large;">。<br></span></p>
<p> </p>
28 楼 lookdd1 2011-01-23  
系统程序 写道
楼主,你的稻草猪打不开了哦


哈哈。。。不好意思。。。。论坛没有备案。。。网管威胁不撤下来服务器就挂了。。。。
27 楼 系统程序 2011-01-22  
楼主,你的稻草猪打不开了哦
26 楼 okjacky 2010-11-19  
这个框架用的还不是很多吧?
25 楼 lookdd1 2010-11-11  
Eastsun 写道
为了避免被隐藏,我来让你精华


大神。。。我这帖子对不起这精华啊。。  
24 楼 Eastsun 2010-11-11  
为了避免被隐藏,我来让你精华
23 楼 grandboy 2010-11-11  
来个精华,虽然现在我用不上,但是觉得认真的帖子。
22 楼 尔今尔后 2010-11-11  
代码不分享一下吗
21 楼 xbgd 2010-11-11  
我这个星期开始学习的,刚刚搭建好框架
20 楼 Hedgehog 2010-11-10  
非常不错,值得关注。。
19 楼 ybzshizds 2010-11-10  
lucene有个spellchecker组件,但是要真正用于生产环境还需要许多改进,如输入:"程许员工作类" 可以提示,您要找的是不是,"程序员工作累"
18 楼 lookdd1 2010-11-10  
ybzshizds 写道
这个根据汉字和拼音进行自动补全的功能,对搜索时的用户体验确实很不错,不知楼主研究过基于lucene的spellchecker没有,加上这个,搜索就真得很像google了.


我这里lucene用的都是最基础的(事实上偶是第一次用lucene  ),还没用用过您所说的spellchecker,您如果熟悉的话可以写写您的经验啊
17 楼 ybzshizds 2010-11-10  
这个根据汉字和拼音进行自动补全的功能,对搜索时的用户体验确实很不错,不知楼主研究过基于lucene的spellchecker没有,加上这个,搜索就真得很像google了.
16 楼 lookdd1 2010-11-09  
godtiger 写道
没听过play。。。

了解Play!framework ,可以见我另一篇帖子;http://www.iteye.com/topic/806974
15 楼 godtiger 2010-11-09  
没听过play。。。
14 楼 liusong1111 2010-11-09  
lookdd1 写道
liusong1111 写道
据我观察,playframework和国内的斗鱼是最接近ruby on rails的java web框架,可以说代表了未来的方向。playframework已经有生产环境的成功案例了,1.1版本还集成了scala插件,方便使用scala语言进行开发,而scala的lift框架由于特意设计成有状态的,目前还不被主流web开发者所接受,scala的另一个web框架scalatra又太新,所以很多scala的爱好者们都把playframework当成首选。

我对playframework了解不深,曾找过它如何执行脱离web环境的Task,找到了Job,可以通过annotation设定定时执行的策略,但不知道如何在console下手工执行,不知道各位有没有思路?




斗鱼有一点就可以让它难以发展,不支持标准的servlet容器,我觉得在技术选型的时候这么一条就足够可以将其排除。至于脱离web环境的JOB我不知道有什么需求需要这么做,脱离web环境不可以自己单独写个独立的程序片段控制吗?使用jdk的JOB或者是使用quartz或者使用操作系统的定时作业?


那只能说斗鱼属于颠覆型作品,未见得不是好事。技术选型当然要排除这么不成熟的东西了,除非有比它的作者更强的信心和能力。

我需要的是ruby on rails中rake的对应物。一个web MVC框架,其中M层和多数环境配置跟web环境是无关的,如果仅依赖它们做一些程序片段,并能使其在console下手工执行,或配置到quartz、crond下是有意义的。其实playframework的Job很接近答案了,只是我没找到手工执行它的方法。其实playframework对于model层也只是在JPA之上做了一层封装,实在不行,我们还可以考虑加一个sh/bat,加载全局配置初始化环境,调用指定的job class,输出结果 -- 做rake所做的事 -- 当然,rake还有跟ant类似的任务依赖等等内容。
13 楼 lookdd1 2010-11-09  
liusong1111 写道
据我观察,playframework和国内的斗鱼是最接近ruby on rails的java web框架,可以说代表了未来的方向。playframework已经有生产环境的成功案例了,1.1版本还集成了scala插件,方便使用scala语言进行开发,而scala的lift框架由于特意设计成有状态的,目前还不被主流web开发者所接受,scala的另一个web框架scalatra又太新,所以很多scala的爱好者们都把playframework当成首选。

我对playframework了解不深,曾找过它如何执行脱离web环境的Task,找到了Job,可以通过annotation设定定时执行的策略,但不知道如何在console下手工执行,不知道各位有没有思路?




斗鱼有一点就可以让它难以发展,不支持标准的servlet容器,我觉得在技术选型的时候这么一条就足够可以将其排除。至于脱离web环境的JOB我不知道有什么需求需要这么做,脱离web环境不可以自己单独写个独立的程序片段控制吗?使用jdk的JOB或者是使用quartz或者使用操作系统的定时作业?
12 楼 liusong1111 2010-11-09  
据我观察,playframework和国内的斗鱼是最接近ruby on rails的java web框架,可以说代表了未来的方向。playframework已经有生产环境的成功案例了,1.1版本还集成了scala插件,方便使用scala语言进行开发,而scala的lift框架由于特意设计成有状态的,目前还不被主流web开发者所接受,scala的另一个web框架scalatra又太新,所以很多scala的爱好者们都把playframework当成首选。

我对playframework了解不深,曾找过它如何执行脱离web环境的Task,找到了Job,可以通过annotation设定定时执行的策略,但不知道如何在console下手工执行,不知道各位有没有思路?



11 楼 lookdd1 2010-11-09  
xiangkun 写道
木有听说过.难道play就是用来做这样的效果的?

不是的。。。play这儿是个服务端的东西。我只是顺路普及了下play!framework。。用其它的服务端框架是一样的

相关推荐

Global site tag (gtag.js) - Google Analytics