2016-11-19 3 views
1

J'utilise lucene.net pour effectuer des postes dans searchs mon application C# asp.net, Ceci est un exemple de document dans mes index:match de lucene.net si terme de recherche n'a pas d'espace

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); 

Problème:
si je recherche self ou destruct ou self destruct Je me suis fait frapper.
si je recherche selfdestruct Je ne reçois pas un coup.

La méthode de recherche:

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

ce qui est l'analyseur que vous utilisez lors de l'indexation? – root545

+0

@ root545 J'utilise la même chose quand je cherche, 'StandardAnalyzer' – mhesabi

Répondre

2

Vous pouvez soutenir en ajoutant un ShingleFilter dans votre analyseur. ShingleFilter combine des jetons adjacents en jetons simples pour faciliter leur recherche sans espace. Par défaut, il affichera également Unigrams (c'est-à-dire qu'il conservera également les jetons uniques). Ainsi, lorsque vous indexez "l'autodestruction", il indexe les jetons "self", "destruct" et "selfdestruct".

Un moyen facile de le faire sans créer votre propre analyseur personnalisé, est d'utiliser ShingleAnalyzerWrapper:

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

Je lis les documents de ShingleFilter.cs, il est dit: Par exemple, la phrase" s'il vous plaît diviser cette phrase en bardeaux "pourrait être symbolisée en bardeaux" s'il vous plaît diviser ", "diviser ceci", "cette phrase", "phrase en", et "en bardeaux". Je pense que j'ai besoin de quelque chose de similaire, je veux dire quelque chose qui attache des mots ensemble. par exemple: '' gladivide'', 'dividethis',' thissentence', 'phraseinto', et' intoshingles' – mhesabi

+1

J'ai utilisé 'ShingleFilter' comme suggéré par femtoRgon avec une modification mineure qui changeait' TOKEN_SEPARATOR = "" 'en' chaîne. vide'. marqué comme réponse. – mhesabi