2012-07-23 18 views
45

मुझे एहसास है कि पूर्ण पाठ खोज और इकाई फ्रेमवर्क से संबंधित कई प्रश्न पूछे गए हैं, लेकिन मुझे आशा है कि यह प्रश्न थोड़ा अलग होगा।इकाई फ्रेमवर्क, कोड प्रथम और पूर्ण पाठ खोज

मैं इकाई फ्रेमवर्क, कोड प्रथम का उपयोग कर रहा हूं और पूर्ण टेक्स्ट खोज करने की आवश्यकता है। जब मुझे पूर्ण पाठ खोज करने की आवश्यकता होती है, तो मेरे पास आमतौर पर अन्य मानदंड/प्रतिबंध भी होंगे - जैसे कि पहली 500 पंक्तियां छोड़ें, या किसी अन्य कॉलम पर फ़िल्टर करें, आदि

मुझे लगता है कि यह मूल्यवान तालिका का उपयोग करके संभाला गया है कार्य - http://sqlblogcasts.com/blogs/simons/archive/2008/12/18/LINQ-to-SQL---Enabling-Fulltext-searching.aspx देखें। और यह सही विचार की तरह लगता है।

दुर्भाग्य से, तालिका मूल्यवान फ़ंक्शंस एंटीटी फ्रेमवर्क 5.0 तक समर्थित नहीं हैं (और फिर भी, मेरा मानना ​​है कि वे पहले कोड के लिए समर्थित नहीं हैं)।

मेरा असली सवाल यह है कि एंटीटी फ्रेमवर्क 4.3 और एंटिटी फ्रेमवर्क 5.0 दोनों के लिए इसे संभालने का सबसे अच्छा तरीका क्या है। लेकिन विशिष्ट होना: (, System.Data.Entity.DbSet.SqlQuery के माध्यम से उदाहरण के लिए)

  1. अन्य गतिशील एसक्यूएल से, किसी भी विकल्प इकाई की रूपरेखा 4.3 के लिए उपलब्ध हैं?

  2. यदि मैं एंटिटी फ्रेमवर्क 5.0 में अपग्रेड करता हूं, तो क्या मैं पहले कोड के साथ तालिका मूल्यवान कार्यों का उपयोग कर सकता हूं?

धन्यवाद, एरिक

+0

प्रश्न का सवाल है (1), मेरा मानना ​​है कि यह अपने ही उम्मीद – billy

+5

मैं पूर्ण पाठ खोज के लिए Lucene.Net उपयोग करने का सुझाव है। – LeffeBrune

+1

Lucene.Net पर एक नज़र डालें :) –

उत्तर

16

मैं पाया है सबसे आसान तरीका लागू है कि करने के लिए इस सेटअप करने के लिए है और SQL सर्वर में पूर्ण-पाठ-खोज कॉन्फ़िगर और फिर एक संग्रहीत प्रक्रिया का उपयोग करें। एसक्यूएल में अपने तर्क पास करें, डीबी को अपना काम करने दें और या तो एक जटिल ऑब्जेक्ट लौटाएं या परिणामों को किसी इकाई में मैप करें। आपको जरूरी नहीं है कि गतिशील एसक्यूएल हो, लेकिन यह इष्टतम हो सकता है। उदाहरण के लिए, यदि आपको पेजिंग की आवश्यकता है, तो आप गतिशील एसक्यूएल की आवश्यकता के बिना प्रत्येक अनुरोध पर पेज नम्बर और पेजसाइज में पास कर सकते हैं। हालांकि, यदि तर्कों की संख्या प्रति क्वेरी में उतार-चढ़ाव करती है, तो यह इष्टतम समाधान होगा।

+3

कभी कभी हम भूल जाते हैं कि हम हमेशा की कोशिश की और सच संग्रहीत प्रक्रिया पर वापस गिर सकता है! मैं इस विधि को इंटरसेप्टर हैक को भी पसंद करता हूं। –

2

अन्य लोग उल्लेख किया है, मैं Lucene.NET

का उपयोग कर कि CodePlex

पर पाया जा सकता

Lucene एक बहुत उच्च सीखने की अवस्था है, लेकिन के लिए यह "SimpleLucene" नामक एक आवरण पाया, शुरू कहेंगे

मुझे ब्लॉग से कुछ कोडब्लॉक उद्धृत करने दें ताकि आपको यह दिखाया जा सके कि इसका उपयोग करना कितना आसान है। मैंने अभी इसका उपयोग करना शुरू कर दिया है, लेकिन वास्तव में इसे लटका दिया है।

पहले, अपने भंडार से कुछ संस्थाओं मिलता है, या अपने मामले में, इकाई की रूपरेखा

public class Repository 
{ 
    public IList<Product> Products { 
     get { 
      return new List<Product> { 
       new Product { Id = 1, Name = "Football" }, 
       new Product { Id = 2, Name = "Coffee Cup"}, 
       new Product { Id = 3, Name = "Nike Trainers"}, 
       new Product { Id = 4, Name = "Apple iPod Nano"}, 
       new Product { Id = 5, Name = "Asus eeePC"}, 
      }; 
     } 
    } 
} 

