Lucene 分组统计方案——只能适合于小数据量,性能耗用太大
2009-10-01 09:10
627 查看
转:http://tech.ddvip.com/2009-01/1231742812105589.html
注意:本文内容仅适用于Lucene.Net,以2.1版为例,其它版本可能会有出入,Java版本差别更大一些。
改动库先要有个思路。Lucene.Net的查询结果是一个Hits,而它有一个方法length可以得到总的结果。这个结果是一个精确值。这个值实际上是在TopDocCollector类的Collect方法计算出来的。要改精算为估算也就是在这里添加算法就可以了。
修改一下其实也适合于 java版本的lucene,我就是用下面这个方法实现的:
public void Collect(int doc,float score)
{
if(score>0.0f)
{
totalHits++;
if(hq.Size()<numHits||score>=minScore)
{
hq.Insert(new ScoreDoc(doc,score));
minScore=((ScoreDoc)hq.Top()).score;//maintainminScore
}
}
}
这个方法中已经有了Document的id号,只要有办法拿到Document就能得到类别了。能拿到Document的类,IndexSearcher和IndexReader都可以。这里用IndexReader比较合算,因为IndexSearcher本身就包含IndexReader的。
Collect方法会在几个地方被用到。都是Scorer一系的类中。比如TermScorer,BooleanScorer2等。所以按分类统计如果给Collect增加参数的话改动量可能会比较大。所以修改TopDocCollector的构造函数。
private IndexReader reader;
public TopDocCollector(int numHits,IndexReader reader)
{
this(numHits,newHitQueue(numHits),reader)
}
public TopDocCollector(int numHits,PriorityQueue hq,IndexReader reader)
{
this.numHits=numHits;
this.hq=hq;
this.reader=reader;
}
同时有两个调用构造函数的地方需要被修改。
TopFieldDocCollector的构造函数:
public TopFieldDocCollector(IndexReader reader,Sort sort,int numHits)
{
super(numHits,newFieldSortedHitQueue(reader,sort.fields,numHits),reader)
}
IndexSearcher的构造函数:
现在TopDocCollector类就可以拿到分类了。
Collect方法改成:
TopDocs方法改成
同时修改:
至此就OK了。从结果中取的时候,比如ID为1的分类,则
hits.Category_Count[1]就出来了。
注意:本文内容仅适用于Lucene.Net,以2.1版为例,其它版本可能会有出入,Java版本差别更大一些。
改动库先要有个思路。Lucene.Net的查询结果是一个Hits,而它有一个方法length可以得到总的结果。这个结果是一个精确值。这个值实际上是在TopDocCollector类的Collect方法计算出来的。要改精算为估算也就是在这里添加算法就可以了。
修改一下其实也适合于 java版本的lucene,我就是用下面这个方法实现的:
public void Collect(int doc,float score)
{
if(score>0.0f)
{
totalHits++;
if(hq.Size()<numHits||score>=minScore)
{
hq.Insert(new ScoreDoc(doc,score));
minScore=((ScoreDoc)hq.Top()).score;//maintainminScore
}
}
}
这个方法中已经有了Document的id号,只要有办法拿到Document就能得到类别了。能拿到Document的类,IndexSearcher和IndexReader都可以。这里用IndexReader比较合算,因为IndexSearcher本身就包含IndexReader的。
Collect方法会在几个地方被用到。都是Scorer一系的类中。比如TermScorer,BooleanScorer2等。所以按分类统计如果给Collect增加参数的话改动量可能会比较大。所以修改TopDocCollector的构造函数。
private IndexReader reader;
public TopDocCollector(int numHits,IndexReader reader)
{
this(numHits,newHitQueue(numHits),reader)
}
public TopDocCollector(int numHits,PriorityQueue hq,IndexReader reader)
{
this.numHits=numHits;
this.hq=hq;
this.reader=reader;
}
同时有两个调用构造函数的地方需要被修改。
TopFieldDocCollector的构造函数:
public TopFieldDocCollector(IndexReader reader,Sort sort,int numHits)
{
super(numHits,newFieldSortedHitQueue(reader,sort.fields,numHits),reader)
}
IndexSearcher的构造函数:
public TopDocs Search(Weight weight,Filter filter,int nDocs) { if(nDocs<=0) //nullmightbereturnedfromhq.top()below. throw new System.ArgumentException("nDocsmustbe>0"); TopDocCollector collector=new TopDocCollector(nDocs,this.reader); Search(weight,filter,collector); return collector.TopDocs(); }
现在TopDocCollector类就可以拿到分类了。
public override void Collect(int doc,float score) { if(score>0.0f) { Documentd=reader.Document(doc); //这里是最耗费,取一次大概耗费15-16毫秒 int category=int.Parse(d.Get("category")); totalHits++; if(hq.Size()<numHits||score>=minScore) { hq.Insert(newScoreDoc(doc,score)); minScore=((ScoreDoc)hq.Top()).score;//maintainminScore } } }
最终这个统计的结构需要反映到Hits类去。返回结构和TopDocCollector的public TopDocs TopDocs()方法有关。给TopDocs 增加一个字段:
public ArrayList<int,int> category_count;
Collect方法改成:
private ArrayList<int,int> category_count;
category_count=new ArrayList<int,int>();
public void Collect(int doc,float score)
{
if(score>0.0f)
{
Documentd=reader.Document(doc);
int category=int.Parse(d.Get("category"));
if(category_count.ContainsKey(category))
category_count[category]++;
else
category_count.add(category,1);
totalHits++;
if(hq.Size()<numHits||score>=minScore)
{
hq.Insert(newScoreDoc(doc,score));
minScore=((ScoreDoc)hq.Top()).score;//maintainminScore
}
}
}
TopDocs方法改成
public TopDocsTopDocs() { ScoreDoc[]scoreDocs=new ScoreDoc[hq.Size()]; for(inti=hq.Size()-1;i>=0;i--) //putdocsinarray scoreDocs[i]=(ScoreDoc)hq.Pop(); float maxScore=(totalHits==0)?scoreDocs[0].score; TopDocs docs=new TopDocs(totalHits,scoreDocs,maxScore); docs.category_count=category_count; return docs; }
Hits类增加:
private ArrayList<int,int> category_count; public ArrayList<int,int> Category_Count{ get{ return category_count; } }
同时修改:
privatevoid GetMoreDocs(int min) { if(hitDocs.Count>min) { min=hitDocs.Count; } intn=min*2;//double#retrieved TopDocs topDocs=(sort==null)?searcher.Search(weight,filter,n):searcher.Search(weight,filter,n,sort); category_count=topDocs.category_count; length=topDocs.totalHits; ScoreDoc[]scoreDocs=topDocs.scoreDocs; floatscoreNorm=1.0f; if(length>0&&topDocs.GetMaxScore()>1.0f) { scoreNorm=1.0f/topDocs.GetMaxScore(); } intend=scoreDocs.Length<length?scoreDocs.Length:length; for(inti=hitDocs.Count;i<end;i++) { hitDocs.Add(newHitDoc(scoreDocs[i].score*scoreNorm,scoreDocs[i].doc)); } }
至此就OK了。从结果中取的时候,比如ID为1的分类,则
hits.Category_Count[1]就出来了。
相关文章推荐
- MySql按周/月/日分组统计数据的方法
- MySql按周/月/日分组统计数据的方法
- MySql按周/月/日分组统计数据的方法
- mysql按日期分组(group by)查询统计的时候,没有数据补0的解决办法
- 创业第23天,完成自定义分组数据统计图表
- poi分页导出,只能解决十几万数据的导出,内存问题没解决,有方案的可以留言
- lucene 分组统计查询
- MySql按周,按月,按日分组统计数据
- sql语句分组统计出年月日下数据记录数目
- Oracle按日期分组统计数据
- MySql按周,按月,按日分组统计数据
- MySql按周/月/日分组统计数据的方法
- Lucene中分组统计(GroupBy)及去重(Distinct)性能在数量级上提升解决方案 --- Lucene高性能
- 数据需求统计常用shell命令---AWK分组求和,分组统计次数
- MySql按周,按月,按日分组统计数据
- MySql之按周,按月,按日分组统计数据
- MySql按周,按月,按日分组统计数据
- 【案例分享】电力设备生产数据的多层分组统计报表实现
- Lucene中分组统计(GroupBy)及去重(Distinct)性能在数量级上提升解决方案 --- Lucene高性能
- SQL数据进行排序、分组、统计10技巧