获取一个索引文件频率最高的Term(可实现热点关键字的一个思路之一)

    前段时间同事也开始对搜索感兴趣,他看到luke工具界面上会显示Term的频率数,提出通过索引用户的搜索日志中的检索关键字,我们是否可以利用这个Field字段中Term频率高低来说明其是否代表热点关键字。

    想想觉得也是有一点在理,特别是对用户没有任何可分析性的情况下。但这就引出了一个问题:如何获取整个索引文件里频率最高的哪几个Term?

    翻了几次API,网上也搜了但没找到什么信息,仅仅看到网上有一篇文章讲到通过IndexReader取出所有的Term,然后再比较每一个的频率,最终得出最高频率的哪几个Term。但这又让我们顾虑的是当大数据量时如何确保其速度?

    既然luke可以在界面上展示出来,那它一定实现了这个功能,所以今天下了源代码,不过发现其已经不支持Lucene3.0.2,查看更新日志原来他们已经更新到可兼容未来Lucene4.0.0版本。最后从日志里找出已被删除的两个java文件:HighFreqTerms.java 和TermInfo.java,源代码如下(本人在里面添加了注释,如有错误请大家帮忙纠正,:-D):

import org.apache.lucene.index.Term;
public class TermInfo {
   public Term term;
   public int docFreq; //term频率
  
   public TermInfo(Term t, int df) {
     this.term = t;
     this.docFreq = df;
  }
}
import org.apache.lucene.util.PriorityQueue;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.TermEnum;
import java.io.File;
import java.util.Hashtable;
/**
 * 获取一个索引文件中最高频率Term数组
 * <code>HighFreqTerms</code> class extracts terms and their frequencies out
 * of an existing Lucene index.
 *
 * @version $Id: HighFreqTerms.java,v 1.2 2003/11/08 10:55:40 Administrator Exp $
 */

public class HighFreqTerms {
     public static int defaultNumTerms = 10; //初始化默认取出top defaultNumTerms-1条
    
     public static void main(String[] args) throws Exception {
        Directory dir = FSDirectory.open( new File( "D://DATAMANAGER//INDEX//SYS_3000"));
        TermInfo[] terms = getHighFreqTerms(IndexReader.open(dir), null, new String[]{ "content"});
         for ( int i = 0; i < terms.length; i ++) {
            System.out.println(i + "./t" + terms[i].term + ":" +terms[i].docFreq);
        }
    }
    
     /**
     * 取出频率最高的term列表
     * @param ir IndexReader
     * @param junkWords Hashtable 过滤词
     * @param fields 可获取多个Field new String[]{"title","content"}
     * @return TermInfo[] 
     * @throws Exception
     */

     public static TermInfo[] getHighFreqTerms(IndexReader ir, Hashtable junkWords, String[] fields) throws Exception {
         return getHighFreqTerms(ir, junkWords, defaultNumTerms, fields);
    }
    
     /**
     * 取出频率最高的term列表
     * @param reader IndexReader
     * @param junkWords Hashtable 过滤词
     * @param numTerms 初始化队列的大小即取出numTerms-1条
     * @param fields 可获取多个Field new String[]{"title","content"}
     * @return TermInfo[] 
     * @throws Exception
     */

     public static TermInfo[] getHighFreqTerms(IndexReader reader, Hashtable junkWords, int numTerms, String[] fields) throws Exception {
         if (reader == null || fields == null) return null;
        TermInfoQueue tiq = new TermInfoQueue(numTerms); //实例化一个numTerms大小存放TermInfo的队列
        TermEnum terms = reader.terms(); //读取索引文件里所有的Term
         int minFreq = 0; //队列最后一个Term的频率即当前最小频率值
         while (terms.next()) { //取出一个Term对象出来
            String field = terms.term().field();
             if (fields != null && fields.length > 0) {
                 boolean skip = true; //跳过标识
                 for ( int i = 0; i < fields.length; i ++) {
                     if (field.equals(fields[i])) { //当前Field属于fields数组中的某一个则不跳过
                        skip = false;
                         break;
                    }
                }
                 if (skip) continue;
            }
             //当前term的内容是过滤词,则直接跳过
             if (junkWords != null && junkWords.get(terms.term().text()) != null) continue;
           
             //获取最高频率term的核心代码
             //(队列底层是最大频率Term,顶层是最小频率Term,当插入一个元素后超出初始化队列大小则pop最上面的那个元素,重新设置最小频率值minFreq)
             if (terms.docFreq() > minFreq) { //当前Term的频率大于最小频率则插入队列中
                tiq.insertWithOverflow( new TermInfo(terms.term(), terms.docFreq()));
                 if (tiq.size() > = numTerms) // if tiq overfull 当队列中的个数大于numTerms
                {
                    tiq.pop();   // remove lowest in tiq 取出最小频率的元素即最上面的一个元素
                    minFreq = ((TermInfo)tiq.top()).docFreq; // reset minFreq 重新设置当前最顶层Term的频率为minFreq
                }
            }
        }
         //pop出队列元素,最终存放在数组中元素的term频率按从大到小排列
        TermInfo[] res = new TermInfo[tiq.size()];
         for ( int i = 0; i < res.length; i ++) {
            res[res.length - i - 1] = (TermInfo)tiq.pop();
        }
         return res;
    }
}
//队列,用于term频率比较的队列
final class TermInfoQueue extends PriorityQueue <TermInfo > {
    TermInfoQueue( int size) {
        initialize(size);
    }
     protected final boolean lessThan(TermInfo a, TermInfo b) {
         return a.docFreq < b.docFreq;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值