का उपयोग अगली बात आप क्या करना चाहते एक सूचकांक परिभाषा

public class ProductIndexDefinition : IIndexDefinition<Product> { 
    public Document Convert(Product p) { 
     var document = new Document(); 
     document.Add(new Field("id", p.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED)); 
     document.Add(new Field("name", p.Name, Field.Store.YES, Field.Index.ANALYZED)); 
     return document; 
    } 

    public Term GetIndex(Product p) { 
     return new Term("id", p.Id.ToString()); 
    } 
} 

बना सकते हैं और बनाने है इसके लिए एक खोज सूचकांक।

var writer = new DirectoryIndexWriter(
    new DirectoryInfo(@"c:\index"), true); 

var service = new IndexService(); 
service.IndexEntities(writer, Repository().Products, ProductIndexDefinition()); 

तो, अब आपके पास एक खोज-योग्य अनुक्रमणिका है। करने के लिए एकमात्र शेष चीज है .., खोज!आप बहुत अद्भुत काम कर सकते हैं, लेकिन यह इस रूप में के रूप में आसान हो सकता है: (अधिक से अधिक उदाहरण के लिए ब्लॉग या codeplex पर दस्तावेज़ीकरण देखें)

var searcher = new DirectoryIndexSearcher(
       new DirectoryInfo(@"c:\index"), true); 

var query = new TermQuery(new Term("name", "Football")); 

var searchService = new SearchService(); 

Func<Document, ProductSearchResult> converter = (doc) => { 
    return new ProductSearchResult { 
     Id = int.Parse(doc.GetValues("id")[0]), 
     Name = doc.GetValues("name")[0] 
    }; 
}; 

IList<Product> results = searchService.SearchIndex(searcher, query, converter); 
2

मैं हाल ही में एक ऐसी ही आवश्यकता थी और एक IQueryable विस्तार विशेष रूप से लिखने के समाप्त हो गया माइक्रोसॉफ्ट पूरा टेक्स्ट सूचकांक का उपयोग, यहां IQueryableFreeTextExtensions

+3

लिंक टूटी हुई है। –

+2

टूटा लिंक। तुमने इसे दूर ले लिया। :(इसके अलावा यहाँ उल्लेख किया: http://effts.codeplex.com/discussions/554652 –

+1

इसे यहाँ मिले http: //www.balsamicsolutions।नेट/ब्लॉग/पोस्ट/2/पूर्ण-पाठ-खोज-इन-माइक्रोसॉफ्ट की इकाई-फ्रेमवर्क –

47

EF6 में पेश किया इंटरसेप्टर का उपयोग करते हुए अपने उपलब्ध के लिए, आप LINQ में पूर्ण पाठ खोज का प्रतीक है और फिर http://www.entityframework.info/Home/FullTextSearch में वर्णित के रूप dbcommand में इसे बदलना सकता है:

public class FtsInterceptor : IDbCommandInterceptor 
{ 
    private const string FullTextPrefix = "-FTSPREFIX-"; 

    public static string Fts(string search) 
    { 
     return string.Format("({0}{1})", FullTextPrefix, search); 
    } 

    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 
    { 
    } 

    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) 
    { 
    } 

    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) 
    { 
     RewriteFullTextQuery(command); 
    } 

    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) 
    { 
    } 

    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 
    { 
     RewriteFullTextQuery(command); 
    } 

    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) 
    { 
    } 

    public static void RewriteFullTextQuery(DbCommand cmd) 
    { 
     string text = cmd.CommandText; 
     for (int i = 0; i < cmd.Parameters.Count; i++) 
     { 
      DbParameter parameter = cmd.Parameters[i]; 
      if (parameter.DbType.In(DbType.String, DbType.AnsiString, DbType.StringFixedLength, DbType.AnsiStringFixedLength)) 
      { 
       if (parameter.Value == DBNull.Value) 
        continue; 
       var value = (string)parameter.Value; 
       if (value.IndexOf(FullTextPrefix) >= 0) 
       { 
        parameter.Size = 4096; 
        parameter.DbType = DbType.AnsiStringFixedLength; 
        value = value.Replace(FullTextPrefix, ""); // remove prefix we added n linq query 
        value = value.Substring(1, value.Length - 2); 
        // remove %% escaping by linq translator from string.Contains to sql LIKE 
        parameter.Value = value; 
        cmd.CommandText = Regex.Replace(text, 
         string.Format(
          @"\[(\w*)\].\[(\w*)\]\s*LIKE\s*@{0}\s?(?:ESCAPE N?'~')", 
          parameter.ParameterName), 
         string.Format(@"contains([$1].[$2], @{0})", 
            parameter.ParameterName)); 
        if (text == cmd.CommandText) 
         throw new Exception("FTS was not replaced on: " + text); 
        text = cmd.CommandText; 
       } 
      } 
     } 
    } 

} 
static class LanguageExtensions 
{ 
    public static bool In<T>(this T source, params T[] list) 
    { 
     return (list as IList<T>).Contains(source); 
    } 
} 

