2013-07-16 33 views
3

我有一个非常庞大的词典,里面的内容,它看起来像:
(在字典中不包括标题)如何加快在一个巨大的字典搜索

(code)  (names) 
------------------------------ 
910235487  Diabetes, tumors, sugar sick, ..... 

我有超过15万线这种对在字典中。

用户输入是关键字(诊断名称),我无法通过键搜索字典。

下面是代码:

var relevantIDs = this.dic.Where(ele => ele.Value.Contains(keyword)).Select(n => Convert.ToUInt64(n.Key)); 

字典是Dictionary<string, string>和我必须使用字符串作为密钥的数据类型,这是因为代码可以有时含有的字符。名称列包含相关诊断名称的列表。所以我也不能改变这种数据类型。

我认为这个问题是对的每个值,我做了Contains操作并会减慢谁处理,但我不能找到一个替代办法做下去......

这是我做过什么以找到匹配的代码。
但是,这段代码的性能很糟糕(完成这一行代码大约需要5分钟)。

有人可以帮忙吗?


更新和简单的解决方案:

我终于找到了赛季为什么搜索是如此缓慢,并通过这样做解决了这个问题:

var relevantStringIDs = this.dic.Where(ele => ele.Value.Contains(keyword)).Tolist(); 
var relevantUlongIDs = relevantStringIDs.Select(n => Convert.ToUInt64(n.Key)).Tolist(); 

之所以说它是慢是this.dic.Where(ele => ele.Value.Contains(keyword)),每执行一次查询的第二部分就会执行(这是IEnumberable<T>的功能,我忘记了它的用语(可能是延迟执行))。因此,我使用ToList()将延迟查询转换为内存中的具体列表,以便在将字符串转换为ulongs时可以重新使用结果,而不是为每次转换再次执行查询。
如果您在此解释中发现错误,请纠正我。

顺便说一句,虽然这可能不是最好的解决方案,但改变后的代码的性能很安静。代码的第一个声明只需169 ms,对我来说足够快。

+0

嗨,大家好,请不要downvote我的问题没有告诉我的原因。我查了其他类似的问题,但没有一个真正解决了我的问题。 – Franva

+0

如果您的代码可以包含字符,您将很难将它们全部转换为Int64 ... –

+0

术语是“[延期执行]”(http://msdn.microsoft.com/en-us/library /bb943859.aspx)”。然而,在Where和Select之间发布一个额外的ToList在这种情况下不太可能有助于提高性能。如果你多次迭代最终结果(我假设你是),那么你主要从* final *'ToList'中受益。尝试从'dic.Where(...)。ToList()。选择(...)。ToList()'到'dic.Where(...)。Select。(...)。ToList )' - 你会发现性能几乎没有变化。 – Douglas

回答

4

你这样做是错误的。当您知道密钥时,字典允许高效查找,而不是数值。

固定性能将构建一个反向字典在你的内容模仿全文索引的一个简单的方法:

var dic = new Dictionary<string, string>(); 
dic.Add("910235487", "Diabetes, tumors, sugar sick"); 
dic.Add("120391052", "Fever, diabetes"); 

char[] delimiters = new char[] { ' ', ',' }; 

var wordCodes = 
    from kvp in dic 
    from word in kvp.Value.Split(delimiters, StringSplitOptions.RemoveEmptyEntries) 
    let code = long.Parse(kvp.Key) 
    select new { Word = word, Code = code }; 

var fullTextIndex = 
    wordCodes.ToLookup(wc => wc.Word, wc => wc.Code, StringComparer.OrdinalIgnoreCase); 

long[] test1 = fullTextIndex["sugar"].ToArray();  // Gives 910235487 
long[] test2 = fullTextIndex["diabetes"].ToArray(); // Gives 910235487, 120391052 

全文索引将需要很长时间的建设;然而,这是一次性成本,并且将通过随后查找节省的时间来摊销。

+0

+1比我的一点清洁,我认为 –

+0

谢谢,我在尝试:) – Franva

+0

嗨,道格拉斯,我发现隐藏在我的代码中的问题。但是,无论如何,我喜欢你的方式,谢谢:) – Franva

2

您的问题是您通过迭代它的值而失去了字典的所有速度优势。字典针对密钥查找进行了优化。

我会用不同的数据类型来处理它,并为你的关键字查找进行优化。

下面是使用LINQ从类似于您的数据创建Lookup的示例。在这种情况下,我直接从字符串数据构建它,这完全避免了字典。

这种类型的查找应该更好。

string [] lines = { 
"123 A, B, C, D", 
"456 E, F, G", 
"321 A, E, H, I", 
"654 B, G", 
"789 A, J, K, L", 
"987 A, M, L, E" 
}; 

var lookup = lines.SelectMany (
    l => (l.Split(new char[]{' '},2)[1]).Split(',').Select (v => v.Trim().ToLower()).ToArray(), 
    (l,o) => new{ 
    keyword = o, 
    code = Convert.ToInt64(l.Split(' ')[0]) 
}).ToLookup(k => k.keyword, v => v.code).Dump(); 

Console.WriteLine(String.Join(",",lookup["a"])); 
Console.WriteLine(String.Join(",",lookup["l"])); 
Console.WriteLine(String.Join(",",lookup["b"])); 

注意,这里假设你正在寻找一个个完整的关键字(您最初的例子中可以查找局部关键字)

+0

谢谢马克:)我现在就试试 – Franva

+0

+1使用LookUp :)干杯 – Franva