了解Lucene领先的通配符性能

Lan*_*uhn 4 lucene solr full-text-search

Lucene默认情况下不允许在搜索术语中使用前导通配符,但可以使用以下命令启用:

QueryParser#setAllowLeadingWildcard(true)
Run Code Online (Sandbox Code Playgroud)

我知道使用前导通配符会阻止Lucene使用索引.使用前导通配符搜索必须扫描整个索引.

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

我已经构建了一个包含1000万个文档的测试索引:

{ name: random_3_word_phrase }
Run Code Online (Sandbox Code Playgroud)

磁盘上的索引是360M.

我的测试查询运行良好,我无法真正演示性能问题.例如,查询name:*ing在不到1秒的时间内生成超过110万份文档.查询同时name:*ing*生成超过150万个文档.

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

Gal*_*llo 6

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

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

举个例子,我启动了一个旧的2GB索引,并搜索了"*e".

在8GB的盒子上,它在5秒内返回500K命中.我在一个只有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;
}
Run Code Online (Sandbox Code Playgroud)

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

关键是,记忆力很快.一旦事情再也无法进入内存并且你必须开始交换到磁盘就是你要看到性能命中.