LINQ

2012-10-31 27 views
7
ile bağışlama/Bulanık arama

Devraldığım bir DB'ye karşı bir arama yapmayı deniyorum. Gereklilik, kullanıcının bir nesneyi isme göre arayabilmesi gerektiğini belirtir. Ne yazık ki, bir nesne onunla ilişkili birden çok isme sahip olabilir. Tek bir isim her kayıt var olduğunda bir arama uygulamak için yeterli kolaydırLINQ

ID Name 
1  John and Jane Doe 
2  Foo McFoo 
3  Boo McBoo 

: Örneğin:

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

Ancak, birden fazla isimleri var olduğunda, bu yaklaşım çalışmaz.

Soru: Kaydın bir dönecekti Bir arama yöntemi yazmak mümkün mü (John ve Jane Doe) birisi arama terimleri John Doe veya Jane Doe kullandığında?

+0

Eğer ayrı arama dizesini kırmak için boşluk üzerinde bir string.split yapabilir miyiz ve sonra sadece birden fazla sorgu ile çalıştırın.Tüm sonuçları içeriyor ve geri veriyor musunuz? –

+0

"John Smith" varsa ne olur? Bölün ve ismin her bir parçasını mı arıyorsun? İlk ve soyadını yapan nedir? Benim aldığım şey şu anki haliyle ismin hiçbir yapıya sahip olmadığı. – hometoast

cevap

3

Bu performansı zarar vereceğini, ama nasıl:

string[] filters = "John Doe".Split(new[] {' '}); 
var objects = from x in db.Foo 
       where filters.All(f => x.Name.Contains(f)) 
       select x; 

O ne beklediğiniz dönmek gibi görünüyor. Şimdi bir de "John Doe" yanı sıra "John ve Jane Doe" olduğu zaman güzel davranmak için ayarlayacağız.

Bu sizin için çalışıyor mu? Ardından LINQ en azından okuma daha kolay olurdu

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, Kesinlikle işe yarıyor! Benim endişem '.All()' performans. Belki de mevcut DB kurulumu göz önüne alındığında bunu yapmanın tek yolu budur. Tetikleyiciyi çekmeden önce topluluğun tepkisini bu yönteme kadar görmeyi çok isterim ... –

+1

Tüm bunlar olmadan standart bir arama yaparsınız (DB yapılandırması ve hepsine bağlı olarak hız). All() çözümüyle, ortalamada 2-3 ile çarptığınızda (isimlerin genellikle bir FirstName ve bir LastName varsa). Yani tam bir maçınız olduğunda, ipi bölmek zorunda kalmazsınız, bu da incinir. İlk başta basit bir arama ile hafifletmeye ne dersin ve eğer bir şey çıkmazsa, All() bitini kullanın? Sadece düşünceler atıyor – Vladimir

0

Birden çok takma ad varsa, adların İlk/Soyadı sütunlarına veya başka bir tabloya çekilmesi gerekir.

Ama gerçekten bir şey 'bağışlayıcı' veya 'bulanık'

Soru gerekirse Lucene Ona sanki görünmelidir ne düşündüğünü: dönecekti Bir arama yöntemi yazmak mümkün mü Birisi John Doe veya Jane Doe arama terimlerini kullandığında birini (John ve Jane Doe) kaydetmek?

Eğer LIKE '%Jane%Doe' için LIKE '%John%Doe' veya "Jane Doe" için "John Doe" dönüştürmek olabilir, Sorunuza çok özgü olmak ve bu söz konusu kaydı almak istiyorum. Ancak "Johnathan Poppadoe" gibi isimlerle ilgili sorunları görebiliyordum. Bu hızlı biri hakkında

7

Sen "ContainsFuzzy" adlı özel uzatma yöntemi oluşturabilirsiniz

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

bariz dezavantajı olduğunu ContainsFuzzy her çağrı bölünmüş listenizi vb. yeniden oluşturmak anlamına gelir, bu nedenle bazı ek yükler vardır.

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. 
    } 

} 

Sizin LINQ:: En az bazı artan kullanılarak verimlilik verecekti FuzzySearch adında bir sınıf oluşturabilir

FuzzySearch _fuzz = new FuzzySearch("Foo McFoo"); 

var objects = from x in db.Foo 
       where _fuzz.IsMatch(x.Name) 
       select x; 
+0

Bana yardım etti, teşekkürler! – BjarkeCK

+0

olmalıdır "(? I) (? =. *" + String.Join (") (? =. *", _searchTerms) + ")"); – JPVenson

+0

@jpv teşekkürler - düzenlendi. – JDB