2013-03-08 13 views
7

Ich habe ein Suchfeld, das eine Suche im Titelfeld basierend auf der angegebenen Eingabe durchführt, so dass der Benutzer alle verfügbaren Titel beginnend mit dem Text empfohlen hat Lucene und Hibernate Search. Es funktioniert gut, bis Platz eingegeben wird. Dann verschwindet das Ergebnis. Zum Beispiel möchte ich "Learning H" mir "Learning Hibernate" als Ergebnis geben. Dies geschieht jedoch nicht. Könntest du mir bitte raten, was ich hier stattdessen verwenden soll.Suche nach Feldern mit Wildcard und Leerzeichen in Hibernate Search

Query Builder:

QueryBuilder qBuilder = fullTextSession.getSearchFactory() 
     .buildQueryBuilder().forEntity(LearningGoal.class).get(); 
    Query query = qBuilder.keyword().wildcard().onField("title") 
     .matching(searchString + "*").createQuery(); 

    BooleanQuery bQuery = new BooleanQuery(); 
    bQuery.add(query, BooleanClause.Occur.MUST); 
    for (LearningGoal exGoal : existingGoals) { 
    Term omittedTerm = new Term("id", String.valueOf(exGoal.getId())); 
    bQuery.add(new TermQuery(omittedTerm), BooleanClause.Occur.MUST_NOT); 
    } 
    @SuppressWarnings("unused") 
    org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(
     query, LearningGoal.class); 

Hibernate Klasse:

@AnalyzerDef(name = "searchtokenanalyzer",tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class), 
filters = { 
    @TokenFilterDef(factory = StandardFilterFactory.class), 
    @TokenFilterDef(factory = LowerCaseFilterFactory.class), 
    @TokenFilterDef(factory = StopFilterFactory.class,params = { 
     @Parameter(name = "ignoreCase", value = "true") }) }) 
     @Analyzer(definition = "searchtokenanalyzer") 
