Lucene默认情况下不允许在搜索字词but this can be enabled中使用前导通配符:
QueryParser#setAllowLeadingWildcard(true)
据我所知,使用前导通配符会阻止Lucene使用索引。使用前导通配符搜索必须扫描整个索引。
如何演示领先通配符查询的性能?什么时候可以使用setAllowLeadingWildcard(true)
?
我已经构建了一个包含1000万个文档的测试索引:
{ name: random_3_word_phrase }
磁盘上的索引是360M。
我的测试查询效果很好,但我无法真正演示性能问题。例如,查询name:*ing
会在不到1秒的时间内生成超过110万份文档。查询name:*ing*
同时生成超过150万份文档。
这是怎么回事?为什么这不慢? 10,000,000份文件还不够吗?文档是否需要包含多个字段?
答案 0 :(得分: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;
}
在将所有1000万个阶段加载到列表中之后,“var matches = index.FindAll(SubstringPredicate);”仍然只需要大约一秒钟。返回超过400万次。
重点是,记忆力很快。一旦事情再也无法进入内存,你必须开始交换到磁盘就是你要看到性能命中。
答案 1 :(得分:1)
如果我理解正确,索引的一部分是术语词典,它是所有索引术语的排序列表。当没有通配符或尾随通配符进行搜索时,Lucene可以利用许多术语具有共同前缀的事实。另一方面,使用前导通配符进行搜索会扫描整个术语词典。这不是最优的,但与索引的其他部分(例如频率和位置数据)相比,术语词典往往很小,因此术语词典的完整扫描本身通常不是大问题。