Luene的核心应用场景是全文检索。简单来说,就是通过用户输入的关键词来匹配相关文档,然后根据匹配程度返回TopN的查询结果给用户。 这里需要解决的一个核心问题就是如何快速返回TopN的结果,这本质上是一个排序的问题。说起排序,我们有很多选择,冒泡,快排,归并...。 这些排序算法在数据量小的时候,不是问题。一旦数据量过大,就成为问题了。

例如对1000万的数组排序:

        Integer[] a = new Integer[10000000];

        for(int i=0;i<10000000;i++){
            a[i] = (int) (Math.random()*10000000);
        }
        long start = System.currentTimeMillis();
        Arrays.sort(a);
        System.out.println((System.currentTimeMillis() - start) +" 毫秒");

在我的电脑耗时需要5秒左右, 这个等待时间对于用户体验来说,就不那么feeling good了。

这时候,该考虑优化了。优化基本上是一个做减法的过程。再回到我们的核心需求: 基于搜索关键词返回TopN的结果。 也就是说,我们只需要TopN的结果有序就可以了。 基于上述需求,我们引入一个新的数据结构: 堆(Heap)。

堆是一种特殊的二叉树。所谓二叉树就是每个节点最多有两个子节点: 最多生二胎,超生不被允许的。

对于二叉树这种树形结构,最核心的关系就是父子节点关系。 定义不同的节点关系,我们就能得到丰富多彩的数据结构,以应对不同场景的业务问题。比如:

规定“子节点不能大于父节点”, 我们可以得出根节点是最大的节点, 得到大顶堆。

规定“子节点不能小于父节点”, 我们可以得出根节点是最小的节点, 得到小顶堆。

规定“根节点大于左子树,小于右子树;子树亦是如此”, 我们得到二叉搜索树;为了使二叉搜索树的左右尽量平衡,我们又得到了“红黑树”,“AVL树”,Treap等不同策略的平衡树。

这些概念性的东西,能理解就OK.

理解了堆的来龙去脉, 我们可能会有点困惑,它并没有直接维护一个有序的结构。 是的,它没有直接维护有序的结构,它是通过删除数据实现排序功能的。理解这一点特别重要。 以大顶堆为例: 由于堆顶是最大的元素,所以