我正在尝试对我继承的数据库实施搜索。该要求规定用户必须能够按名称搜索对象。不幸的是,一个对象可能有多个与之关联的名称。例如:
ID Name 1 John and Jane Doe 2 Foo McFoo 3 Boo McBoo
当每个记录中存在单个名称时,很容易实现搜索:
var objects = from x in db.Foo
where x.Name.Contains("Foo McFoo")
select x;
但是,当存在多个名称时,该方法不起作用。
问题:当有人使用搜索字词John Doe
或Jane Doe
时,是否可以编写一个返回记录的搜索方法(John和Jane Doe)?< / p>
答案 0 :(得分:7)
您可以创建名为“ContainsFuzzy”的自定义扩展方法:
public static bool ContainsFuzzy(this string target, string text){
// do the cheap stuff first
if ( target == text ) return true;
if ( target.Contains( text ) ) return true;
// if the above don't return true, then do the more expensive stuff
// such as splitting up the string or using a regex
}
然后你的LINQ至少会更容易阅读:
var objects = from x in db.Foo
where x.Name.ContainsFuzzy("Foo McFoo")
select x;
明显的缺点是每次调用ContainsFuzzy意味着重新创建拆分列表等,因此涉及一些开销。你可以创建一个名为FuzzySearch的类,它至少可以提高你的效率:
class FuzzySearch{
private string _searchTerm;
private string[] _searchTerms;
private Regex _searchPattern;
public FuzzySearch( string searchTerm ){
_searchTerm = searchTerm;
_searchTerms = searchTerm.Split( new Char[] { ' ' } );
_searchPattern = new Regex(
"(?i)(?=.*" + String.Join(")(?=.*", _searchTerms) + ")");
}
public bool IsMatch( string value ){
// do the cheap stuff first
if ( _searchTerm == value ) return true;
if ( value.Contains( _searchTerm ) ) return true;
// if the above don't return true, then do the more expensive stuff
if ( _searchPattern.IsMatch( value ) ) return true;
// etc.
}
}
你的LINQ:
FuzzySearch _fuzz = new FuzzySearch( "Foo McFoo" );
var objects = from x in db.Foo
where _fuzz.IsMatch( x.Name )
select x;
答案 1 :(得分:4)
这会影响性能,但这个快速的方法呢:
string[] filters = "John Doe".Split(new[] {' '});
var objects = from x in db.Foo
where filters.All(f => x.Name.Contains(f))
select x;
它似乎回归了你的期望。现在,当你还有一张唱片“John Doe”以及“John and Jane Doe”时,你会调整它以表现得很好。
这对你有用吗?
答案 2 :(得分:0)
如果有多个别名,您可能需要将名称拉出到First / LastName列或其他表中。
但我真的认为如果你需要'宽容'或'模糊'的话,你应该把它看作Lucene之类的东西
问题:是否可以编写将返回的搜索方法 当有人使用搜索词John时记录一个(John和Jane Doe) Doe还是Jane Doe?
要非常特定于您的问题,您可以将“John Doe”转换为LIKE '%John%Doe'
或“Jane Doe”转换为LIKE '%Jane%Doe'
,这将检索该记录。但是我可以看到像“Johnathan Poppadoe”这样的名字出现问题。
答案 3 :(得分:0)
我想知道没有人提到Levenshtein距离算法。
这是一种算法,可以通过一个整数告诉两个字符串之间的距离。
Here是一篇SO帖子,您可以找到该算法的一些实现。
因此,通过使用签名int Distance(string x, string y)
的距离函数,您可以使用LINQ过滤远距离并对结果进行排序,以使低距离出现在结果顶部。
请注意,这将导致性能损失。