2013-03-08 10 views
7

Mam pole wyszukiwania, które wykonuje wyszukiwanie w polu tytułu na podstawie danych wejściowych, więc użytkownik polecił wszystkie dostępne tytuły rozpoczynające się od wstawionego tekstu. Opiera się na Lucene i Hibernate Search. Działa dobrze, dopóki nie zostanie wprowadzone miejsce. Wtedy wynik zniknie. Na przykład chcę, aby "Learning H" dało mi "Learning Hibernate" w wyniku. Jednak tak się nie dzieje. czy mógłbyś mi doradzić, czego tu użyć?Jak wyszukiwać pola za pomocą symboli wieloznacznych i spacji w wyszukiwaniu w trybie hibernacji

Konstruktor zapytań:

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

hibernacji klasy:

@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

drukowanie zapytanie do wyjścia z pewnością pomogą Ci .. – phani

+0

To jest rzeczywiście przydatne, ale nie pomogło mi zrozumieć, dlaczego nie mam wyników. Na przykład mam cel naukowy, którego tytuł brzmi "Nauka teorii prawdopodobieństwa". Wynik dwóch zapytań to ** bQuery: + title: learning p * hibQuery: FullTextQueryImpl (title: learning p *) ** dla ciągu wejściowego "learning p". Znajduje wartość, jeśli ciąg wejściowy to "uczenie się". –

+0

Próbowałem również zastąpić spację przez?, Ale nie dało wyniku. –

Odpowiedz

7

znalazłem obejście tego problemu. Chodzi o tokenowanie łańcucha wejściowego i usuwanie słów zatrzymania. Dla ostatniego tokenu utworzyłem zapytanie za pomocą wieloznacznego słowa kluczowego, a dla wszystkich poprzednich słów stworzyłem termQuery. Oto pełny kod

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

Czy możesz dodać więcej wyjaśnień? Nie rozumiem tego tak daleko. Dlaczego używasz innego zapytania do ostatniego tokenu? I zmodyfikuj swój przykład, że jest wystarczająco jasny. Dlaczego "istniejąceGoals" są w ogóle konieczne? – alexander

+0

Załóżmy, że mamy tytuł "Wyszukiwanie Hibernacji". Gdy użytkownik wprowadzi "Hibernacja Se", pierwszym tokenem będzie "Hibernacja" i przyjmujemy dokładny termin, ponieważ wiemy, że użytkownik wpisał całe słowo, jakie chciał, ponieważ już zaczął wpisywać inne słowo. W przypadku drugiego słowa "se", ponieważ wiemy, że użytkownik nie skończył pisać, używamy symbolu wieloznacznego, aby upewnić się, że nie znajduje się on w środku wyrazu, co ma dokładnie miejsce w tym przypadku. Tak więc zapytanie o ostatnie słowo obejmie wszystko zaczynające się od "se", a wszystkie wyrazy wprowadzone wcześniej przez użytkownika będą używane jako dokładne terminy. –

+0

Dla drugiego pytania (existingGoals), jest to bardzo specyficzne dla mojego scenariusza użycia.Chciałem wykluczyć z wyników wyszukiwania te tytuły, które użytkownik już dodał do swojej listy wybranych elementów, więc te istniejąceGoals to tak naprawdę tytuły, które powinny zostać zignorowane i może nie być potrzebne w twoim przypadku. –

-1

SQL wykorzystuje różne kwantyfikatorów niż jakikolwiek terminal. W SQL '%' zastępuje zero lub więcej wystąpień dowolnego znaku (w terminalu zamiast niego używa się '*'), a podkreślenie '_' zastępuje dokładnie jeden znak (w terminalu zamiast niego używa się '?'). Hibernacja nie tłumaczy symboli wieloznacznych.

Więc w drugim wierszu trzeba zastąpić matching(searchString + "*") z

matching(searchString + "%") 
+0

Jesteś tego pewien? Po tym nie daje mi żadnych wyników, nawet bez spacji w searchString. Poprzednio (z *) miałem pewne wyniki, dopóki miejsce nie pojawi się w searchString. Nie wiem, jak ten HibernateSearch jest związany z SQL? Wykonuje przeszukiwanie indeksów Lucene, które nie są przechowywane w bazie danych, więc nie jestem pewien, czy używa składni SQL. –

+0

Dla Hibernate + SQL jestem pewien, ale nie używam Lucene i nie wiem, co robi silnik Lucene z danymi wejściowymi. – Johanna

+0

Rozumiem. Myślałeś, że jest to regularne zapytanie do bazy danych. Jednak wyszukiwanie w trybie hibernacji używa zapytań Lucene do przeszukiwania indeksów lucenu, a jego składnia nie jest taka sama, jak w przypadku SQL http://www.lucenetutorial.com/lucene-query-syntax.html –

Powiązane problemy