2012-10-31 8 views
7

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

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を使用している場合、レコード1(ジョンとジェーン・ドウ)を返す検索メソッドを記述することは可能ですか?

+0

は、あなたが離れて、​​検索文字列を破るために空白でのstring.Splitを行うことができますし、で複数のクエリを実行するだけです。すべての結果を含み、返しますか? –

+0

「John Smith」があればどうなりますか?それを分割して名前の各部分を検索しますか?名前とは何ですか?私が得意とするのは、現在の形では構造がないように見えるということです。 – hometoast

答えて

3

これは、パフォーマンスを傷つけるだろうが、どのようには:

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"のレコードを持っているときにうまく動作するようにチューニングします。

これは機能しますか?次に、あなたのLINQは、少なくとも読みやすくなり

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 
} 

+0

+1、それは確かに動作します!私の懸念は '.All()'の性能です。おそらく、これが現在のDBセットアップを考えれば、これを行う唯一の方法です。私はそれにトリガーを引く前に、この方法にコミュニティからの反応を見たいと思っています。 –

+1

まあまあ、あなたは標準の検索(あなたはDBの設定とすべての場合に応じて速度)を行うだろう。 All()ソリューションでは、平均で2〜3を掛けます(名前には通常FirstNameとLastNameが1つあります)。したがって、あなたが完全に一致する場合、あなたは文字列を分割する必要はありません、それは傷つくでしょう。最初は簡単な検索で緩和するのはどうですか。何も現れなければ、All()ビットを使用しますか?ちょうど思考を投げる – Vladimir

0

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

しかし、私は本当にあなたが「寛容」または「ファジー」なものが必要な場合は、あなたがそれでLuceneようになっているはずだと思う

質問:それは可能です を返す検索方法を書くために誰かが検索用語を使用したときに1つ(JohnとJane Doe)を記録します。John DoeまたはJane Doe?

あなたの質問に非常に。具体的には、あなたはLIKE '%Jane%Doe'LIKE '%John%Doe'に「ジョン・ドウ」または「ジェーン・ドウ」を変換することができ、これはそのレコードを取得します。しかし、私は "Johnathan Poppadoe"のような名前の問題を見ることができました。このクイック約1

7

あなたは「ContainsFuzzy」という名前のカスタム拡張メソッドを作成することができ

var objects = from x in db.Foo 
       where x.Name.ContainsFuzzy("Foo McFoo") 
       select x; 

明らかな欠点があることContainsFuzzyへの各呼び出しあなたの分割リストを再作成することなどを意味するので、いくつかのオーバーヘッドがあります。あなたは、少なくともあなたにいくつかの増加effeciencyを与えるだろう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; 
+0

私は多くのお手伝いをしました、ありがとう! – BjarkeCK

+0

"(?i)(?=。*" + String.Join( ")(?=。*"、_searchTerms)+ ")"); – JPVenson

+0

@jpvありがとう - 編集しました。 – JDB

関連する問題