2011-01-14 6 views
3

Ich habe eine Suchfunktion mit Lucene.Net implementiert. Der Index enthält britische akademische Qualifikationen, einschließlich "A Level".Lucene.Net - Wie behandelt man eine durch Leerzeichen getrennte Phrase als einzelnes Token?

Ich möchte, dass die Benutzer in der Lage sind, mit dem Ausdruck "A Level" zu suchen, aber mit dem Standard Analyzer wird das "A" als Stoppwort entfernt und daher nur "Level" indexiert/gesucht .

Was ist meine beste Option, um dies zu umgehen? Ich schätze, ich muss irgendwie "A Level" zu "A-Level" oder ähnlichem durch Erstellen eines benutzerdefinierten Analysators tokenisieren.

Ist dies der beste Ansatz?

Edits:

Beachten Sie, dass will ich möchte nicht die ganze Suche eine Phrase Abfrage sein. d. h. in meinem Suchfeld möchte ich, dass der Benutzer < "A Level" AND Englisch Maths Physics eingeben kann und dies würde jedes mit "A Level" und entweder Englisch Mathe oder Physik zurückgeben. Frage aktualisiert, um dies zu reflektieren.

Ich würde speziell wie die Verwendung von ‚A‘ zu halten als ein Stoppwort in allen Fällen appart von ‚Stufe A‘

Die Phrase ‚eine Ebene‘ ist nicht in einem eigenen spezifischen Bereich, ist es in ein freies Textfeld, das die Phrase enthalten kann.

Antwort

3

Verwendung PhraseQuery -, die mit jedem anderen durch Boolesche Konstruktion kombiniert werden können

EDITED

Sie brauchen nicht ganze Phrase zu suchen. Für Sie ist es sieht aus wie folgt probieren (sorry ist es Pseudo-Code, da ich es nicht testen können jetzt) ​​

BooleanQuery rootQuery = new ... 
PhraseQuery q1 = new PhraseQuery("A Level"); 
TermQuery q2 = new TermQuery("English"); 
TermQuery q3 = new TermQuery("Maths"); 
TermQuery q4 = new TermQuery("Physics"); 
rootQuery.Add(q1, BooleanClause.Occur.SHOULD); //or MUST - depends on you 
rootQuery.Add(q2, BooleanClause.Occur.SHOULD); 
rootQuery.Add(q3, BooleanClause.Occur.SHOULD); 
rootQuery.Add(q4, BooleanClause.Occur.SHOULD); 
+0

Aber ich will nicht wollen, die ganze Suche eine Phrase Abfrage sein. d. h. in meinem Suchfeld möchte ich, dass der Benutzer in der Lage ist, <"A Level" AND English Maths Physics> einzugeben, und dies würde jedes mit "A Level" und entweder Englisch Mathe oder Physik zurückgeben. Frage aktualisiert, um dies zu reflektieren. –

+0

@Gareth D - siehe meine Bearbeitung – Dewfy

+2

@Dewfy - Aber bleibt das Problem immer noch? d. h., das "A" in "A Level" wird vom Standardanalysator als Stoppwort entfernt, was dazu führt, dass die Phrasenabfrage alle Instanzen von "level" anstelle von "A Level" zurückgibt. –

1

Wie haben Sie den Inhalt indiziert - welche Analysator Sie verwendet haben? Wenn Sie StandardAnalyzer verwenden, dann können Sie die Stoppwörter im Konstruktor angeben (können Sie eine leere Liste verwenden):

Analyzer analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29, new Hashtable()); 

So Index der contenxt mit oberen Analysator. Danach können Sie den Inhalt abfragen können die QueryParser mit (unbedingt den Analysator oben verwenden) oder Sie die Abfrage manuell Konstrukt kann:

 // Phrase query 
     PhraseQuery phraseQuery = new PhraseQuery(); 
     phraseQuery.Add(new Term("MyField", "A")); 
     phraseQuery.Add(new Term("MyField", "Level")); 

     // Or query 
     BooleanQuery orQuery = new BooleanQuery(); 
     orQuery.Add(new BooleanClause(new TermQuery(new Term("MyField", "English")), BooleanClause.Occur.SHOULD)); 
     orQuery.Add(new BooleanClause(new TermQuery(new Term("MyField", "Maths")), BooleanClause.Occur.SHOULD)); 
     orQuery.Add(new BooleanClause(new TermQuery(new Term("MyField", "Physics")), BooleanClause.Occur.SHOULD)); 

     // Main query 
     BooleanQuery query = new BooleanQuery(); 
     query.Add(phraseQuery, BooleanClause.Occur.MUST); 
     query.Add(orQuery, BooleanClause.Occur.MUST); 

