12

継承したDBに対して検索を実装しようとしています。要件は、ユーザーが名前でオブジェクトを検索できる必要があることを示しています。残念ながら、オブジェクトには複数の名前が関連付けられている可能性があります。例えば:

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;

ただし、複数の名前が存在する場合、そのアプローチは機能しません。

質問:誰かが検索語を使用したときにレコード1(JohnとJane Doe)を返す検索メソッドを作成することは可能ですJohn DoeJane 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;

それはあなたが期待するものを返すようです。これで、「JohnDoe」と「Johnand 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

レーベンシュタイン距離アルゴリズムについて誰も言及しなかったのだろうか。

これは、2つの文字列間の距離をintで伝えるアルゴリズムです。

これは、このアルゴリズムのいくつかの実装を見つけることができるSOの投稿です。

したがって、シグネチャの距離関数をint Distance(string x, string y)使用すると、LINQを使用して、高距離をフィルターで除外し、結果の上に低距離が表示されるように結果を並べ替えることができます。
これはパフォーマンスにコストがかかることに注意してください。

于 2019-05-30T10:15:27.200 に答える
1

名前をFirst/LastName列にプルするか、複数のエイリアスがある場合は別のテーブルにプルする必要があります。

しかし、 「寛容」または「あいまい」なものが必要な場合は、 Luceneのようなものを見る必要があると私は本当に思います

質問:誰かが検索用語JohnDoeまたはJaneDoeを使用したときに、レコード1(JohnおよびJane Doe)を返す検索メソッドを作成することは可能ですか?

質問を非常に具体的にするために、「JohnDoe」LIKE '%John%Doe'または「 JaneDoe」をに変換するLIKE '%Jane%Doe'と、そのレコードが取得されます。しかし、「ジョナサン・ポッパドー」のような名前には問題がありました。

于 2012-10-31T16:48:11.787 に答える