5

Lucene 默认情况下不允许在搜索词中使用前导通配符,但可以通过以下方式启用

QueryParser#setAllowLeadingWildcard(true)

我了解使用前导通配符会阻止 Lucene 使用索引。带有前导通配符的搜索必须扫描整个索引。

如何演示领先的通配符查询的性能?什么时候可以使用setAllowLeadingWildcard(true)

我已经建立了一个包含 1000 万个文档的测试索引,格式如下:

{ name: random_3_word_phrase }

磁盘上的索引为 360M。

我的测试查询执行良好,但我无法实际演示性能问题。例如,查询name:*ing在不到 1 秒的时间内生成超过 110 万个文档。查询name:*ing*同时产生超过 150 万个文档。

这是怎么回事?为什么这么慢?10,000,000 个文档还不够吗?文档是否需要包含多个字段?

4

2 回答 2

8

取决于你有多少内存,以及有多少令牌索引在内存中。

在任何旧计算机上都可以快速搜索 360MB 的总索引。360GB 的索引需要更长的时间...... ;)

例如,我启动了一个旧的 2GB 索引,并搜索“*e”。

在一个 8GB 的​​盒子上,它在 5 秒内返回了 50 万次点击。我在一个只有 1GB 内存的盒子上尝试了相同的索引,大约花了 20 秒。

为了进一步说明,这里有一些通用的 C# 代码,它基本上对 1000 万个随机 3 词短语进行“** E*”类型的搜索。

static string substring = "E";

private static Random random = new Random((int)DateTime.Now.Ticks);//thanks to McAden

private static string RandomString(int size)
{
    StringBuilder builder = new StringBuilder();
    char ch;
    for (int i = 0; i < size; i++)
    {
        ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
        builder.Append(ch);
    }

    return builder.ToString();
}

static void FindSubStringInPhrases()
{
    List<string> index = new List<string>();

    for (int i = 0; i < 10000000; i++)
    {
        index.Add(RandomString(5) + " " + RandomString(5) + " " + RandomString(5));
    }

    var matches = index.FindAll(SubstringPredicate);

}

static bool SubstringPredicate(string item)
{
    if (item.Contains(substring))
        return true;
    else
        return false;
}

在将所有 1000 万个阶段加载到列表中之后,“var matches = index.FindAll(SubstringPredicate);”仍然只需要大约一秒钟 返回超过 400 万次点击。

关键是,内存很快。一旦事情不再适合内存并且您必须开始交换到磁盘,您就会看到性能下降。

于 2012-08-01T19:51:58.803 回答
2

如果我理解正确的话,索引的一部分是术语字典,它是所有索引术语的排序列表。在没有通配符或尾随通配符的情况下进行搜索时,Lucene 可以利用许多术语具有共同前缀这一事实。另一方面,使用前导通配符进行搜索会扫描整个术语词典。这不是最优的,但是与索引的其他部分(例如频率和位置数据)相比,术语字典往往很小,因此对术语字典进行全面扫描通常本身并不是什么大问题。

于 2012-08-01T19:55:21.423 回答