2012-04-19 8 views
8

Я изучаю Hibernate Search Query DSL, и я не уверен, как создавать запросы с использованием логических аргументов, таких как AND или OR.Как использовать логические операторы с Hibernate Search

Например, предположим, что я хочу вернуть все записи людей, у которых есть значение «bill» или «bob».

После гибернации документы, один пример использует метод BOOL() ж/два подзапросов, такие как:

QueryBuilder b = fts.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get(); 
Query luceneQuery = b.bool() 
    .should(b.keyword().onField("firstName").matching("bill").createQuery()) 
    .should(b.keyword().onField("firstName").matching("bob").createQuery()) 
    .createQuery(); 

logger.debug("query 1:{}", luceneQuery.toString()); 

Это в конечном счете производит запрос Lucene, что я хочу, но это правильный способ использовать логическая логика с поиском в спящем режиме? Является ли «should()» эквивалентом «OR» (аналогично, «must()» соответствует «AND») ?.

Кроме того, при написании запроса этот способ кажется громоздким. Например, что, если бы я имел коллекцию firstNames для сопоставления? Является ли этот тип запросов хорошим совпадением для DSL в первую очередь?

+0

'must' является' and', но 'should' кажется, что какое-то мягкая версия' and'. Определенно не 'или'. В теории вы можете получить 'или' как 'not and not', получив' must (b.must(). Not(). Must(). Not()). Not() ', но это не очень удовлетворительный ответ. – trutheality

ответ

3

Да, ваш пример правильный. Булевы операторы называются , если вместо ИЛИ из-за имен, которые они имеют в API Lucene и документации, и потому что это более уместно: это не только влияет на логическое решение, но также влияет на оценку результата ,

Например, если вы ищете автомобили «марки Fiat» или «синие», автомобили, фирменные Fiat и синие, также будут возвращены и имеют более высокий балл, чем синие, но не Fiat.

Это может показаться громоздким, поскольку оно является программным и предоставляет множество подробных опций. Более простая альтернатива - использовать простую строку для вашего запроса и использовать QueryParser для создания запроса. Как правило, синтаксический анализатор полезен для анализа пользовательского ввода, программному проще справляться с четко определенными полями; например, если у вас есть коллекция, которую вы упомянули, ее легко построить в для цикла.

1

Чтобы ответить вам вопрос второстепенный:

Например, что делать, если у меня была коллекция firstNames в соответствии с?

Я не эксперт, но согласно (третий пример с конца) 5.1.2.1. Ключевое слово запросов в Hibernate Search Documentation, вы должны быть в состоянии построить запрос следующим образом:

Collection<String> namesCollection = getNames(); // Contains "billy" and "bob", for example 
StringBuilder names = new StringBuilder(100); 
for(String name : namesCollection) { 
    names.append(name).append(" "); // Never mind the space at the end of the resulting string. 
} 

QueryBuilder b = fts.getSearchFactory().buildQueryBuilder().forEntity(Person.class).get(); 
Query luceneQuery = b.bool() 
    .should(
     // Searches for multiple possible values in the same field 
     b.keyword().onField("firstName").matching(sb.toString()).createQuery() 
    ) 
    .must(b.keyword().onField("lastName").matching("thornton").createQuery()) 
    .createQuery(); 

и имеют в результате, Person s с (firstNameпредпочтительно «котелок» или «боб») И (lastName = "thornton"), хотя я не думаю, что это даст хороший ол Билли Боб Торнтон более высокий балл ;-).

1

Вы также можете использовать BooleanQuery. Я бы предпочел этот сигнал. Вы можете использовать это в цикле списка.

org.hibernate.search.FullTextQuery hibque = null; 

    org.apache.lucene.search.BooleanQuery bquery = new BooleanQuery(); 

    QueryBuilder qb = fulltextsession.getSearchFactory().buildQueryBuilder() 
       .forEntity(entity.getClass()).get(); 
    for (String keyword : list) { 
     bquery.add(qb.keyword().wildcard().onField(entityColumn).matching(keyword) 
       .createQuery() , BooleanClause.Occur.SHOULD); 
    } 

    if (!filterColumn.equals("") && !filterValue.equals("")) { 
     bquery.add(qb.keyword().wildcard().onField(column).matching(value).createQuery() 
         , BooleanClause.Occur.MUST); 
    } 

    hibque = fulltextsession.createFullTextQuery(bquery, entity.getClass()); 

    int num = hibque.getResultSize(); 
1

Я искал одну и ту же проблему и имею несколько другую проблему, чем представленную. Я искал фактическое соединение OR.Случай не работал для меня, как результаты, которые не прошли ни одно из двух выражений, но с более низким счетом. Я хотел полностью опустить эти результаты. Однако вы можете создать фактическое логическое ИЛИ выражение, используя отдельное логическое выражение, для которого вы отключаете забивая:

val booleanQuery = cb.bool(); 
val packSizeSubQuery = cb.bool(); 

packSizes.stream().map(packSize -> cb.phrase() 
    .onField(LUCENE_FIELD_PACK_SIZES) 
    .sentence(packSize.name()) 
    .createQuery()) 
    .forEach(packSizeSubQuery::should); 

booleanQuery.must(packSizeSubQuery.createQuery()).disableScoring(); 
fullTextEntityManager.createFullTextQuery(booleanQuery.createQuery(), Product.class) 
return persistenceQuery.getResultList(); 
+0

Знаете ли вы, как сравнить значение с NULL в Hibernate Search? Например, в SQL я сравниваю значение с NULL следующим образом: ** WHERE TABLE.FIELD NULL ** – adyjr

+0

Не можете ли вы выполнить поиск по ключевому слову с 'null' как значением? Что касается моего понимания пространственного пространства Hibernate, то полевой мост должен гарантировать, что ваше нулевое значение сериализуется в равной степени для запроса, как это делается для хранения объекта, и это должно работать из коробки. –

+0

Thks Jan. Ответ здесь: http://stackoverflow.com/a/11890368/2278773. Но нужно использовать родной запрос Lucene. – adyjr

Смежные вопросы