我在这里解释术语和复杂程度有点挣扎,随时编辑它。
我有1.000 - 20.000个对象。每个人都可以包含几个名字(第一,第二,中间,最后,标题......)和标准化数字(家庭,商业......),电子邮件地址甚至物理地址和配偶名称。
我想实现一个搜索,使用户能够自由组合单词部分和数字部分。
当我搜索" LL 676"我想找到包含任何字符串的所有对象" LL" AND" 676"。
目前我正在遍历每个对象和每个对象属性,将searchString拆分为" "并执行stringInstance.Contains(searchword)。
这太慢了,所以我正在寻找更好的解决方案。
与此相关的语言无关数据结构是什么?
就我而言,我需要它用于C#
以下数据结构是否是一个很好的解决方案?
它基于HashMap / Dictionary
首先,我创建一个字符串,其中包含我想要查看的所有姓名部分和电话号码,例如:" William Bill Henry Gates III 3. +436760000 billgatesstreet 12":
然后我分开" "并且对于每个单词x,我创建所有可能的子字符串y fullfill x.contains(y)。我将每个子字符串放在hashmap / dictionary中
在查找/搜索时,我只需要调用每个搜索词并搜索结果。当然,查找速度非常快(原生Hashmap /字典速度)。
编辑:由于我使用更智能的算法来获取子串,所以插入也非常快(无关紧要的时间)。
答案 0 :(得分:1)
我可能误解了您的算法或要求,但这似乎可能会带来潜在的性能提升:
foreach (string arg in searchWords)
{
if (String.IsNullOrEmpty(arg))
continue;
tempList = new List<T>();
if (dictionary.ContainsKey(arg))
foreach (T obj in dictionary[arg])
if (list.Contains(obj))
tempList.Add(obj);
list = new List<T>(tempList);
}
这个想法是你在此之前单独做第一个搜索词,并且只将所有后续词放入searchWords列表。
这应该允许你完全删除你的最终foreach循环。结果只保留在您的列表中,只要它们保持匹配每个searchWord,而不是最初必须堆积匹配单个单词的所有内容,然后在结束时将它们过滤掉。
答案 1 :(得分:0)
如果有人关心我的解决方案:
免责声明:
这只是草稿
我只做了一些综合测试,并且我已经编写了很多它而没有再次测试。
我修改了我的代码:插入现在是((n ^ 2)/ 2)+(n / 2)而不是2 ^ n-1无限快。字长现在无关紧要。
namespace MegaHash
{
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
public class GenericConcurrentMegaHash<T>
{
// After doing a bulk add, call AwaitAll() to ensure all data was added!
private ConcurrentBag<Task> bag = new ConcurrentBag<Task>();
private ConcurrentDictionary<string, List<T>> dictionary = new ConcurrentDictionary<string, List<T>>();
// consider changing this to include for example '-'
public char[] splitChars;
public GenericConcurrentMegaHash()
: this(new char[] { ' ' })
{
}
public GenericConcurrentMegaHash(char[] splitChars)
{
this.splitChars = splitChars;
}
public void Add(string keyWords, T o)
{
keyWords = keyWords.ToUpper();
foreach (string keyWord in keyWords.Split(splitChars))
{
if (keyWord == null || keyWord.Length < 1)
return;
this.bag.Add(Task.Factory.StartNew(() => { AddInternal(keyWord, o); }));
}
}
public void AwaitAll()
{
lock (this.bag)
{
foreach (Task t in bag)
t.Wait();
this.bag = new ConcurrentBag<Task>();
}
}
private void AddInternal(string key, T y)
{
for (int i = 0; i < key.Length; i++)
{
for (int i2 = 0; i2 < i + 1; i2++)
{
string desire = key.Substring(i2, key.Length - i);
if (dictionary.ContainsKey(desire))
{
List<T> l = dictionary[desire];
lock (l)
{
try
{
if (!l.Contains(y))
l.Add(y);
}
catch (Exception ex)
{
ex.ToString();
}
}
}
else
{
List<T> l = new List<T>();
l.Add(y);
dictionary[desire] = l;
}
}
}
}
public IList<T> FulltextSearch(string searchString)
{
searchString = searchString.ToUpper();
List<T> list = new List<T>();
string[] searchWords = searchString.Split(splitChars);
foreach (string arg in searchWords)
{
if (arg == null || arg.Length < 1)
continue;
if (dictionary.ContainsKey(arg))
foreach (T obj in dictionary[arg])
if (!list.Contains(obj))
list.Add(obj);
}
List<T> returnList = new List<T>();
foreach (T o in list)
{
foreach (string arg in searchWords)
if (dictionary[arg] == null || !dictionary[arg].Contains(o))
goto BREAK;
returnList.Add(o);
BREAK:
continue;
}
return returnList;
}
}
}