2012-01-25 2 views
4

Я использую этот код индекса:Lucene .NET

public void IndexEmployees(IEnumerable<Employee> employees) 
{ 
    var indexPath = GetIndexPath(); 
    var directory = FSDirectory.Open(indexPath); 

    var indexWriter = new IndexWriter(directory, new StandardAnalyzer(Version.LUCENE_29), true, IndexWriter.MaxFieldLength.UNLIMITED); 

    foreach (var employee in employees) 
    { 
     var document = new Document(); 
     document.Add(new Field("EmployeeId", employee.EmployeeId.ToString(), Field.Store.YES, Field.Index.NO, Field.TermVector.NO)); 
     document.Add(new Field("Name", employee.FirstName + " " + employee.LastName, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO)); 
     document.Add(new Field("OfficeName", employee.OfficeName, Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO)); 
     document.Add(new Field("CompetenceRatings", string.Join(" ", employee.CompetenceRatings.Select(cr => cr.Name)), Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.NO)); 

     indexWriter.AddDocument(document); 
    } 

    indexWriter.Optimize(); 
    indexWriter.Close(); 

    var indexReader = IndexReader.Open(directory, true); 
    var spell = new SpellChecker.Net.Search.Spell.SpellChecker(directory); 
    spell.ClearIndex(); 

    spell.IndexDictionary(new LuceneDictionary(indexReader, "Name")); 
    spell.IndexDictionary(new LuceneDictionary(indexReader, "OfficeName")); 
    spell.IndexDictionary(new LuceneDictionary(indexReader, "CompetenceRatings")); 
} 

public DirectoryInfo GetIndexPath() 
{ 
    return new DirectoryInfo(HttpContext.Current.Server.MapPath("/App_Data/EmployeeIndex/")); 
} 

И этот код, чтобы найти результаты (а также предложения):

public SearchResult Search(DirectoryInfo indexPath, string[] searchFields, string searchQuery) 
{ 
    var directory = FSDirectory.Open(indexPath); 

    var standardAnalyzer = new StandardAnalyzer(Version.LUCENE_29); 

    var indexReader = IndexReader.Open(directory, true); 
    var indexSearcher = new IndexSearcher(indexReader); 

    var parser = new MultiFieldQueryParser(Version.LUCENE_29, searchFields, standardAnalyzer); 
    //parser.SetDefaultOperator(QueryParser.Operator.OR); 
    var query = parser.Parse(searchQuery); 

    var hits = indexSearcher.Search(query, null, 5000); 

    return new SearchResult 
       { 
        Suggestions = FindSuggestions(indexPath, searchQuery), 
        LuceneDocuments = hits 
         .scoreDocs 
         .Select(scoreDoc => indexSearcher.Doc(scoreDoc.doc)) 
         .ToArray() 
       }; 
} 

public string[] FindSuggestions(DirectoryInfo indexPath, string searchQuery) 
{ 
    var directory = FSDirectory.Open(indexPath); 

    var spell = new SpellChecker.Net.Search.Spell.SpellChecker(directory); 

    var similarWords = spell.SuggestSimilar(searchQuery, 20); 

    return similarWords; 
} 

var searchResult = Search(GetIndexPath(), new[] { "Name", "OfficeName", "CompetenceRatings" }, "admin*"); 

Простые запросы, как: администратор или admin * не дает мне никаких результатов. Я знаю, что есть сотрудник с таким именем. Я хочу найти Джеймса Джеймсона, если буду искать Джеймса.

Спасибо!

+0

Как мы должны знать, как вы ищите, пока не покажете нам код, в котором вы вызываете Search()? В частности, какие параметры вы передаете. – jishi

+0

jishi: Извините, я включил вызов метода поиска в вопрос: var searchResult = Search (GetIndexPath(), new [] {"Name", "OfficeName", "CompetenceRatings"}, "admin *") ; – Martin

ответ

4

Первое, что нужно. Вы должны зафиксировать изменения индекса.

indexWriter.Optimize(); 
indexWriter.Commit(); //Add This 
indexWriter.Close(); 

Edit # 2 Кроме того, держать его просто, пока вы не получите то, что работает.

Прокомментировать этот материал.

//var indexReader = IndexReader.Open(directory, true); 
//var spell = new SpellChecker.Net.Search.Spell.SpellChecker(directory); 
//spell.ClearIndex(); 