Bye

+0

Ich verwende den StandardAnalyzer. Ich würde speziell gerne die Verwendung von "A" als Stop-Wort in allen Fällen von "A Level" behalten, also habe ich Angst, dass Ihre Lösung das Problem nicht anspricht. Ich werde die Frage aktualisieren, um dies zu verdeutlichen. –

+0

Warum nicht? Erstellen Sie dann zwei Analysatoren (einer mit "A" als Stoppwort und einer, bei dem "A" kein Stoppwort ist) und wählen Sie zwischen Analysatoren entsprechend Ihren Geschäftsanforderungen (während der Indizierung und Suche). Sie können auch den Analysator pro Feld einstellen (mit PerFieldAnalyzerWrapper). Oder schließlich, wählen Sie einen anderen Analysator ... – rrejc

+0

Ich denke, er will die Stoppwörter nicht basierend auf dem Feld, sondern basierend auf den Begriffen im Feld zu wechseln. Daher funktioniert 'PerFieldAnalyzerWrapper' nicht. – Xodarap

1

Die KeywordAnalyzer keine Saiten tokenize, im Gegensatz zu den StandardAnalyzer. Ich gehe davon aus, dass es eine. NET-Implementierung von diesem - possibly this?

Ich werde oft etwas tun (Vorsicht, Java folgt):

private ReusableAnalyzer getReusableAnalyzer(String fieldName, Reader reader) { 
    boolean phrase = treatAsPhrase(fieldName); 
    ReusableAnalyzer ra = new ReusableAnalyzer(); 
    TokenStream result = phrase ? new KeywordTokenizer(reader) : new StandardTokenizer(version, reader); 

wobei ich die Feldnamen, ob zu bestimmen, verwenden Sie den Text als „Ausdruck“ oder nicht zu behandeln.

+0

Ich möchte das Feld als Token freigeben, da es auch anderen Text enthält. Der Ausdruck "A Level" ist nicht in seinem eigenen spezifischen Bereich, es ist in einem freien Textfeld, das den Ausdruck einschließen kann. Ich habe die Frage aktualisiert, um dies zu verdeutlichen. –

+0

Sie könnten eine benutzerdefinierte Implementierung von StopFilter erstellen - kopieren Sie das Original. Wenn Sie auf das Stoppwort "A" und dann auf das nächste Token "schauen", wenn es "Level" ist, dann wenden Sie den Stopp nicht an. – Joel

2

Ich denke nicht, dass dies derzeit mit Lucene machbar ist. Ich habe einen halbfertigen Stecker in dem dies funktioniert, Sie können es sehen here. Es werden nicht die Attribute "Position" und "Offset" gesetzt, was bedeutet, dass die Phrasensuche nicht korrekt funktioniert, aber hoffentlich sollte es Ihnen einen Vorsprung verschaffen.

+0

Das sieht mir sehr ähnlich. Ich werde damit spielen und versuchen, dass die Position und die Offset-Attribute funktionieren. –

+0

@Gareth D: Wenn Sie es funktioniert, posten Sie Ihren Code, damit ich es stehlen kann :-) – Xodarap

+0

Warum nicht einfach einen benutzerdefinierten StopFilter erstellen? – Joel

1

Dies ist in Lucene mit ein wenig mehr Anpassung machbar.

1) Erstellen Sie ein separates Feld, in dem Stoppwörter beibehalten werden. Sie müssen Ihren eigenen Analysator erstellen, der von StandardAnalyzer erbt, aber keine Stoppwörter im Basiskonstruktor angibt.

public class PreserveStopWordsAnalyzer : StandardAnalyzer 
{ 
    public PreserveStopWordsAnalyzer() : base(Version.LUCENE_29, new Hashtable()) 
    {} 
} 

2) Gesuchte Begriffe im Feld "Stoppwort" suchen. Zum Beispiel:

+RegularField:English +StopWordField:"A Level"