2013-03-08 9 views
7

Ho una casella di ricerca che esegue una ricerca sul campo titolo in base all'input dato, quindi l'utente ha raccomandato tutti i titoli disponibili a partire dal testo inserito. È basato su Lucene e Hibernate Search. Funziona bene finché non viene inserito lo spazio. Quindi il risultato sparisce. Ad esempio, voglio che "Learning H" mi dia "Learning Hibernate" come risultato. Tuttavia, questo non succede. potresti per favore consigliarmi cosa dovrei usare qui invece.Come cercare i campi con caratteri jolly e spazi in Hibernate Cerca

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 classe:

@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

stampa la query per l'output sarà sicuramente aiutare .. – phani

+0

E 'utile in effetti, ma non mi ha aiutato a capire il motivo per cui non ho risultati. Ad esempio, ho un obiettivo di apprendimento il cui titolo è "Teoria della teoria dell'apprendimento". L'output di due query è ** bQuery: + title: learning p * hibQuery: FullTextQueryImpl (titolo: learning p *) ** per la stringa di input "learning p". Trova valore se la stringa di input è "apprendimento". –

+0

Ho anche provato a sostituire lo spazio con?, Ma non ha dato risultati. –

risposta

7

ho trovato soluzione per questo problema. L'idea è di tokenizzare la stringa di input e rimuovere le parole di stop. Per l'ultimo token ho creato una query utilizzando il carattere jolly della parola chiave e per tutte le parole precedenti ho creato un TermQuery. Ecco il codice completo

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

Puoi aggiungere ulteriori spiegazioni? Non capisco così lontano. Perché stai utilizzando una query diversa per l'ultimo token? E per favore modifica il tuo esempio, che è abbastanza chiaro. Perché i 'esistentiGoals 'sono necessari? – alexander

+0

Diciamo che abbiamo il titolo "Hibernate Search". Quando l'utente ha inserito "Hibernate Se", il primo token sarà "Hibernate" e stiamo prendendo il termine esatto poiché sappiamo che l'utente ha inserito l'intera parola che voleva, poiché ha già iniziato a digitare un'altra parola. Per la seconda parola "se", poiché sappiamo che l'utente potrebbe non aver finito di digitare, stiamo usando il jolly per essere sicuri che non sia nel mezzo della parola, che è esattamente il caso qui. Quindi la query dell'ultima parola coprirà tutto a partire da "se" e tutte le parole inserite dall'utente verranno utilizzate come termini esatti. –

+0

Per la seconda domanda (esistentiGoals), questo è qualcosa di molto specifico per il mio caso di utilizzo.Volevo escludere dai risultati di ricerca quei titoli che l'utente ha già aggiunto al suo elenco di elementi selezionati, quindi questi esistentiGoals sono in realtà titoli che dovrebbero essere ignorati e potresti non averne bisogno nel tuo caso. –

-1

SQL utilizza diversi caratteri jolly di ogni terminale. In SQL '%' sostituisce zero o più occorrenze di qualsiasi carattere (nel terminale si utilizza invece '*') e il carattere di sottolineatura '_' sostituisce esattamente un carattere (nel terminale si utilizza invece '?'). Hibernate non traduce i caratteri jolly.

Così nella seconda riga è necessario sostituire matching(searchString + "*") con

matching(searchString + "%") 
+0

Sei sicuro di questo? Dopo questo non mi dà alcun risultato, anche senza spazi in searchString. Precedentemente (con *) ho avuto alcuni risultati fino a quando non è sorto lo spazio in searchString. Non so come questo HibernateSearch sia correlato a SQL? Esegue la ricerca sugli indici di Lucene che non sono memorizzati nel database, quindi non sono sicuro se utilizza la sintassi SQL. –

+0

Per Hibernate + SQL sono sicuro, ma non uso Lucene e non so cosa stia facendo il motore Lucene con l'input. – Johanna

+0

Capisco. Hai pensato che questa è una normale query del database. Tuttavia, Hibernate Search utilizza le query di Lucene per cercare gli indici di lucene e la sua sintassi non è la stessa di SQL http://www.lucenetutorial.com/lucene-query-syntax.html –

Problemi correlati