使用LINQ进行宽容/模糊搜索

我正在尝试对我inheritance的数据库实施搜索。 该要求声明用户必须能够按名称搜索对象。 不幸的是,一个对象可能有多个与之关联的名称。 例如:

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 DoeJane Doe时,是否可以编写一个可以返回记录的搜索方法(John和Jane Doe)?

这会损害性能,但这个快速的方法如何:

 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和Jane Doe”时,你会调整它以表现得很好。

这对你有用吗?

您可以创建名为“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; 

如果有多个别名,您可能需要将名称拉出到First / LastName列或其他表中。

但是我真的认为你应该看看像Lucene这样的东西,如果你需要“宽容”或“模糊”的东西

问题 :当有人使用搜索词John Doe或Jane Doe时,是否可以编写一个可以返回记录的搜索方法(John和Jane Doe)?

为了非常具体你的问题,你可以将“John Doe”转换为LIKE '%John%Doe'或“Jane Doe”转换为LIKE '%Jane%Doe' ,这将检索该记录。 但是我可以看到像“Johnathan Poppadoe”这样的名字出现问题。