उदाहरण के लिए, यदि आप FTS-अनुक्रमित क्षेत्र NoteText साथ वर्ग नोट है:

public class Note 
{ 
    public int NoteId { get; set; } 
    public string NoteText { get; set; } 
} 

और एफई नक्शे के लिए यह

public class NoteMap : EntityTypeConfiguration<Note> 
{ 
    public NoteMap() 
    { 
     // Primary Key 
     HasKey(t => t.NoteId); 
    } 
} 

और इसके लिए संदर्भ:

public class MyContext : DbContext 
{ 
    static MyContext() 
    { 
     DbInterception.Add(new FtsInterceptor()); 
    } 

    public MyContext(string nameOrConnectionString) : base(nameOrConnectionString) 
    { 
    } 

    public DbSet<Note> Notes { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Configurations.Add(new NoteMap()); 
    } 
} 

आप हो सकता है एफटीएस क्वेरी के लिए काफी सरल वाक्यविन्यास:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var s = FtsInterceptor.Fts("john"); 

     using (var db = new MyContext("CONNSTRING")) 
     { 
      var q = db.Notes.Where(n => n.NoteText.Contains(s)); 
      var result = q.Take(10).ToList(); 
     } 
    } 
} 

कि उत्पन्न होगा एसक्यूएल

तरह
exec sp_executesql N'SELECT TOP (10) 
[Extent1].[NoteId] AS [NoteId], 
[Extent1].[NoteText] AS [NoteText] 
FROM [NS].[NOTES] AS [Extent1] 
WHERE contains([Extent1].[NoteText], @p__linq__0)',N'@p__linq__0 char(4096)',@p__linq__0='(john) 

कृपया ध्यान दें कि आप स्थानीय चर का उपयोग करना चाहिए और अभिव्यक्ति के अंदर की तरह

var q = db.Notes.Where(n => n.NoteText.Contains(FtsInterceptor.Fts("john"))); 
+0

'नोटमैप 'क्या है? –

+0

मैंने नमूना नोटमैप क्लास – Ben

+0

जोड़ा है धन्यवाद @ बेन, एहसास नहीं हुआ कि उस फैशन में ईएफ कॉन्फ़िगर किया जा सकता है। –

2

उदाहरण यहाँ http://www.entityframework.info/Home/FullTextSearch FTS आवरण स्थानांतरित नहीं कर सकते पूर्ण समाधान नहीं है। आपको यह समझने की आवश्यकता होगी कि पूर्ण पाठ खोज कैसे काम करती है। कल्पना करें कि आपके पास एक खोज क्षेत्र है और उपयोगकर्ता खोज को हिट करने के लिए 2 शब्द टाइप करता है। उपरोक्त कोड एक अपवाद फेंक देगा। तार्किक और या OR का उपयोग कर क्वेरी में इसे पास करने के लिए आपको पहले खोज वाक्यांश पर प्री-प्रोसेसिंग करने की आवश्यकता है।

var searchTerm = @"\"blah\" AND/OR \"blah2\" "; 

पूरा समाधान होगा::

उदाहरण के लिए आपके खोज वाक्यांश "blah blah2" है, तो आप में इस बदलने की आवश्यकता

value = Regex.Replace(value, @"\s+", " "); //replace multiplespaces 
        value = Regex.Replace(value, @"[^a-zA-Z0-9 -]", "").Trim();//remove non-alphanumeric characters and trim spaces 

        if (value.Any(Char.IsWhiteSpace)) 
        { 
         value = PreProcessSearchKey(value); 
        } 


public static string PreProcessSearchKey(string searchKey) 
    { 
     var splitedKeyWords = searchKey.Split(null); //split from whitespaces 

     // string[] addDoubleQuotes = new string[splitedKeyWords.Length]; 

     for (int j = 0; j < splitedKeyWords.Length; j++) 
     { 
      splitedKeyWords[j] = $"\"{splitedKeyWords[j]}\""; 
     } 

     return string.Join(" AND ", splitedKeyWords); 
    } 

इस तरीकों का उपयोग करता है और तर्क ऑपरेटर। आप एक तर्क के रूप कि गुजरती हैं और दोनों के लिए विधि AND या OR ऑपरेटर का उपयोग हो सकता है। जब कोई उपयोगकर्ता अल्फा न्यूमेरिक वर्ण में प्रवेश करती है और आप जगह में कोई सर्वर साइट मॉडल स्तर मान्यता है

आप पलायन करना होगा कोई भी-अक्षरांकीय अक्षर अन्यथा यह अपवाद फेंक होगा।

संबंधित मुद्दे