`

获取一个索引文件频率最高的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;
    }
}


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/foamflower/archive/2010/12/01/6048672.aspx

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics