Как искать поля с подстановочными знаками и пробелами в Hibernate Search

У меня есть поле поиска, которое выполняет поиск по полю заголовка на основе заданного ввода, поэтому пользователь рекомендовал все доступные заголовки, начиная с вставленного текста. Оно основано на поиске Lucene и Hibernate. Работает нормально, пока не введен пробел. Потом результат исчезнет. Например, я хочу, чтобы «Learning H» давал мне в результате «Learning Hibernate». Однако этого не происходит. не могли бы вы посоветовать мне, что я должен использовать здесь вместо этого.

Конструктор запросов:

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

Класс гибернации:

@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 {

person zoran jeremic    schedule 08.03.2013    source источник
comment
печать запроса на вывод вам определенно поможет ..   -  person phanin    schedule 08.03.2013
comment
Это действительно полезно, но не помогло мне понять, почему у меня нет результатов. Например, у меня есть цель обучения под названием "Теория вероятности обучения". Результатом двух запросов является bQuery: + title: learning p * hibQuery: FullTextQueryImpl (title: learning p *) для обучения входной строке p. Он находит значение, если входная строка обучается.   -  person zoran jeremic    schedule 08.03.2013
comment
Я также пробовал заменить пробел на?, Но это не дало результата.   -  person zoran jeremic    schedule 08.03.2013


Ответы (2)


Я нашел способ обойти эту проблему. Идея состоит в том, чтобы токенизировать входную строку и удалить стоп-слова. Для последнего токена я создал запрос с использованием подстановочного знака ключевого слова, а для всех предыдущих слов я создал TermQuery. Вот полный код

    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);
person zoran jeremic    schedule 13.03.2013
comment
Не могли бы вы добавить больше пояснений? Я пока не понимаю. Почему вы используете другой запрос для последнего токена? И, пожалуйста, измените свой пример, чтобы он был достаточно ясным. Зачем вообще existingGoals? - person alexander; 14.08.2015
comment
Допустим, у нас есть заголовок Hibernate Search. Когда пользователь вошел в Hibernate Se, первым токеном будет Hibernate, и мы берем точный термин, поскольку мы знаем, что пользователь ввел все слово, которое он хотел, поскольку он уже начал вводить другое слово. Для второго слова se, поскольку мы знаем, что пользователь мог не закончить ввод, мы используем подстановочный знак, чтобы быть уверенным, что он не в середине слова, что здесь и есть. Таким образом, запрос последнего слова будет охватывать все, что начинается с se, и все слова, введенные пользователем ранее, будут использоваться как точные термины. - person zoran jeremic; 14.08.2015
comment
Что касается второго вопроса (existingGoals), это что-то очень специфичное для моего сценария использования. Я хотел исключить из результатов поиска те заголовки, которые пользователь уже добавил в свой список выбранных элементов, поэтому эти существующие цели на самом деле являются заголовками, которые следует игнорировать, и они могут вам не понадобиться в вашем случае. - person zoran jeremic; 14.08.2015
comment
В этом есть большой смысл. Я просто использовал ваш цикл для своего варианта использования. :) Спасибо! - person alexander; 15.08.2015
comment
Спасибо, бро. Очень помогло. - person gschambial; 23.03.2018

В SQL используются разные символы подстановки, чем в любом терминале. В SQL '%' заменяет ноль или более вхождений любого символа (вместо этого в терминале используется '*'), а подчеркивание '_' заменяет ровно один символ (в терминале вместо этого используется '?'). Hibernate не переводит подстановочные знаки.

Итак, во второй строке вы должны заменить matching(searchString + "*") на

  matching(searchString + "%")
person Johanna    schedule 08.03.2013
comment
Ты уверен насчет этого? После этого он не дает мне никаких результатов, даже без пробелов в searchString. Раньше (с *) у меня были некоторые результаты, пока в searchString не возникло пробел. Я не знаю, как этот HibernateSearch связан с SQL? Он выполняет поиск по индексам Lucene, которые не хранятся в базе данных, поэтому я не уверен, использует ли он синтаксис SQL. - person zoran jeremic; 08.03.2013
comment
Я уверен в Hibernate + SQL, но я не использую Lucene и не знаю, что движок Lucene делает с вводом. - person Johanna; 11.03.2013
comment
Я понимаю. Вы думали, что это обычный запрос к базе данных. Однако Hibernate Search использует запросы Lucene для поиска по индексам lucene, и его синтаксис отличается от синтаксиса SQL lucenetutorial.com/lucene-query-syntax.html - person zoran jeremic; 11.03.2013