lucene中用到的优先队列

来源:互联网 发布:linux怎么安装aptget 编辑:程序博客网 时间:2024/06/06 00:59

jdk有一个java.util.PriorityQueue。lucene中也有个PriorityQueue.为了节约空间和更高效,lucene没有使用jdkp中的PriorityQueue.它们的主要读取方法时间都是的log(n),但也有些不同。

下面看看lucene中使用的PriorityQueue它内部是一个堆排序。
java.util.PriorityQueue是一个自增长的优先队列.也就是说,随着插入元素的增加,它的容量会越来越大,而 org.apache.lucene.util.PriorityQueue则不会,它是一个指定的容量的优先队列。因为它保存的始终是最大的数据.因此,如果只取前n个数据时可以用lucene的PriorityQueue,这样可以达到节省内存。
下面分析一下原代码.
下面是lucene中的PriorityQueue的插入节点的实现细节,
public Object insertWithOverflow(Object element) {
if (size < maxSize) {//小于最大容量,直接放进堆
      put(element);
      return null;
    } else if (size > 0 && !lessThan(element, heap[1])) {//如果当前的堆已满,并且大于当前最小的元素,则将最小元素返回,并插入新元素
      Object ret = heap[1];
      heap[1] = element;
      adjustTop();//重新进行堆排序
      return ret;
    } else {//堆已满并且要插入的元素小于堆中最小的元素
      return element;
    }
}
heap[1]是堆顶,保存堆中的最小元素.
由引看出在org.apache.lucene.util.PriorityQueue中n是固定的,因此重新进行堆排序的时间是恒定的。

可能是为了提高插入效率,在org.apache.lucene.util.PriorityQueue的实现类TopDocCollector类中保存了队列中的最小元素,如果存在最小元素,则可以先与最小元素进行比较.再决定是否执行插入操作.
用变量保存了当前队列中最小的元素.以提高效率
   public void collect(int doc, float score) {
    if (score > 0.0f) {
      totalHits++;
      if (reusableSD == null) {
        reusableSD = new ScoreDoc(doc, score);
      } else if (score >= reusableSD.score) {//如果有最小元素,则与最小元素比较。如果大于最小元素则更新最小元素,并执行插入操作.
        // reusableSD holds the last "rejected" entry, so, if
        // this new score is not better than that, there's no
        // need to try inserting it
        reusableSD.doc = doc;
        reusableSD.score = score;
      } else {//如果小于最小元素,直接返回
        return;
      }
      reusableSD = (ScoreDoc) hq.insertWithOverflow(reusableSD);
    }
  }

不过个人认为insertWithOverflow方法里已经做了类似判断,而且从效率上来讲没区别,没必要在外面增加最小值判断,这样做反而容易引起逻辑不一致.