bobo-browse
bobo-browse 是一款用java写的lucene扩展组件,通过它直接使用lucene建立的索引文件,就可以很方便的在lucene上实现分组统计功能。虽然lucene的使用已经很广泛,稳定性和效率方面都得到了大家的认可,但是在对搜索结果进行分组统计时就有些无能为力了。这样致使不少有需求的项目中,不得不修改lucene的源代码来实现分组统计的功能,要修改lucene源码首先必须对lucene的TopDocCollector类和排序原理有很深的理解,而且还要考虑多线程和性能的问题,如果你的项目中用到了compass,那还得修改compass的源代码,另外给后续的升级还会带来很多麻烦。 bobo-browse为了填补lucene在分组统计功能上的空缺,由此而诞生。早期的bobo-browse开源项目放在sourceforge上,后来被搬到google code上。目前项目地址为http://code.google.com/p/bobo-browse/
下载安装
Get the source:
svn co https://bobo-browse.googlecode.com/svn/trunk bobo-trunk
Assuming checked out to ~/bobo-trunk: Build: Builds jars:
* cd ~/bobo-trunk * ant
Run cardemo app:
* In ~/bobo-trunk, do ant run-cardemo * cardemo should be deployed at: http://localhost:8888/cars/
cars.war is generated under cardemo/ Build Javadocs
* In ~/bobo-trunk, do ant javadoc * javadocs are generated under doc/
cardemo运行起来的效果(该例子中还用到了springMVC, springIOC,ajax技术DWR,总的索引数据是1.5W条)
测试代码:
package com.jobcn.test; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.Map; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.index.IndexReader; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Query; import org.apache.lucene.search.SortField; import org.apache.lucene.store.FSDirectory; import com.browseengine.bobo.api.BoboBrowser; import com.browseengine.bobo.api.BoboIndexReader; import com.browseengine.bobo.api.Browsable; import com.browseengine.bobo.api.BrowseFacet; import com.browseengine.bobo.api.BrowseHit; import com.browseengine.bobo.api.BrowseRequest; import com.browseengine.bobo.api.BrowseResult; import com.browseengine.bobo.api.FacetAccessible; import com.browseengine.bobo.api.FacetSpec; import com.browseengine.bobo.api.FacetSpec.FacetSortSpec; import com.browseengine.bobo.facets.FacetHandler; import com.browseengine.bobo.facets.impl.SimpleFacetHandler; public class TestSearchPosByLucene { private static FSDirectory fsd; static { String indexDir = "/use/lucene/target/index/compos_0"; try { if(fsd == null){ fsd = FSDirectory.getDirectory(indexDir); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void test(String keyWord) throws Exception{ // reqworkyear facet handler SimpleFacetHandler reqworkyearHandler = new SimpleFacetHandler("reqworkyear"); // reqdegreeid facet handler SimpleFacetHandler reqdegreeidHandler = new SimpleFacetHandler("reqdegreeid"); List<FacetHandler> handlerList = Arrays.asList(new FacetHandler[]{reqworkyearHandler, reqdegreeidHandler}); IndexReader reader = IndexReader.open(fsd,true); // decorate it with a bobo index reader BoboIndexReader boboReader = BoboIndexReader.getInstance(reader,handlerList); // creating a browse request BrowseRequest br=new BrowseRequest(); br.setCount(5); br.setOffset(0); br.setFetchStoredFields(true); // parse a query QueryParser parser = new QueryParser("alltext",new StandardAnalyzer()); Query q=parser.parse(keyWord); br.setQuery(q); SortField[] sortFields = new SortField[2]; //按学历+发布日期排序 sortFields[0] = new SortField("reqdegreeid", SortField.INT, true); sortFields[1] = new SortField("postdate", SortField.STRING, true); br.setSort(sortFields); // add the facet output specs FacetSpec reqworkyearSpec = new FacetSpec(); reqworkyearSpec.setOrderBy(FacetSortSpec.OrderHitsDesc); FacetSpec reqdegreeidSpec = new FacetSpec(); reqdegreeidSpec.setMinHitCount(2); reqdegreeidSpec.setOrderBy(FacetSortSpec.OrderHitsDesc); br.setFacetSpec("reqworkyear",reqworkyearSpec); br.setFacetSpec("reqdegreeid",reqdegreeidSpec); long startTime = System.currentTimeMillis(); // perform browse Browsable browser=new BoboBrowser(boboReader); BrowseResult result=browser.browse(br); int totalHits = result.getNumHits(); System.out.println("公司发布的职位信息中含有‘"+keyWord+"’关键字的职位总数:" + totalHits); System.out.println("打印前"+ br.getCount() +"个职位Id:"); BrowseHit[] hits = result.getHits(); for(BrowseHit hit : hits){ System.out.println(hit.getStoredFields().get("$/compos/Id")); } Map<String,FacetAccessible> facetMap = result.getFacetMap(); FacetAccessible colorFacets = facetMap.get("reqdegreeid"); List<BrowseFacet> facetVals = colorFacets.getFacets(); System.out.println("学历统计:"); for(BrowseFacet facetVal : facetVals){ System.out.println(facetVal.getValue() +"--->"+ facetVal.getHitCount() ); } FacetAccessible colorFacets2 = facetMap.get("reqworkyear"); List<BrowseFacet> facetVals2 = colorFacets2.getFacets(); System.out.println("工作经验统计:"); for(BrowseFacet facetVal : facetVals2){ System.out.println(facetVal.getValue() +"--->"+ facetVal.getHitCount() ); } long endTime = System.currentTimeMillis(); System.out.println("总共用时:"+(endTime - startTime) + " ms"); } public static void main(String args[]) throws Exception{ TestSearchPosByLucene t = new TestSearchPosByLucene(); t.test("软件工程师"); t.test("销售"); t.test("文员"); t.test("程序员"); t.test("机械"); t.test("品质"); t.test("采购"); t.test("网络"); } }
测试结果(测试数据为464667条索引数据)
公司发布的职位信息中含有‘软件工程师’关键字的职位总数:4411
打印前5个职位Id:
146985307
1614164
147057728
146493293
146883100
学历统计:
50--->2850
40--->922
0--->541
60--->64
30--->20
20--->13
工作经验统计:
002--->1377
001--->967
003--->904
000--->894
005--->131
-100--->99
-001--->13
004--->12
008--->8
010--->3
006--->2
009--->1
总共用时:2203ms
职位信息中含有‘销售’关键字的职位总数:105705
打印前5个职位Id:
146746253
145398731
144558278
146676991
145903475
学历统计:
40--->53122
0--->20360
50--->19842
30--->7235
20--->4950
60--->189
70--->7
工作经验统计:
000--->32267
001--->24848
002--->23029
003--->15861
005--->6687
-100--->1575
008--->777
010--->324
-001--->145
004--->132
006--->46
007--->13
009--->1
总共用时:530ms
职位信息中含有‘文员’关键字的职位总数:8951
打印前5个职位Id:
147021795
1589251
1622088
1597617
1617689
学历统计:
40--->3207
0--->2172
30--->1837
20--->1230
50--->504
工作经验统计:
000--->3482
001--->2848
002--->1298
-100--->951
003--->306
005--->39
-001--->17
010--->4
004--->3
008--->2
006--->1
总共用时:187ms
职位信息中含有‘程序员’关键字的职位总数:2907
打印前5个职位Id:
147212315
136862380
145218476
146803412
146799915
学历统计:
50--->1111
40--->1093
0--->662
30--->25
60--->11
20--->5
工作经验统计:
001--->954
002--->860
000--->668
003--->330
005--->49
-100--->37
-001--->4
004--->3
008--->1
010--->1
总共用时:129ms
职位信息中含有‘机械’关键字的职位总数:21289
打印前5个职位Id:
1581752
1621668
1627486
147070171
147190901
学历统计:
40--->7886
50--->6918
0--->3535
30--->1992
20--->808
60--->145
70--->5
工作经验统计:
003--->5191
002--->4824
000--->3485
005--->3158
001--->2456
-100--->1182
008--->409
010--->283
004--->175
006--->75
007--->28
-001--->17
011--->5
009--->1
总共用时:155ms
职位信息中含有‘品质’关键字的职位总数:9401
打印前5个职位Id:
146711801
1618120
1621358
1621362
1621387
学历统计:
40--->3820
50--->2690
0--->1420
30--->755
20--->661
60--->54
工作经验统计:
003--->2307
002--->1970
000--->1479
005--->1384
001--->1309
-100--->464
008--->204
010--->135
004--->93
006--->38
007--->13
-001--->3
009--->2
总共用时:185ms
职位信息中含有‘采购’关键字的职位总数:10897
打印前5个职位Id:
146820815
146820816
1517476
1597948
1627281
学历统计:
40--->4872
50--->3172
0--->1612
30--->789
20--->416
60--->34
70--->2
工作经验统计:
003--->2637
002--->2365
000--->1872
001--->1767
005--->1520
-100--->318
008--->218
010--->116
004--->52
-001--->14
006--->13
007--->3
009--->2
总共用时:106ms
职位信息中含有‘网络’关键字的职位总数:36103
打印前5个职位Id:
1634505
1617099
146026202
145398731
146298700
学历统计:
40--->15922
50--->10997
0--->6604
30--->1665
20--->688
60--->218
70--->9
工作经验统计:
000--->9680
001--->9171
002--->8501
003--->5569
005--->2215
-100--->427
008--->202
-001--->142
010--->138
004--->40
006--->13
007--->4
009--->1
总共用时:121 ms<!-- end content -->