//spell.IndexDictionary(new LuceneDictionary(indexReader, "Name")); 
//spell.IndexDictionary(new LuceneDictionary(indexReader, "OfficeName")); 
//spell.IndexDictionary(new LuceneDictionary(indexReader, "CompetenceRatings")); 

Edit # 3

поля вы ищете, вероятно, не будет часто меняться. Я бы включил их в вашу функцию поиска.

string[] fields = new string[] { "Name", "OfficeName", "CompetenceRatings" }; 

Самая главная причина, я полагаю, в том, что поля чувствительны к регистру, а иногда вы не получите никаких результатов, и это потому, что вы будете искать в поле «Name» (который не существует) вместо «Name» поле. Легче обнаружить ошибку таким образом.

+0

Хорошо пятнистый. Можно предположить, что у него был рабочий индекс, чтобы начать с ... – jishi

+0

Это такой тип «ошибки», который заставляет человека ударить головой о стол. – SharpBarb

+0

Отлично, теперь я получаю результаты. Я немного поработаю и посмотрю, работает ли он так, как ожидалось. Благодаря! – Martin

0

Этот метод Parse() наследуется. Вы пытались использовать статические методы, возвращающие объект Query?

Parse(Version matchVersion, String[] queries, String[] fields, Analyzer analyzer) 
+0

Я обновил код для этого: вар запрос = MultiFieldQueryParser.Parse (Version.LUCENE_29, Enumerable.Repeat (SearchQuery, searchFields.Length) .ToArray(), searchFields, standardAnalyzer); Я до сих пор не получаю никаких результатов. – Martin

+0

Затем начните с проверки вашего индекса с помощью Люка или его эквивалента и убедитесь, что ваш индекс действительно возвращает какой-либо результат для любого запроса. – jishi

1

В моей (ограниченный) опыт работы с Lucene, я обнаружил, что вы должны создать свой собственный запрос, чтобы получить «Google», как поведение. Вот что я делаю, YMMV, но он генерирует ожидаемые результаты в моем приложении. Основная идея заключается в том, что вы комбинируете термин запрос (точное соответствие), префиксный запрос (все, что начинается с термина), и нечеткий запрос для каждого термина в строке поиска. Код ниже не компилируется, но дает вам идею

Query GetQuery(string querystring) 
{ 

    Search.Search.BooleanQuery query = new Search.Search.BooleanQuery(); 

    Search.Analysis.TokenStream tk = StandardAnalyzerInstance.TokenStream(null, new StringReader(querystring)); 
    Search.Analysis.Tokenattributes.TermAttribute ta = tk.GetAttribute(typeof(Search.Analysis.Tokenattributes.TermAttribute)) as Search.Analysis.Tokenattributes.TermAttribute; 

    while (tk.IncrementToken()) 
    { 
     string term = ta.Term(); 
     Search.Search.BooleanQuery bq = new Search.Search.BooleanQuery(); 
     bq.Add(new Search.Search.TermQuery(new Search.Index.Term("fieldToQuery", term)), Search.Search.BooleanClause.Occur.SHOULD); 
     bq.Add(new Search.Search.PrefixQuery(new Search.Index.Term("fieldToQuery", term)), Search.Search.BooleanClause.Occur.SHOULD); 
     bq.Add(new Search.Search.FuzzyQuery(new Search.Index.Term("fieldToQuery", term)), Search.Search.BooleanClause.Occur.SHOULD); 
     query.Add(bq, Search.Search.BooleanClause.Occur.MUST); 
    } 

    return query; 
} 
+0

Я переписал ваш код: http://pastebin.com/Kt4VqAtA (слишком долго, чтобы вставить здесь). Однако это не дает мне никаких результатов. Линия, вызывающая метод, выглядит так: var query = BuildQuery (standardAnalyzer, searchFields, searchQuery); и заменяет var parser = new MultiFieldQueryParser (Version.LUCENE_29, searchFields, standardAnalyzer); var query = parser.Parse (searchQuery); часть из приведенного выше примера. – Martin

+0

Попробуйте следующее: http://pastebin.com/M2cpHrQe.Единственное, что я могу думать, чтобы изменить, зависит от нашего приложения - при добавлении подзапросов я использую MUST, то есть какая-то форма каждого термина должна быть в каждом поле. Это может быть слишком жестким для вашего приложения, и в этом случае вы можете изменить запрос как менее строгий. –

+0

Джо, спасибо за ваше предложение. Я все еще не могу получить никаких результатов. – Martin

Смежные вопросы