public class LearningGoal extends Node { 
+0

Drucken der Abfrage zur Ausgabe wird definitiv helfen .. – phani

+0

Es ist nützlich, in der Tat, aber half mir nicht zu verstehen, warum ich nicht Resultate haben. Ich habe zum Beispiel ein Lernziel, dessen Titel "Lernwahrscheinlichkeitstheorie" lautet. Die Ausgabe von zwei Abfragen ist ** bQuery: + title: learning p * hibQuery: FullTextQueryImpl (Titel: learning p *) ** für die Eingabezeichenfolge "learning p". Es findet Wert, wenn der Eingabe-String "lernt". –

+0

Ich habe auch versucht, den Raum mit? Zu ersetzen, aber es gab kein Ergebnis. –

Antwort

7

ich Abhilfe für dieses Problem gefunden. Die Idee besteht darin, die Eingabezeichenfolge zu symbolisieren und Stoppwörter zu entfernen. Für das letzte Token habe ich eine Abfrage mit Keyword-Platzhalter erstellt, und für alle vorherigen Wörter habe ich eine TermQuery erstellt. Hier ist der vollständige Code

BooleanQuery bQuery = new BooleanQuery(); 
    Session session = persistence.currentManager(); 
    FullTextSession fullTextSession = Search.getFullTextSession(session); 
    Analyzer analyzer = fullTextSession.getSearchFactory().getAnalyzer("searchtokenanalyzer"); 
    QueryParser parser = new QueryParser(Version.LUCENE_35, "title", analyzer); 
    String[] tokenized=null; 
    try { 
    Query query= parser.parse(searchString); 
    String cleanedText=query.toString("title"); 
    tokenized = cleanedText.split("\\s"); 

    } catch (ParseException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

    QueryBuilder qBuilder = fullTextSession.getSearchFactory() 
      .buildQueryBuilder().forEntity(LearningGoal.class).get(); 
    for(int i=0;i<tokenized.length;i++){ 
     if(i==(tokenized.length-1)){ 
      Query query = qBuilder.keyword().wildcard().onField("title") 
        .matching(tokenized[i] + "*").createQuery(); 
       bQuery.add(query, BooleanClause.Occur.MUST); 
     }else{ 
      Term exactTerm = new Term("title", tokenized[i]); 
      bQuery.add(new TermQuery(exactTerm), BooleanClause.Occur.MUST); 
     } 
    } 
     for (LearningGoal exGoal : existingGoals) { 
     Term omittedTerm = new Term("id", String.valueOf(exGoal.getId())); 
     bQuery.add(new TermQuery(omittedTerm), BooleanClause.Occur.MUST_NOT); 
    } 
    org.hibernate.Query hibQuery = fullTextSession.createFullTextQuery(
      bQuery, LearningGoal.class); 
+0

Können Sie bitte weitere Erklärungen hinzufügen? Ich verstehe es nicht so weit. Warum verwenden Sie eine andere Abfrage für das letzte Token? Und modifiziere bitte dein Beispiel, dass es klar genug ist. Warum sind 'existingGoals' überhaupt notwendig? – alexander

+0

Sagen wir, wir haben den Titel "Hibernate Search". Wenn der Benutzer "Hibernate Se" eingegeben hat, wird der erste Token "Hibernate" sein und wir nehmen den genauen Begriff, da wir wissen, dass der Benutzer das ganze Wort eingegeben hat, das er wollte, da er bereits anfängt, ein anderes Wort einzugeben. Für das zweite Wort "se", da wir wissen, dass der Benutzer die Eingabe nicht beendet hat, verwenden wir Wildcard, um sicher zu sein, dass er nicht in der Mitte des Wortes ist, was genau hier der Fall ist. Die Abfrage für das letzte Wort deckt also alles ab, was mit "se" beginnt, und alle Wörter, die zuvor eingegeben wurden, werden als exakte Begriffe verwendet. –

+0

Für die zweite Frage (existingGoals) ist dies etwas sehr Spezifisches für mein Anwendungsfall-Szenario.Ich wollte diejenigen Titel von den Suchergebnissen ausschließen, die der Benutzer bereits zu seiner Liste ausgewählter Objekte hinzugefügt hat, so dass diese vorhandenen Titel tatsächlich Titel sind, die ignoriert werden sollten und in Ihrem Fall möglicherweise nicht benötigt werden. –

-1

SQL verwendet verschiedene Platzhalter als jedes Endgerät. In SQL '%' ersetzt null oder mehr Vorkommen eines beliebigen Zeichens (im Terminal verwenden Sie stattdessen '*'), und der Unterstrich '_' ersetzt genau ein Zeichen (im Terminal verwenden Sie stattdessen '?'). Hibernate übersetzt die Platzhalterzeichen nicht.

So in der zweiten Zeile haben Sie matching(searchString + "*") mit ersetzen

matching(searchString + "%") 
+0

Sind Sie sich sicher? Danach gibt es mir keine Ergebnisse, auch ohne Leerzeichen in searchString. Zuvor (mit *) hatte ich einige Ergebnisse, bis der Platz in searchString entstanden ist. Ich weiß nicht, wie HibernateSearch mit SQL verwandt ist. Es führt eine Suche über die Lucene-Indizes durch, die nicht in der Datenbank gespeichert sind, so dass ich nicht sicher bin, ob es die SQL-Syntax verwendet. –

+0

Für Hibernate + SQL bin ich sicher, aber ich benutze nicht Lucene, und ich weiß nicht, was die Lucene-Engine mit der Eingabe macht. – Johanna

+0

Ich verstehe. Sie dachten, dass dies eine regelmäßige Datenbankabfrage ist. Hibernate Search verwendet Lucene-Abfragen jedoch, um über Lucene-Indizes zu suchen, und seine Syntax ist nicht identisch mit SQL http://www.lucenetutorial.com/lucene-query-syntax.html –