2016-11-19 6 views
1

Я использую Lucene.Net для выполнения поисковых запросов в должности в моих C# asp.net приложениях Это образец документ в моих индексах:lucene.net матча, если условие поиска не имеет места

var doc = new Document(); 
var title = new Field("Title", "the album hardwired to self-destruct released", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS); 
title.Boost = 5; 
doc.Add(title); 
var ns_title = new Field("NoSpace_Title", "thealbumhardwiredtoselfdesctructreleased", Field.Store.NO, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS); 
ns_title.Boost = 5; 
doc.Add(ns_title); 
doc.Add(new Field("Body", "the body text of the post", Field.Store.YES, Field.Index.ANALYZED, Field.TermVector.WITH_POSITIONS_OFFSETS)); 
doc.Add(new Field("Id", "1", Field.Store.YES, Field.Index.NOT_ANALYZED)); 
writer.AddDocument(doc); 

Проблема:
если я ищу self или destruct или self destruct Я получаю удар.
если я ищу selfdestruct Я не получаю удар.

Метод поиска:

var searchWords = s.Split(' ').ToList(); 
var directory = GetDirectory(); 
var reader = IndexReader.Open(directory, true); 
var searcher = new IndexSearcher(reader); 
var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30); 
var parser = new MultiFieldQueryParser(Lucene.Net.Util.Version.LUCENE_30, "Title,NoSpace_Title,Body".Split(','), analyzer); 
var booleanQuery = new BooleanQuery(); 

// Title:selfdestruct*NoSpace_Title:selfdestruct*Body:selfdestruct* 
s = string.Join(" ", searchWords.Select(x => x.Contains("*") ? x : x + "*")); 
Query query = parser.Parse(QueryParser.Escape(s)); 
query.Boost = 5; 
booleanQuery.Add(query, Occur.SHOULD); 

// Title:*selfdestruct*,NoSpace_Title:*selfdestruct*,Body:*selfdestruct* 
// (I suppose this should work and get hit but it doesn't) 
s = "*" + string.Join("", searchWords) + "*"; 
Query query2 = parser.Parse(QueryParser.Escape(s)); 
query2.Boost = 3; 
booleanQuery.Add(query2, Occur.SHOULD); 

// Title:selfdestruct~0.85 (fuzzy search) 
s = string.Join(" ", searchWords.Select(x => x.Contains("~") ? x : x + "~0.85")); 
Query query3 = parser.Parse(QueryParser.Escape(s)); 
booleanQuery.Add(query3, Occur.SHOULD); 

var collector = TopScoreDocCollector.Create(1000, true); 
searcher.Search(booleanQuery, collector); 
var hits = collector.TopDocs().ScoreDocs; 
var docs = hits.Select(x => searcher.Doc(x.Doc)).ToList(); 
+0

что анализатор используется при индексировании? – root545

+0

@ root545 Я использую то же самое при поиске «StandardAnalyzer» – mhesabi

ответ

2

Вы можете поддержать это, добавив ShingleFilter в ваш анализатор.

ShingleFilter объединит соседние маркеры в одиночные токены, чтобы облегчить их поиск без пробелов. По умолчанию он также выводит Unigrams (то есть он также будет поддерживать одиночные токены). Итак, когда вы индексируете «самоуничтожение», он будет индексировать маркеры «я», «разрушить» и «самоуничтожить».

Самый простой способ сделать это без создания собственного анализатора, заключается в использовании ShingleAnalyzerWrapper:

var analyzer = new ShingleAnalyzerWrapper(
     new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30), 
     2); 
+0

Я читаю документы ShingleFilter.cs, в нем говорится: Например, предложение «пожалуйста, разделите это предложение на черепицу», может быть обозначено в черепицу «пожалуйста, разделите», «разделите это», «это предложение», «предложение в» и «на черепицу». Мне кажется, что мне нужно что-то подобное, я имею в виду то, что связывает слова вместе. например: 'happyivide',' divethis', 'thiscentence',' sentenceinto' и 'intoshingles' – mhesabi

+1

Я использовал' ShingleFilter', как предположил femtoRgon, с одной незначительной модификацией, которая меняла 'TOKEN_SEPARATOR =" "' на 'string. empty'. отмеченный как ответ. – mhesabi