@Test @SuppressWarnings("unchecked") public void testBoolean() throws Exception { Transaction transaction = fullTextSession.beginTransaction(); final QueryBuilder monthQb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Month.class).get(); // must Query query = monthQb .bool() .must(monthQb.keyword().onField("mythology").matching("colder").createQuery()) .createQuery(); List<Month> results = fullTextSession.createFullTextQuery(query, Month.class).list(); assertEquals(1, results.size()); assertEquals("January", results.get(0).getName()); // must not + all query = monthQb .bool() .should(monthQb.all().createQuery()) .must(monthQb.keyword().onField("mythology").matching("colder").createQuery()) .not() .createQuery(); results = fullTextSession.createFullTextQuery(query, Month.class).list(); assertEquals(2, results.size()); assertEquals("February", results.get(0).getName()); assertEquals("March", results.get(1).getName()); // implicit must not + all (not recommended) query = monthQb .bool() .must(monthQb.keyword().onField("mythology").matching("colder").createQuery()) .not() .createQuery(); results = fullTextSession.createFullTextQuery(query, Month.class).list(); assertEquals(2, results.size()); assertEquals("February", results.get(0).getName()); assertEquals("March", results.get(1).getName()); // all except (recommended) query = monthQb .all() .except(monthQb.keyword().onField("mythology").matching("colder").createQuery()) .createQuery(); results = fullTextSession.createFullTextQuery(query, Month.class).list(); assertEquals(2, results.size()); assertEquals("February", results.get(0).getName()); assertEquals("March", results.get(1).getName()); transaction.commit(); }
// locate a customer in the database public Customers extractCustomer(String email, String password) { FullTextEntityManager fullTextEntityManager = org.hibernate.search.jpa.Search.getFullTextEntityManager(em); QueryBuilder queryBuilder = fullTextEntityManager .getSearchFactory() .buildQueryBuilder() .forEntity(Customers.class) .get(); org.apache.lucene.search.Query query = queryBuilder .bool() .must(queryBuilder.keyword().onField("email").matching(email).createQuery()) .must(queryBuilder.keyword().onField("password").matching(password).createQuery()) .createQuery(); FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(query, Customers.class); fullTextQuery.initializeObjectsWith( ObjectLookupMethod.SKIP, DatabaseRetrievalMethod.FIND_BY_ID); List results = fullTextQuery.getResultList(); if (results.isEmpty()) { return null; } return (Customers) results.get(0); }
public static List<Object> performSearch( Select command, Class<?> type, String cacheName, CacheContainerWrapper cache) throws TranslatorException { LogManager.logTrace(LogConstants.CTX_CONNECTOR, "Using Lucene Searching."); // $NON-NLS-1$ // Map<?, ?> cache, SearchManager searchManager = Search.getSearchManager((Cache<?, ?>) cache.getCache(cacheName)); QueryBuilder queryBuilder = searchManager.buildQueryBuilderForClass(type).get(); BooleanJunction<BooleanJunction> junction = queryBuilder.bool(); boolean createdQueries = buildQueryFromWhereClause(command.getWhere(), junction, queryBuilder); Query query = null; if (createdQueries) { query = junction.createQuery(); } else { query = queryBuilder.all().createQuery(); } CacheQuery cacheQuery = searchManager.getQuery(query, type); // rootNodeType List<Object> results = cacheQuery.list(); if (results == null || results.isEmpty()) { return Collections.emptyList(); } return results; }
@Test(expected = SearchException.class) public void testIllegalBooleanJunction() { final QueryBuilder monthQb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Month.class).get(); // forgetting to set any condition on the boolean, an exception shall be thrown: BooleanJunction<BooleanJunction> booleanJunction = monthQb.bool(); assertTrue(booleanJunction.isEmpty()); Query query = booleanJunction.createQuery(); Assert.fail("should not reach this point"); }
@Test @SuppressWarnings("unchecked") public void testQueryCustomization() throws Exception { Transaction transaction = fullTextSession.beginTransaction(); final QueryBuilder monthQb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Month.class).get(); // combined query, January and february both contain whitening but February in a longer text Query query = monthQb .bool() .should(monthQb.keyword().onField("mythology").matching("whitening").createQuery()) .should(monthQb.keyword().onField("history").matching("whitening").createQuery()) .createQuery(); List<Month> results = fullTextSession.createFullTextQuery(query, Month.class).list(); assertEquals(2, results.size()); assertEquals("January", results.get(0).getName()); // boosted query, January and february both contain whitening but February in a longer text // since history is boosted, February should come first though query = monthQb .bool() .should(monthQb.keyword().onField("mythology").matching("whitening").createQuery()) .should( monthQb .keyword() .onField("history") .boostedTo(30) .matching("whitening") .createQuery()) .createQuery(); results = fullTextSession.createFullTextQuery(query, Month.class).list(); assertEquals(2, results.size()); assertEquals("February", results.get(0).getName()); // FIXME add other method tests besides boostedTo transaction.commit(); }
private Query getQuery(QueryBuilder queryBuilder, List<Query> queries) { if (queries.isEmpty()) { return queryBuilder.all().createQuery(); } else { BooleanJunction<BooleanJunction> bool = queryBuilder.bool(); for (Query query : queries) { bool.must(query); } return bool.createQuery(); } }
private FullTextQuery buildFullTextQuery( UserSearchRequest request, Pageable pageable, Criteria criteria) { FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager); QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(User.class).get(); @SuppressWarnings("rawtypes") BooleanJunction<BooleanJunction> junction = qb.bool(); junction.must(qb.all().createQuery()); if (StringUtils.hasText(request.getKeyword())) { Analyzer analyzer = fullTextEntityManager.getSearchFactory().getAnalyzer("synonyms"); String[] fields = new String[] { "loginId", "name.firstName", "name.lastName", }; MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer); parser.setDefaultOperator(QueryParser.Operator.AND); Query query = null; try { query = parser.parse(request.getKeyword()); } catch (ParseException e1) { try { query = parser.parse(QueryParser.escape(request.getKeyword())); } catch (ParseException e2) { throw new RuntimeException(e2); } } junction.must(query); } if (!CollectionUtils.isEmpty(request.getRoles())) { for (User.Role role : request.getRoles()) { junction.must(qb.keyword().onField("roles").matching(role).createQuery()); } } Query searchQuery = junction.createQuery(); Sort sort = new Sort(new SortField("id", SortField.Type.STRING, false)); FullTextQuery persistenceQuery = fullTextEntityManager .createFullTextQuery(searchQuery, User.class) .setCriteriaQuery(criteria) // .setProjection("id") .setSort(sort); if (pageable != null) { persistenceQuery.setFirstResult(pageable.getOffset()); persistenceQuery.setMaxResults(pageable.getPageSize()); } return persistenceQuery; }
@Override public Page<Comment> search(CommentSearchRequest request, Pageable pageable) { FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager); QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Comment.class).get(); @SuppressWarnings("rawtypes") BooleanJunction<BooleanJunction> junction = qb.bool(); junction.must(qb.all().createQuery()); if (StringUtils.hasText(request.getKeyword())) { Analyzer analyzer = fullTextEntityManager.getSearchFactory().getAnalyzer("synonyms"); String[] fields = new String[] {"authorName", "content"}; MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer); parser.setDefaultOperator(QueryParser.Operator.AND); Query query = null; try { query = parser.parse(request.getKeyword()); } catch (ParseException e1) { try { query = parser.parse(QueryParser.escape(request.getKeyword())); } catch (ParseException e2) { throw new RuntimeException(e2); } } junction.must(query); } if (StringUtils.hasText(request.getLanguage())) { junction.must( qb.keyword().onField("post.language").matching(request.getLanguage()).createQuery()); } if (request.getPostId() != null) { junction.must(qb.keyword().onField("post.id").matching(request.getPostId()).createQuery()); } if (request.getApproved() != null) { junction.must(qb.keyword().onField("approved").matching(request.getApproved()).createQuery()); } Query searchQuery = junction.createQuery(); Session session = (Session) entityManager.getDelegate(); Criteria criteria = session .createCriteria(Comment.class) .setFetchMode("post", FetchMode.JOIN) .setFetchMode("author", FetchMode.JOIN); Sort sort = null; if (pageable.getSort() != null) { if (pageable.getSort().getOrderFor("date") != null) { Order order = pageable.getSort().getOrderFor("date"); sort = new Sort( new SortField( "date", SortField.Type.STRING, order.getDirection().equals(Direction.DESC)), new SortField( "id", SortField.Type.LONG, order.getDirection().equals(Direction.DESC))); } } if (sort == null) { sort = new Sort( new SortField("date", SortField.Type.STRING), new SortField("id", SortField.Type.LONG)); } FullTextQuery persistenceQuery = fullTextEntityManager .createFullTextQuery(searchQuery, Comment.class) .setCriteriaQuery(criteria) .setSort(sort); persistenceQuery.setFirstResult(pageable.getOffset()); persistenceQuery.setMaxResults(pageable.getPageSize()); int resultSize = persistenceQuery.getResultSize(); @SuppressWarnings("unchecked") List<Comment> results = persistenceQuery.getResultList(); return new PageImpl<>(results, pageable, resultSize); }
private static boolean buildQueryFromWhereClause( Condition criteria, BooleanJunction<BooleanJunction> junction, QueryBuilder queryBuilder) throws TranslatorException { boolean createdQueries = false; BooleanJunction<BooleanJunction> inUse = junction; if (criteria instanceof AndOr) { LogManager.logTrace(LogConstants.CTX_CONNECTOR, "Parsing compound criteria."); // $NON-NLS-1$ AndOr crit = (AndOr) criteria; AndOr.Operator op = crit.getOperator(); switch (op) { case AND: BooleanJunction<BooleanJunction> leftAnd = queryBuilder.bool(); boolean andLeftHasQueries = buildQueryFromWhereClause(crit.getLeftCondition(), leftAnd, queryBuilder); BooleanJunction<BooleanJunction> rightAnd = queryBuilder.bool(); boolean andRightHasQueries = buildQueryFromWhereClause(crit.getRightCondition(), rightAnd, queryBuilder); if (andLeftHasQueries && andRightHasQueries) { leftAnd.must(rightAnd.createQuery()); inUse.should(leftAnd.createQuery()); } else if (andLeftHasQueries) { inUse.should(leftAnd.createQuery()); } else if (andRightHasQueries) { inUse.should(rightAnd.createQuery()); } createdQueries = (andLeftHasQueries ? andLeftHasQueries : andRightHasQueries); break; case OR: boolean orLeftHasQueries = buildQueryFromWhereClause(crit.getLeftCondition(), inUse, queryBuilder); boolean orRightHasQueries = buildQueryFromWhereClause(crit.getRightCondition(), inUse, queryBuilder); createdQueries = (orLeftHasQueries ? orLeftHasQueries : orRightHasQueries); break; default: final String msg = ObjectPlugin.Util.getString( "LuceneSearch.invalidOperator", new Object[] {op, "And, Or"}); // $NON-NLS-1$ //$NON-NLS-2$ throw new TranslatorException(msg); } } else if (criteria instanceof Comparison) { createdQueries = visit((Comparison) criteria, inUse, queryBuilder); } else if (criteria instanceof Exists) { LogManager.logTrace( LogConstants.CTX_CONNECTOR, "Parsing EXISTS criteria: NOT IMPLEMENTED YET"); //$NON-NLS-1$ // TODO Exists should be supported in a future release. } else if (criteria instanceof Like) { createdQueries = visit((Like) criteria, inUse, queryBuilder); } else if (criteria instanceof In) { createdQueries = visit((In) criteria, inUse, queryBuilder); } // else if (criteria instanceof Not) { // LogManager.logTrace(LogConstants.CTX_CONNECTOR, "Parsing NOT criteria."); //$NON-NLS-1$ // isNegated = true; // filterList.addAll(getSearchFilterFromWhereClause(((Not)criteria).getCriteria(), // new LinkedList<String>())); // } return createdQueries; }
/** Execute Lucene index query. */ private QueryResponse executeQuery( AdvancedCache<byte[], byte[]> cache, SerializationContext serCtx, QueryRequest request) { final SearchManager searchManager = Search.getSearchManager(cache); final SearchIntegrator searchFactory = searchManager.getSearchFactory(); final QueryCache queryCache = ComponentRegistryUtils.getQueryCache(cache); // optional component LuceneQueryParsingResult parsingResult; Query luceneQuery; if (queryCache != null) { KeyValuePair<String, Class> queryCacheKey = new KeyValuePair<String, Class>(request.getJpqlString(), LuceneQueryParsingResult.class); parsingResult = queryCache.get(queryCacheKey); if (parsingResult == null) { parsingResult = parseQuery(cache, serCtx, request.getJpqlString(), searchFactory); queryCache.put(queryCacheKey, parsingResult); } } else { parsingResult = parseQuery(cache, serCtx, request.getJpqlString(), searchFactory); } luceneQuery = parsingResult.getQuery(); if (!cache.getCacheConfiguration().compatibility().enabled()) { // restrict on entity type QueryBuilder qb = searchFactory.buildQueryBuilder().forEntity(parsingResult.getTargetEntity()).get(); luceneQuery = qb.bool() .must( qb.keyword() .onField(TYPE_FIELD_NAME) .ignoreFieldBridge() .ignoreAnalyzer() .matching(parsingResult.getTargetEntityName()) .createQuery()) .must(luceneQuery) .createQuery(); } CacheQuery cacheQuery = searchManager.getQuery(luceneQuery, parsingResult.getTargetEntity()); if (parsingResult.getSort() != null) { cacheQuery = cacheQuery.sort(parsingResult.getSort()); } int projSize = 0; if (parsingResult.getProjections() != null && !parsingResult.getProjections().isEmpty()) { projSize = parsingResult.getProjections().size(); cacheQuery = cacheQuery.projection(parsingResult.getProjections().toArray(new String[projSize])); } if (request.getStartOffset() > 0) { cacheQuery = cacheQuery.firstResult((int) request.getStartOffset()); } if (request.getMaxResults() > 0) { cacheQuery = cacheQuery.maxResults(request.getMaxResults()); } List<?> list = cacheQuery.list(); List<WrappedMessage> results = new ArrayList<WrappedMessage>(projSize == 0 ? list.size() : list.size() * projSize); for (Object o : list) { if (projSize == 0) { results.add(new WrappedMessage(o)); } else { Object[] row = (Object[]) o; for (int j = 0; j < projSize; j++) { results.add(new WrappedMessage(row[j])); } } } QueryResponse response = new QueryResponse(); response.setTotalResults(cacheQuery.getResultSize()); response.setNumResults(list.size()); response.setProjectionSize(projSize); response.setResults(results); return response; }
public static void Bench() { Session session = null; FullTextSession fullTextSession = null; SessionFactory sessionFactory = null; try { sessionFactory = new Configuration().configure(hibernateConfigurationFile).buildSessionFactory(); session = sessionFactory.openSession(); session.beginTransaction(); fullTextSession = Search.getFullTextSession(session); long gridTotalDuration = 0; long spatialTotalDuration = 0; long doubleRangeTotalDuration = 0; long distanceDoubleRangeTotalDuration = 0; long gridDocsFetched = 0; long spatialDocsFetched = 0; long doubleRangeDocsFetched = 0; long distanceDoubleRangeDocsFetched = 0; org.apache.lucene.search.Query luceneQuery; long startTime, endTime, duration; FullTextQuery hibQuery; List gridResults, rangeResults; final QueryBuilder queryBuilder = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(POI.class).get(); org.apache.lucene.search.Query query; final Integer iterations = 2000; final Integer warmUp = 50; Random random = new Random(42); for (int i = 0; i < iterations; i++) { Point center = Point.fromDegrees(random.nextDouble() * 2 + 44, random.nextDouble() * 2 + 3); double radius = 25.0d; Rectangle boundingBox = Rectangle.fromBoundingCircle(center, radius); query = queryBuilder .bool() .must( queryBuilder .range() .onField("latitude") .from(boundingBox.getLowerLeft().getLatitude()) .to(boundingBox.getUpperRight().getLatitude()) .createQuery()) .must( queryBuilder .range() .onField("longitude") .from(boundingBox.getLowerLeft().getLongitude()) .to(boundingBox.getUpperRight().getLongitude()) .createQuery()) .createQuery(); hibQuery = fullTextSession.createFullTextQuery(query, POI.class); hibQuery.setProjection("id", "name"); startTime = System.nanoTime(); try { doubleRangeDocsFetched += hibQuery.getResultSize(); } finally { endTime = System.nanoTime(); } duration = endTime - startTime; if (i > warmUp) { doubleRangeTotalDuration += duration; } session.clear(); query = queryBuilder .bool() .must( queryBuilder .range() .onField("latitude") .from(boundingBox.getLowerLeft().getLatitude()) .to(boundingBox.getUpperRight().getLatitude()) .createQuery()) .must( queryBuilder .range() .onField("longitude") .from(boundingBox.getLowerLeft().getLongitude()) .to(boundingBox.getUpperRight().getLongitude()) .createQuery()) .createQuery(); org.apache.lucene.search.Query filteredQuery = new ConstantScoreQuery( SpatialQueryBuilderFromPoint.buildDistanceFilter( new QueryWrapperFilter(query), center, radius, "location")); hibQuery = fullTextSession.createFullTextQuery(filteredQuery, POI.class); hibQuery.setProjection("id", "name"); startTime = System.nanoTime(); try { distanceDoubleRangeDocsFetched += hibQuery.getResultSize(); } finally { endTime = System.nanoTime(); } duration = endTime - startTime; if (i > warmUp) { distanceDoubleRangeTotalDuration += duration; } rangeResults = hibQuery.list(); session.clear(); luceneQuery = SpatialQueryBuilderFromPoint.buildGridQuery(center, radius, "location"); hibQuery = fullTextSession.createFullTextQuery(luceneQuery, POI.class); hibQuery.setProjection("id", "name"); startTime = System.nanoTime(); try { gridDocsFetched += hibQuery.getResultSize(); } finally { endTime = System.nanoTime(); } duration = endTime - startTime; if (i > warmUp) { gridTotalDuration += duration; } session.clear(); luceneQuery = SpatialQueryBuilderFromPoint.buildSpatialQueryByGrid(center, radius, "location"); hibQuery = fullTextSession.createFullTextQuery(luceneQuery, POI.class); hibQuery.setProjection("id", "name"); startTime = System.nanoTime(); try { spatialDocsFetched += hibQuery.getResultSize(); } finally { endTime = System.nanoTime(); } duration = endTime - startTime; if (i > warmUp) { spatialTotalDuration += duration; } gridResults = hibQuery.list(); session.clear(); if (rangeResults.size() != gridResults.size()) { luceneQuery = SpatialQueryBuilderFromPoint.buildDistanceQuery(center, radius, "location"); hibQuery = fullTextSession.createFullTextQuery(luceneQuery, POI.class); hibQuery.setProjection("id", "name"); System.out.println( ">>>>> Different numbers of documents fetched for point (" + Double.toString(center.getLatitude()) + "," + Double.toString(center.getLongitude()) + ") and radius " + Double.toString(radius)); System.out.println("Range results : " + rangeResults); System.out.println("Grid results : " + gridResults); System.out.println("Pure distance results : " + hibQuery.getResultSize()); List<Integer> rangeIds = new ArrayList<Integer>(); for (int index = 0; index < rangeResults.size(); index++) { rangeIds.add((Integer) ((Object[]) rangeResults.get(index))[0]); } List<Integer> gridIds = new ArrayList<Integer>(); for (int index = 0; index < gridResults.size(); index++) { gridIds.add((Integer) ((Object[]) gridResults.get(index))[0]); } rangeIds.removeAll(gridIds); System.out.println("Missing Ids : " + rangeIds); } } session.getTransaction().commit(); session.close(); sessionFactory.close(); System.out.println( "Mean time with Grid : " + Double.toString( (double) gridTotalDuration * Math.pow(10, -6) / (iterations - warmUp)) + " ms. Average number of docs fetched : " + Double.toString(gridDocsFetched / ((iterations - warmUp) * 1.0d))); System.out.println( "Mean time with Grid + Distance filter : " + Double.toString( (double) spatialTotalDuration * Math.pow(10, -6) / (iterations - warmUp)) + " ms. Average number of docs fetched : " + Double.toString(spatialDocsFetched / ((iterations - warmUp) * 1.0d))); System.out.println( "Mean time with DoubleRange : " + Double.toString( (double) doubleRangeTotalDuration * Math.pow(10, -6) / (iterations - warmUp)) + " ms. Average number of docs fetched : " + Double.toString(doubleRangeDocsFetched / ((iterations - warmUp) * 1.0d))); System.out.println( "Mean time with DoubleRange + Distance filter : " + Double.toString( (double) distanceDoubleRangeTotalDuration * Math.pow(10, -6) / (iterations - warmUp)) + " ms. Average number of docs fetched : " + Double.toString(distanceDoubleRangeDocsFetched / ((iterations - warmUp) * 1.0d))); } catch (Exception e) { e.printStackTrace(); } finally { if (fullTextSession != null && fullTextSession.isOpen()) { Transaction transaction = fullTextSession.getTransaction(); if (transaction != null && transaction.isActive()) { transaction.rollback(); } fullTextSession.close(); } if (sessionFactory != null && !sessionFactory.isClosed()) { sessionFactory.close(); } } }
private FullTextQuery buildFullTextQuery( ArticleSearchRequest request, Pageable pageable, Criteria criteria) { FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager); QueryBuilder qb = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Article.class).get(); @SuppressWarnings("rawtypes") BooleanJunction<BooleanJunction> junction = qb.bool(); junction.must(qb.all().createQuery()); junction.must( qb.keyword().onField("drafted").ignoreAnalyzer().matching("_null_").createQuery()); if (StringUtils.hasText(request.getKeyword())) { Analyzer analyzer = fullTextEntityManager.getSearchFactory().getAnalyzer("synonyms"); String[] fields = new String[] { "title", "body", "categories.name", "tags.name", }; MultiFieldQueryParser parser = new MultiFieldQueryParser(fields, analyzer); parser.setDefaultOperator(QueryParser.Operator.AND); Query query = null; try { query = parser.parse(request.getKeyword()); } catch (ParseException e1) { try { query = parser.parse(QueryParser.escape(request.getKeyword())); } catch (ParseException e2) { throw new RuntimeException(e2); } } junction.must(query); } if (request.getStatus() != null) { junction.must(qb.keyword().onField("status").matching(request.getStatus()).createQuery()); } if (StringUtils.hasText(request.getLanguage())) { junction.must(qb.keyword().onField("language").matching(request.getLanguage()).createQuery()); } if (request.getDateFrom() != null) { junction.must(qb.range().onField("date").above(request.getDateFrom()).createQuery()); } if (request.getDateTo() != null) { junction.must(qb.range().onField("date").below(request.getDateTo()).createQuery()); } if (!CollectionUtils.isEmpty(request.getCategoryIds())) { BooleanJunction<BooleanJunction> subJunction = qb.bool(); for (long categoryId : request.getCategoryIds()) { subJunction.should( qb.keyword().onField("categories.id").matching(categoryId).createQuery()); } junction.must(subJunction.createQuery()); } if (!CollectionUtils.isEmpty(request.getCategoryCodes())) { BooleanJunction<BooleanJunction> subJunction = qb.bool(); for (String categoryCode : request.getCategoryCodes()) { subJunction.should( qb.keyword().onField("categories.code").matching(categoryCode).createQuery()); } junction.must(subJunction.createQuery()); } if (!CollectionUtils.isEmpty(request.getTagIds())) { BooleanJunction<BooleanJunction> subJunction = qb.bool(); for (long tagId : request.getTagIds()) { subJunction.should(qb.keyword().onField("tags.id").matching(tagId).createQuery()); } junction.must(subJunction.createQuery()); } if (!CollectionUtils.isEmpty(request.getTagNames())) { BooleanJunction<BooleanJunction> subJunction = qb.bool(); for (String tagName : request.getTagNames()) { subJunction.should(qb.phrase().onField("tags.name").sentence(tagName).createQuery()); } junction.must(subJunction.createQuery()); } if (request.getAuthorId() != null) { junction.must( qb.keyword().onField("author.id").matching(request.getAuthorId()).createQuery()); } Query searchQuery = junction.createQuery(); Sort sort = new Sort( new SortField("date", SortField.Type.STRING, true), new SortField("id", SortField.Type.LONG, true)); FullTextQuery persistenceQuery = fullTextEntityManager .createFullTextQuery(searchQuery, Article.class) .setCriteriaQuery(criteria) .setSort(sort); if (pageable != null) { persistenceQuery.setFirstResult(pageable.getOffset()); persistenceQuery.setMaxResults(pageable.getPageSize()); } return persistenceQuery; }