12

我正在尝试对我继承的数据库进行搜索。该要求规定用户必须能够按名称搜索对象。不幸的是,一个对象可能有多个与之关联的名称。例如:

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或时返回记录一(John 和 Jane Doe) Jane Doe

4

4 回答 4

10

这会损害性能,但是这个快速的怎么样:

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”时,您可以调整它以使其表现得很好。

这对你有用吗?

于 2012-10-31T17:03:10.160 回答
9

您可以创建一个名为“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;
于 2012-10-31T17:23:25.443 回答
3

我想知道怎么没有人提到 Levenshtein 距离算法。

这是一种算法,通过 int 告诉两个字符串之间的距离。

是一个 SO 帖子,您可以找到该算法的一些实现。

因此,使用 signature 的距离函数int Distance(string x, string y),您可以使用 LINQ 过滤掉高距离并对结果进行排序,以便低距离出现在结果之上。
请注意,这将导致性能代价高昂。

于 2019-05-30T10:15:27.200 回答
1

如果有多个别名,您可能需要将名称提取到 First/LastName 列或另一个表中。

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

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

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

于 2012-10-31T16:48:11.787 回答