@Test public void testSortableField() throws Exception { FullTextSession s = Search.getFullTextSession(openSession()); Transaction tx = s.beginTransaction(); Item item1 = new Item(); item1.setId(3); item1.setPrice((short) 3454); s.persist(item1); Item item2 = new Item(); item2.setId(2); item2.setPrice((short) 3354); s.persist(item2); Item item3 = new Item(); item3.setId(1); item3.setPrice((short) 3554); s.persist(item3); tx.commit(); s.clear(); tx = s.beginTransaction(); Query q = s.getSearchFactory().buildQueryBuilder().forEntity(Item.class).get().all().createQuery(); FullTextQuery query = s.createFullTextQuery(q, Item.class); query.setSort(new Sort(new SortField("price", SortField.Type.INT))); List<?> results = query.list(); assertThat(results) .onProperty("price") .describedAs("Sortable field via programmatic config") .containsExactly((short) 3354, (short) 3454, (short) 3554); query.setSort(new Sort(new SortField("id", SortField.Type.STRING))); results = query.list(); assertThat(results) .onProperty("id") .describedAs("Sortable field via programmatic config") .containsExactly(1, 2, 3); s.delete(results.get(0)); s.delete(results.get(1)); s.delete(results.get(2)); tx.commit(); s.close(); }
/** * 全文检索 * * @param page 分页对象 * @param query 关键字查询对象 * @param queryFilter 查询过滤对象 * @param sort 排序对象 * @return 分页对象 */ @SuppressWarnings("unchecked") public Page<T> search(Page<T> page, BooleanQuery query, BooleanQuery queryFilter, Sort sort) { // 按关键字查询 FullTextQuery fullTextQuery = getFullTextSession().createFullTextQuery(query, entityClass); // 过滤无效的内容 if (queryFilter != null) { fullTextQuery.setFilter(new CachingWrapperFilter(new QueryWrapperFilter(queryFilter))); } // 设置排序 if (sort != null) { fullTextQuery.setSort(sort); } // 定义分页 page.setCount(fullTextQuery.getResultSize()); fullTextQuery.setFirstResult(page.getFirstResult()); fullTextQuery.setMaxResults(page.getMaxResults()); // 先从持久化上下文中查找对象,如果没有再从二级缓存中查找 fullTextQuery.initializeObjectsWith( ObjectLookupMethod.SECOND_LEVEL_CACHE, DatabaseRetrievalMethod.QUERY); // 返回结果 page.setList(fullTextQuery.list()); return page; }
@SuppressWarnings("unchecked") @Test public void testResultOrderedByIdAlteringSortStyle() throws Exception { Transaction tx = fullTextSession.beginTransaction(); Query query = queryParser.parse("summary:lucene"); FullTextQuery hibQuery = fullTextSession.createFullTextQuery(query, Book.class); hibQuery.setSort(new Sort(new SortField("id", SortField.Type.LONG, false))); List<Book> result = hibQuery.list(); assertThat(result).onProperty("id").containsExactly(1, 2, 3, 10); hibQuery.setSort(new Sort(new SortField("id", SortField.Type.STRING, false))); result = hibQuery.list(); assertThat(result).onProperty("id").containsExactly(1, 10, 2, 3); hibQuery.setSort(new Sort(new SortField("id", SortField.Type.LONG, false))); result = hibQuery.list(); assertThat(result).onProperty("id").containsExactly(1, 2, 3, 10); tx.commit(); }
@SuppressWarnings("unchecked") @Test public void testResultOrderedByDocId() throws Exception { Transaction tx = fullTextSession.beginTransaction(); Query query = queryParser.parse("summary:lucene"); FullTextQuery hibQuery = fullTextSession.createFullTextQuery(query, Book.class); Sort sort = new Sort(new SortField(null, SortField.Type.DOC, false)); hibQuery.setSort(sort); List<Book> result = hibQuery.list(); assertNotNull(result); assertThat(result).onProperty("id").containsOnly(1, 2, 3, 10); tx.commit(); }
@SuppressWarnings("unchecked") @Test public void testResultOrderedByDateDescending() throws Exception { Transaction tx = fullTextSession.beginTransaction(); // order by date backwards Query query = queryParser.parse("summary:lucene OR summary:action"); FullTextQuery hibQuery = fullTextSession.createFullTextQuery(query, Book.class); Sort sort = new Sort(new SortField("publicationDate", SortField.Type.STRING, true)); // DESC hibQuery.setSort(sort); List<Book> result = hibQuery.list(); assertNotNull(result); assertThat(result).onProperty("id").containsExactly(4, 10, 3, 2, 1); assertEquals("Groovy in Action", result.get(0).getSummary()); tx.commit(); }
@SuppressWarnings("unchecked") @Test public void testResultOrderedBySummaryStringDescending() throws Exception { Transaction tx = fullTextSession.beginTransaction(); // order by summary backwards Query query = queryParser.parse("summary:lucene OR summary:action"); FullTextQuery hibQuery = fullTextSession.createFullTextQuery(query, Book.class); Sort sort = new Sort(new SortField("summary_forSort", SortField.Type.STRING, true)); // DESC hibQuery.setSort(sort); List<Book> result = hibQuery.list(); assertNotNull(result); assertEquals("Wrong number of test results.", 5, result.size()); assertEquals("Hibernate & Lucene", result.get(0).getSummary()); tx.commit(); }
@Override public StorageResults visit(OrderBy orderBy) { TypedExpression field = orderBy.getExpression(); if (field instanceof Field) { FieldMetadata fieldMetadata = ((Field) field).getFieldMetadata(); SortField sortField = new SortField( fieldMetadata.getName(), getSortType(fieldMetadata), orderBy.getDirection() == OrderBy.Direction.DESC); query.setSort(new Sort(sortField)); return null; } else { throw new NotImplementedException( "No support for order by for full text search on non-field."); } }
/** * 生成Hibernate的FullTextQuery全文搜索对象。 * * @return 返回Hibernate的FullTextQuery全文搜索对象。 */ public FullTextQuery generateQuery() { FullTextQuery fullTextQuery = session.createFullTextQuery(generateLuceneQuery(), clazz); if (!sortFields.isEmpty()) { for (SortField sortField : sortFields) { if (!searchFields.containsKey(sortField.getField())) { throw new HibernateException("全文搜索时指定的排序字段 " + sortField.getField() + " 必须包含在搜索字段中"); } } fullTextQuery.setSort(new Sort(sortFields.toArray(new SortField[] {}))); } if (filter != null) { fullTextQuery.setFilter(filter); } if (criteriaQuery != null) { fullTextQuery.setCriteriaQuery(criteriaQuery); } return fullTextQuery; }
@SuppressWarnings("unchecked") @Test public void testCustomFieldComparatorDescendingSort() { Transaction tx = fullTextSession.beginTransaction(); Query query = new MatchAllDocsQuery(); FullTextQuery hibQuery = fullTextSession.createFullTextQuery(query, NumberHolder.class); Sort sort = new Sort(new SortField("sum", new SumFieldComparatorSource(), true)); hibQuery.setSort(sort); List<NumberHolder> result = hibQuery.list(); assertNotNull(result); assertEquals("Wrong number of test results.", 4, result.size()); int previousSum = 100; for (NumberHolder n : result) { assertTrue("Documents should be ordered by decreasing sum", previousSum > n.getSum()); previousSum = n.getSum(); } tx.commit(); }
@Override public StorageResults visit(Select select) { // TMDM-4654: Checks if entity has a composite PK. Set<ComplexTypeMetadata> compositeKeyTypes = new HashSet<ComplexTypeMetadata>(); // TMDM-7496: Search should include references to reused types Collection<ComplexTypeMetadata> types = new HashSet<ComplexTypeMetadata>(select.accept(new SearchTransitiveClosure())); for (ComplexTypeMetadata type : types) { if (type.getKeyFields().size() > 1) { compositeKeyTypes.add(type); } } if (!compositeKeyTypes.isEmpty()) { StringBuilder message = new StringBuilder(); Iterator it = compositeKeyTypes.iterator(); while (it.hasNext()) { ComplexTypeMetadata compositeKeyType = (ComplexTypeMetadata) it.next(); message.append(compositeKeyType.getName()); if (it.hasNext()) { message.append(','); } } throw new FullTextQueryCompositeKeyException(message.toString()); } // Removes Joins and joined fields. List<Join> joins = select.getJoins(); if (!joins.isEmpty()) { Set<ComplexTypeMetadata> joinedTypes = new HashSet<ComplexTypeMetadata>(); for (Join join : joins) { joinedTypes.add(join.getRightField().getFieldMetadata().getContainingType()); } for (ComplexTypeMetadata joinedType : joinedTypes) { types.remove(joinedType); } List<TypedExpression> filteredFields = new LinkedList<TypedExpression>(); for (TypedExpression expression : select.getSelectedFields()) { if (expression instanceof Field) { FieldMetadata fieldMetadata = ((Field) expression).getFieldMetadata(); if (joinedTypes.contains(fieldMetadata.getContainingType())) { TypeMapping mapping = mappings.getMappingFromDatabase(fieldMetadata.getContainingType()); filteredFields.add( new Alias( new StringConstant(StringUtils.EMPTY), mapping.getUser(fieldMetadata).getName())); } else { filteredFields.add(expression); } } else { filteredFields.add(expression); } } selectedFields.clear(); selectedFields.addAll(filteredFields); } // Handle condition Condition condition = select.getCondition(); if (condition == null) { throw new IllegalArgumentException("Expected a condition in select clause but got 0."); } // Create Lucene query (concatenates all sub queries together). FullTextSession fullTextSession = Search.getFullTextSession(session); Query parsedQuery = select.getCondition().accept(new LuceneQueryGenerator(types)); // Create Hibernate Search query Set<Class> classes = new HashSet<Class>(); for (ComplexTypeMetadata type : types) { String className = ClassCreator.getClassName(type.getName()); try { ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); classes.add(contextClassLoader.loadClass(className)); } catch (ClassNotFoundException e) { throw new RuntimeException("Could not find class '" + className + "'.", e); } } FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery( parsedQuery, classes.toArray(new Class<?>[classes.size()])); // Very important to leave this null (would disable ability to search across different types) fullTextQuery.setCriteriaQuery(null); fullTextQuery.setSort(Sort.RELEVANCE); // Default sort (if no order by specified). query = EntityFinder.wrap( fullTextQuery, (HibernateStorage) storage, session); // ensures only MDM entity objects are returned. // Order by for (OrderBy current : select.getOrderBy()) { current.accept(this); } // Paging Paging paging = select.getPaging(); paging.accept(this); pageSize = paging.getLimit(); boolean hasPaging = pageSize < Integer.MAX_VALUE; if (!hasPaging) { return createResults(query.scroll(ScrollMode.FORWARD_ONLY)); } else { return createResults(query.list()); } }