2015-04-15 1 views
0

Я использую сочетание Hibernate Search и Apache Lucene. То, что я делаю, должно быть справедливым и легким, но я не могу достичь своей цели.Как заставить комбинацию из двух запросов быть ДОЛЖНЫ в Lucene?

У меня есть список строк (фраз), в которые я хочу запросить поле. Поле может содержать любую из этих строк. Между каждым полем должно быть только одно из них.

В MySQL это будет выглядеть следующим образом

select * from movies where (genres = 'name' or genres = 'name2') OR (actors = 'name' or actors = 'name2)' AND (actors = 'name' or actors = 'name2)

Так, если фильм содержал по крайней мере, один жанр дал и 1 актер дал или 2 актеров, то условие будет выполнено. Теперь в Lucene я сначала создаю BooleanQuery, объединяющий всех возможных участников с Occur.SHOULD. Затем я создаю еще один BooleanQuery, объединяющий предыдущий BooleanQuery с другим (который, например, содержит все жанры).

В конце концов, я делаю то же самое дважды и добавляю оба эти BooleanQueries к новому, как с Occur.MUST. Тем не менее, я получаю результаты, когда только одно из моих условий, если выполнено не менее 2. Как мне решить это?

private BooleanQuery getMatchQuery(List<String> list, String field) { 
     BooleanQuery bq = new BooleanQuery(); 
     QueryBuilder qb = getFullTextEntityManager().getSearchFactory().buildQueryBuilder().forEntity(Movie.class).get(); 
     for (String string : list) { 
      bq.add(qb.phrase().onField(field).sentence(string).createQuery(), Occur.SHOULD); 
     } 
     return bq; 
    } 

private BooleanQuery getParamMatches(MovieDto dto, boolean genres){ 
     BooleanQuery bq = new BooleanQuery(); 
     bq.add(getMatchQuery(dto.getActors(), "actors"), Occur.SHOULD); 
     bq.add(getMatchQuery(dto.getDirectors(), "directors"), Occur.SHOULD); 
     bq.add(getMatchQuery(dto.getWriters(), "writers"), Occur.SHOULD); 
     if(genres){ 
      bq.add(getMatchQuery(dto.getGenres(), "genres"), Occur.SHOULD); 
     } 
     return bq; 

    } 
public List<Movie> test(MovieDto dto){ 
     QueryBuilder qb = getFullTextEntityManager().getSearchFactory().buildQueryBuilder().forEntity(Movie.class).get(); 
     log.info(getMatches(dto.getActors())); 
     BooleanQuery bq = new BooleanQuery(); 
     bq.add(getParamMatches(dto, true), Occur.MUST); 
     bq.add(getParamMatches(dto, false), Occur.MUST); 
     javax.persistence.Query query = getFullTextEntityManager().createFullTextQuery(bq, Movie.class); 
     List<Movie> result = query.getResultList(); 
     return result; 
    } 

Это тот порядок, в котором я делаю это, как описано выше. Однако звонки выполняются снизу вверх. Результат запроса это одна:

+((actors:"marlon brando" actors:"al pacino" actors:"james caan" actors:"richard s castellano") 
(directors:"francis ford coppola") (writers:"mario puzo screenplay" writers:"francis ford coppola screenplay" writers:"mario puzo novel") 
(genres:crime genres:drama)) 
+((actors:"marlon brando" actors:"al pacino" actors:"james caan" actors:"richard s castellano") 
(directors:"francis ford coppola") (writers:"mario puzo screenplay" writers:"francis ford coppola screenplay" writers:"mario puzo novel")) 

Итак, как я могу идти о том, чтобы оба условия обязательно в комбинации, так что я не буду получать результаты, в которых только один актер, режиссер и т.д. присутствует? Я хочу, чтобы по крайней мере 2 параметра совпадали, по одному из каждого запроса.

+0

Я только что понял, набрав все это подробно, что, вероятно, я уже делаю это правильно, но это не совсем применимо к моему делу, потому что query1 и query2 могут совпадать с одним и тем же актером, и все это будет верно , Кто-нибудь может это подтвердить? Если у кого-то есть решение для моей проблемы, которое я не смог правильно идентифицировать, это было бы даже лучше. – Schaka

ответ

1

Ваш комментарий правильный, оба ваших подзапроса могут (и во всех результатах данного запроса, безусловно, будут) совпадать с тем же термином.

Существует более простой способ убедиться, что у вас есть как минимум два подзапроса в булевом запросе, вместо того, чтобы создавать список всех возможных комбинаций или что-то в этом роде. BooleanQuery.setMinimumNumberShouldMatch. Таким образом:

BooleanQuery query = getParamMatches(dto, true); 
query.setMinimumShouldMatch(2); 

Необходимо иметь совпадение, по крайней мере, в двух из ваших полей. Если вы хотите получить удар по любым двум указанным условиям, независимо от того, находятся ли они в разных полях или нет, вы должны добавить их все в один BooleanQuery. Это, вероятно, означало бы модификацию getMatchQuery, чтобы принять BooleanQuery в качестве аргумента и просто добавить к нему вместо создания нового.

+0

Из того, что я понимаю, я должен переместить все условия в один BooleanQuery (одно условие для актеров, режиссеров, жанров и т. Д.), А затем установить для этого запроса значениеMinimumShouldMatch (2), так что по крайней мере 2 из условий всегда должны быть истинными. Кажется, что я должен решить свою проблему. Таким образом, «актеры: x genres: y» будут соответствовать, но «жанры: x genres: y» не совпадают, правильно? Я постараюсь получить эту работу и принять ваш вопрос в качестве решения, если это произойдет. Спасибо! – Schaka

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